2016-03-21 100 views
1

我正在使用struts-2.3.16,我必须在应用程序中全局禁止来自Freemarker模板的异常。这意味着,我们必须转发到全局jsp来显示一条通用消息,而不是使用来自Freemarker的堆栈跟踪的黄色屏幕,以防止向用户显示堆栈跟踪。对于struts中的泛型异常,我们将全局结果映射到struts.xml中,但它不适用于Freemarker异常。抑制Freemarker模板错误

到目前为止,我已经实施了从What are different ways to handle error in FreeMarker template?的解决方案。所以我创建了一个CustomFreemarkerManager和一个CustomTemplateExceptionHandler。

我CustomFreemarkerManager看起来是这样的:

@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; 
} 

在这里,我ServletContext的发到我CustomTemplateExceptionHandler这样我就可以创建一个RequestDispatcher转发给我的exception.jsp。问题是在异常处理程序中,我没有请求和响应,我无法转发到我的jsp。

类CustomTemplateExceptionHandler看起来像这样至今:

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 
    } 
} 

任何人都知道我该怎么做呢?我希望堆栈跟踪仅在服务器上记录,并且在UI中用普通消息替换堆栈跟踪。

+0

我现在修改了重新抛出异常的代码。它是一个freemarker.core.InvalidReferenceException,它扩展了java.lang.Exception并且应该被Struts2捕获。对于在Struts中引发的所有其他异常,将捕获异常并显示全局异常消息。似乎在这种情况下,首先执行该操作,然后引发Freemarker异常,所以也许这就是为什么它不被Struts捕获的原因。 –

+0

是的,你是对的。您可以尝试使用异常处理程序打印重定向。请参阅http://freemarker.624813.n4.nabble.com/URL-redirect-in-ftl-td625576.html。 –

+0

查看'HTML_DEBUG_HANDLER'如何打印 - https://github.com/apache/incubator-freemarker/blob/2.3-gae/src/main/java/freemarker/template/TemplateExceptionHandler.java#L98。顺便说一句好的问题。 :) –

回答

0

好的,所以我对这个问题的解决方案是打印在我的CustomTemplateExceptionHandler中的PrintWriter上,其响应类似于Freemarker提供的标准HTML_DEBUG_HANDLER。看看这个链接:

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

在这里你可以看到HTML_DEBUG_HANDLER进行管理。我用普通信息替换了打印堆栈跟踪。 Freemarker文档建议您使用RETHROW_HANDLER,并在Template.process()调用后在应用程序中稍后捕获异常。在这里看到:

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

但由于Struts2的工作与后台的Freemarker,并在执行动作之后执行Freemarker的方法,我无法弄清楚如何以及在哪里捕获异常。我已经设法在方法handleTemplateException()中看到HttpServlet响应和请求(请参阅问题),但我无法转发到我的exception.jsp,因为响应已经提交,所以它给了我一个例外。

最终的代码如下所示:

类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; 
} 

类CustomTemplateExceptionHandler:

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; 
} 

如果有人发现这个更好的反应请把你的答案!

0

它应该更容易。如果你不想要黄色的调试模板错误,你必须将TemplateExceptionHandlerHTML_DEBUG_HANDLER切换到RETHROW_HANDLER(因为顶部的freemarker消息提示:FreeMarker模板错误调试模式;在生产中使用RETHROW!

现在,我更喜欢这样做编程方式(像你一样),因为我想选择TemplateExceptionHandler根据环境(PROTESTDEVEL),我的解决办法是把环境信息的环境。使用

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);  
     } 

    } 
} 

,并告诉支柱向你的经理在struts.properties

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

希望这有助于。