2016-03-21 16 views
1

Ich benutze Struts-2.3.16 und ich muss Ausnahmen von Freemarker Vorlage global in unserer Anwendung zu unterdrücken. Dies bedeutet, dass ich anstelle des gelben Bildschirms mit dem Stacktrace von Freemarker an ein globales JSP weiterleiten muss, das eine generische Nachricht anzeigt, so dass die Anzeige von Stacktraces für den Benutzer verhindert wird. Für generische Ausnahmen in Struts haben wir ein global-result in struts.xml gemappt, aber es funktioniert nicht für Freemarker-Ausnahmen.Suppress Freemarker Vorlage Fehler

Bisher habe ich die Lösung von What are different ways to handle error in FreeMarker template? implementiert. Also habe ich einen CustomFreemarkerManager und einen CustomTemplateExceptionHandler erstellt.

Mein CustomFreemarkerManager sieht wie folgt aus:

@Override 
public void init(ServletContext servletContext) throws TemplateException { 
    super.config = super.createConfiguration(servletContext); 
    super.config.setTemplateExceptionHandler(new CustomTemplateExceptionHandler(servletContext)); 
    super.contentType = "text/html"; 
    super.wrapper = super.createObjectWrapper(servletContext); 
    if (LOG.isDebugEnabled()) { 
     LOG.debug("Using object wrapper of class " + super.wrapper.getClass().getName(), new String[0]); 
    } 

    super.config.setObjectWrapper(super.wrapper); 
    super.templatePath = servletContext.getInitParameter("TemplatePath"); 
    if (super.templatePath == null) { 
     super.templatePath = servletContext.getInitParameter("templatePath"); 
    } 

    super.configureTemplateLoader(super.createTemplateLoader(servletContext, super.templatePath)); 
    super.loadSettings(servletContext); 
} 

@Override 
protected Configuration createConfiguration(ServletContext servletContext) throws TemplateException { 
    Configuration configuration = new Configuration(); 
    configuration.setTemplateExceptionHandler(new CustomTemplateExceptionHandler(servletContext)); 
    if (super.mruMaxStrongSize > 0) { 
     configuration.setSetting("cache_storage", "strong:" + super.mruMaxStrongSize); 
    } 

    if (super.templateUpdateDelay != null) { 
     configuration.setSetting("template_update_delay", super.templateUpdateDelay); 
    } 

    if (super.encoding != null) { 
     configuration.setDefaultEncoding(super.encoding); 
    } 

    configuration.setLocalizedLookup(false); 
    configuration.setWhitespaceStripping(true); 
    return configuration; 
} 

Von hier aus ich die ServletContext meiner CustomTemplateExceptionHandler senden, so kann ich ein Request erstellen, um meine exception.jsp zu übermitteln. Das Problem ist, dass ich im Ausnahmebehandler die Anfrage und die Antwort nicht habe und ich kann nicht zu meinem JSP weiterleiten.

Die Klasse CustomTemplateExceptionHandler sieht wie folgt aus so weit:

private ServletContext servletContext; 

public CustomTemplateExceptionHandler(ServletContext servletContext) { 
    this.servletContext = servletContext; 
} 

public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException { 
    if (servletContext != null) { 
     RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/resources/exception.jsp"); 

     //HERE I have to forward to my jsp 
    } 
} 

Wer weiß, wie kann ich das tun? Ich möchte, dass der Stacktrace nur auf dem Server und in der Benutzeroberfläche protokolliert wird, um den Stacktrace durch eine generische Nachricht zu ersetzen.

+0

Ich habe jetzt den Code modifiziert, um die Ausnahme erneut auslösen. Es ist eine freemarker.core.InvalidReferenceException, die java.lang.Exception erweitert und von Struts2 abgefangen werden sollte. Bei allen anderen Ausnahmen, die in Struts ausgelöst werden, werden die Ausnahmen abgefangen und die globale Ausnahmebedingungsnachricht wird angezeigt. Scheint so, als ob in dieser Situation die Aktion zuerst ausgeführt wird und danach die Freemarker-Ausnahme ausgelöst wird. Vielleicht wird sie deswegen nicht von Struts abgefangen. –

+0

Ja, Sie haben Recht. Sie können versuchen, Redirect mit dem Ausnahmebehandler zu drucken. Siehe http://freemarker.624813.n4.nabble.com/URL-redirect-in-ftl-td625576.html. –

+0

Sehen Sie, wie 'HTML_DEBUG_HANDLER' prints - https://github.com/apache/incubator-freemarker/blob/2.3-gae/src/main/java/freemarker/template/TemplateExceptionHandler.java#L98. BTW gute Frage. :) –

Antwort

0

Ok, also war meine Lösung für dieses Problem, auf dem PrintWriter zu drucken, der in meinem CustomTemplateExceptionHandler eine ähnliche Antwort mit dem Standard HTML_DEBUG_HANDLER kommt, der von Freemarker angeboten wird. Schauen Sie sich den folgenden Link:

https://github.com/apache/incubator-freemarker/blob/2.3-gae/src/main/java/freemarker/template/TemplateExceptionHandler.java#L98

