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<String, Object> 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视图的配置:

<!-- 配置freeMarker视图解析器 -->
<bean id="viewResolverFtl" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
    <property name="contentType" value="text/html; charset=UTF-8"/>
    <property name="exposeRequestAttributes" value="true"/>
    <property name="exposeSessionAttributes" value="true"/>
    <property name="exposeSpringMacroHelpers" value="true"/>
    <property name="allowSessionOverride" value="true" />
    <property name="allowRequestOverride" value="true" />
    <property name="cache" value="true"/>
    <property name="suffix" value=".ftl"/>
    <property name="order" value="0"/>
</bean>

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值