原创

## 关于SpringMVC Model数据不允许覆盖

报错

Cannot expose session attribute 'projectId' because of an existing model object of the same name

代码:

@RequestMapping("turnToDocs.do")

  public ModelAndView turnToDocs(String projectId){

    Map<String, String> map = new HashMap<String, String>();

    map.put("projectId", projectId);

    return new ModelAndView("ftl/file_manage/approve_docs",map);

  }

异常:

二月 24, 2017 11:53:54 上午 org.apache.catalina.core.StandardWrapperValve invoke

严重: Servlet.service() for servlet [spring] in context with path [/STObject] threw exception [Cannot expose session attribute 'projectId' because of an existing model object of the same name] with root cause

javax.servlet.ServletException: Cannot expose session attribute 'projectId' because of an existing model object of the same name

  at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:141)

  at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:266)

  at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1225)

  at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1012)

  at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)

  at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)

  at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:931)

  at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:822)

  at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)

  at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:807)

  at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)

  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)

  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)

  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

  at com.cxcm.crm.filter.AuthorityFilter.doFilter(AuthorityFilter.java:60)

  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)

  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)

  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)

  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108)

  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:522)

  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)

  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)

  at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)

  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)

  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)

  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1110)

  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)

  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:785)

  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1419)

  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:44)

  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)

  at java.lang.Thread.run(Thread.java:745)

异常原因:

查看spring源码发现,spring mvc会把session中的数据放到model中去,默认情况下不允许model中的数据被重写。而我的代码中,之前已经在session中设置了name为projectId的数据值,所以,不允许在new ModelAndView中继续放名为projectId的数据。

    **if** (**this**.exposeSessionAttributes) {

​      HttpSession session = request.getSession(**false**);

​      **if** (session != **null**) {

​       **for** (Enumeration<String> en = session.getAttributeNames(); en.hasMoreElements();) {

​         String attribute = 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");

​         }

​         Object attributeValue = session.getAttribute(attribute);

​         **if** (logger.isDebugEnabled()) {

​           logger.debug("Exposing session attribute '" + attribute +

​              "' with value [" + attributeValue + "] to model");

​         }

​         model.put(attribute, attributeValue);

​       }

​      }

​    }

其它测试:

  1. 既然session中的值都复制到model中了,那是否在ftl中可以获取呢?回答:对的

​ 测试方法:在controller中修改model中key为pId,session中key依然为projectId,在ftl用 input value=${projectId!}依然可以获取到值

  1. 在其它controller中采用projectId传值,那么这个projectId中的值到底是session中的,还是request中的呢?回答:request中的

​ 测试方法:修改request中projectId的值,从ftl中获取的数值和request中的数值一致

正文到此结束