Spring + Freemarker 遇到的异常

在使用springmvc+freemarker,遇到了以下异常(如:资源找不到重定向到404的请求时):

javax.servlet.ServletException: Cannot expose request attribute 'tmp_save' because of an existing model object of the same name
at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:123)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1244)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1027)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:971)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)

看一下源码,可以发现如果exposeRequestAttributes设为true,model中已经存在该key,且allowRequestOverride为false是,就会报该错。session一样: 

 

protected final void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception {
    String attribute;
    Object attributeValue;
    if(this.exposeRequestAttributes) {
        for(Enumeration en = request.getAttributeNames(); en.hasMoreElements(); model.put(attribute, attributeValue)) {
            attribute = (String)en.nextElement();
            if(model.containsKey(attribute) && !this.allowRequestOverride) {
                throw new ServletException("Cannot expose request attribute '" + attribute + "' because of an existing model object of the same name");
            }
  
            attributeValue = request.getAttribute(attribute);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Exposing request attribute '" + attribute + "' with value [" + attributeValue + "] to model");
            }
        }
    }
  
    if(this.exposeSessionAttributes) {
        HttpSession session = request.getSession(false);
        Object attributeValue;
        String attribute;
        if(session != null) {
            for(Enumeration en = session.getAttributeNames(); en.hasMoreElements(); model.put(attribute, attributeValue)) {
                attribute = (String)en.nextElement();
                if(model.containsKey(attribute) && !this.allowSessionOverride) {
                    throw new ServletException("Cannot expose session attribute '" + attribute + "' because of an existing model object of the same name");
                }
  
                attributeValue = session.getAttribute(attribute);
                if(this.logger.isDebugEnabled()) {
                    this.logger.debug("Exposing session attribute '" + attribute + "' with value [" + attributeValue + "] to model");
                }
            }
        }
    }
  
    if(this.exposeSpringMacroHelpers) {
        if(model.containsKey("springMacroRequestContext")) {
            throw new ServletException("Cannot expose bind macro helper 'springMacroRequestContext' because of an existing model object of the same name");
        }
  
        model.put("springMacroRequestContext", new RequestContext(request, response, this.getServletContext(), model));
    }
  
    this.applyContentType(response);
    this.renderMergedTemplateModel(model, request, response);
}
  1. 控制器绑定链接的函数,里面的参数列表如果要用到BindResult(用于验证器验证后获取验证结果),这个变量必须紧跟在被验证对象(command)之后,否则在进行验证时会抛出异常。
  2. 如果在视图解析器(我们用的是velocity)中设置了属性exposeSessionAttributes为true之后,所有的session中的变量都会在传给视图(velocity模板)时被合并到model中。这时如果在控制器中使用了@sessionAttributes注解(会把session中指定的变量存到model中),在最后合并model的时候会报Cannot expose session attribute 'xxx' because of an existing model object of the same name异常。查看了AbstractTemplateView.java文件后,发现spring在合并的时候还判断了allowSessionOverride这个属性,如果为false,就会抛出上面提到的异常。所以这种情况下,还要在配置文件的viewResolver中添加allowSessionOverride属性,value为true,这样即使遇到重复的值,也会直接使用Map中的put方法将旧值覆盖。

解决方法可以把allowRequestOverride 设为 true,下面是freemarker视图的配置:



    
    
    
    
    
    
    
    
    
    

 

你可能感兴趣的:(Freemaker)