Hier können Sie sehen, wie HTML_DEBUG_HANDLER verwaltet wird. Ich ersetzte das Drucken des Stacktrace durch eine allgemeine Nachricht. Die Freemarker-Dokumentation empfiehlt Ihnen, RETHROW_HANDLER zu verwenden und die Ausnahme später in Ihrer Anwendung nach dem Aufruf von Template.process() abzufangen. Siehe hier:

http://freemarker.org/docs/app_faq.html#misc.faq.niceErrorPage

Aber weil Struts2 mit Freemarker arbeitet hinter den Kulissen, und die Freemarker Methoden ausgeführt werden, nachdem die Aktion ausgeführt wurde, kann ich es nicht herausfinden, wie und wo die Ausnahme zu fangen. Ich habe es geschafft, die HttpServlet Antwort und Anfrage im Verfahren handleTemplateException() (siehe die Frage) zu bekommen, aber ich konnte nicht mich auf meine exception.jsp, weil die Antwort bereits engagiert war und so war es mir eine Ausnahme geben.

Klasse CustomFreemarkerManager:

@Override 
public void init(ServletContext servletContext) throws TemplateException { 
    super.config = super.createConfiguration(servletContext); 
    super.config.setTemplateExceptionHandler(new CustomTemplateExceptionHandler()); 
    super.contentType = "text/html"; 
    super.wrapper = super.createObjectWrapper(servletContext); 
    if (LOG.isDebugEnabled()) { 
     LOG.debug("Using object wrapper of class " + super.wrapper.getClass().getName(), new String[0]); 
    } 

    super.config.setObjectWrapper(super.wrapper); 
    super.templatePath = servletContext.getInitParameter("TemplatePath"); 
    if (super.templatePath == null) { 
     super.templatePath = servletContext.getInitParameter("templatePath"); 
    } 

    super.configureTemplateLoader(super.createTemplateLoader(servletContext, super.templatePath)); 
    super.loadSettings(servletContext); 
} 

@Override 
protected Configuration createConfiguration(ServletContext servletContext) throws TemplateException { 
    Configuration configuration = new Configuration(); 
    configuration.setTemplateExceptionHandler(new CustomTemplateExceptionHandler()); 
    if (super.mruMaxStrongSize > 0) { 
     configuration.setSetting("cache_storage", "strong:" + super.mruMaxStrongSize); 
    } 

    if (super.templateUpdateDelay != null) { 
     configuration.setSetting("template_update_delay", super.templateUpdateDelay); 
    } 

    if (super.encoding != null) { 
     configuration.setDefaultEncoding(super.encoding); 
    } 

    configuration.setLocalizedLookup(false); 
    configuration.setWhitespaceStripping(true); 
    return configuration; 
} 

Klasse CustomTemplateExceptionHandler:

Der endgültige Code sieht wie folgt aus

public void handleTemplateException(TemplateException te, Environment env, Writer out) throws TemplateException { 

    boolean externalPw = out instanceof PrintWriter; 
    PrintWriter pw = externalPw ? (PrintWriter) out : new PrintWriter(out); 
    try { 
     pw.print("<!-- ERROR MESSAGE STARTS HERE -->" 
       + "<!-- ]]> -->" 
       + "</table></table></table>" 
       + "<div align='left' style='" 
       + "background-color:#FFFF7C; " 
       + "display:block; " 
       + "border-top:double; " 
       + "padding:10px; " 
       + "'>"); 
     pw.print("<b style='" 
       + "color: red; " 
       + "font-size:14px; " 
       + "font-style:normal; " 
       + "font-weight:bold; " 
       + "'>" 
       + "Oops! We have encountered a problem. Please try again!" 
       + "</b>"); 
     pw.println("</div></html>"); 
     pw.flush(); // To commit the HTTP response 
    } finally { 
     if (!externalPw) pw.close(); 
    } 

    throw te; 
} 

Wenn jemand eine bessere Antwort auf diese findet schreiben Sie Ihre Antwort!

0

Es sollte einfacher sein. Wenn Sie nicht über die gelben Debug-Vorlage Fehler wollen, müssen die TemplateExceptionHandler von HTML_DEBUG_HANDLER zu RETHROW_HANDLER wechseln (wie die Freemarker Nachricht auf der Oberseite vorschlagen: Freemarker Template Fehler DEBUG-Modus; Rethrow in der Produktion verwenden!)

Nun, ich ziehe es programmatisch tun (wie du), weil ich die TemplateExceptionHandler abhängig von der Umgebung wählen möchte (PRO, TEST, DEVEL), meine Lösung ist Umgebungsinformationen im Kontext zu setzen.

public class CustomFreemarkerManager extends FreemarkerManager {  


    public CustomFreemarkerManager(){ 
     super(); 
    } 

    @Override 
    public void init(ServletContext servletContext) throws TemplateException { 

     //important! 
     super.init(servletContext); 

     //other stuff maybe you want to tune... 

     //Getting environmentInfo object from the context, it's a personal solution 
     EnvironmentInfo environmentInfo = (EnvironmentInfo)servletContext.getAttribute(EnvironmentInfo.CONTEXT_NAME); 

     if (environment.isPro()) { 
      config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); 
     }else{ 
      config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);  
     } 

    } 
} 

und sagen Streben Ihrem Manager in struts.properties

struts.freemarker.manager.classname=com.jobisjob.northpole.web.core.CustomFreemarkerManager 

hoffe, das hilft zu verwenden.