Cannot expose request attribute 'userName' because of an existing model object of the same name

一、背景说明

     在预发布环境中进行功能验证时,点击“我的反馈”菜单时出现Cannot expose request attribute 'userName' because of an existing model object of the same name 错误,在测试环境正常显示。

二、认识异常

11-Jun-2019 16:43:57.429 SEVERE    org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [springServlet] in context with path [] threw exception [Cannot expose request attribute 'userName' because of an existing model object of the same name] with root cause
javax.servlet.ServletException: Cannot expose request attribute 'userName' 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:1257)
at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1037)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:980)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:521)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1096)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:674)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
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)

错误异常说明:request中存在同名的userName属性,获取失败
注:该错误会在Tomcat的server/logs/localhost.log日志中展示

三、排查问题

1、在LoginInteceptor中通过 request.setAttribute 方式添加了userName属性

public class LoginInteceptor implements HandlerInterceptor{
    @Override
    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
	    throws Exception{
        /**......**/
	request.setAttribute("userName",'test');
	/**......**/
    }
}

2、同时在Controller中通过modelAndView.addObject 方式添加了userName属性

@RequestMapping("/myCall")
public ModelAndView myCall(ModelAndView modelAndView){
	modelAndView.setViewName("my/call");
	modelAndView.addObject("userName","test");
	return modelAndView ;
}

3、同时在Spring MVC的viewResolver解析器中配置了exposeRequestAttributes和exposeSessionAttributes值为ture

<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityLayoutViewResolver">
	/**......**/
	<property name="exposeRequestAttributes" value="true"/>
	<property name="exposeSessionAttributes" value="true"/>
	/**......**/
</bean>

exposeRequestAttributes 和 exposeSessionAttributes 设置为true的话会将request和session中的键值和值合并到modelAndView的Map参数中。

通过以上三项最终导致问题的产生

四、解决问题

方案一:修改Controller中参数名称userName,改为modelAndView.addObject("myUserName","test"),简单粗暴

方案二:在Spring MVC的viewResolver解析器配置中添加allowRequestOverride=true和allowSessionOverride=true配置,允许request和session设置的键值被覆盖,具体配置如下所示:

<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityLayoutViewResolver">
	/**......**/
	<property name="exposeRequestAttributes" value="true"/>
	<property name="allowRequestOverride" value="true"/>
	<property name="exposeSessionAttributes" value="true"/>
	<property name="allowSessionOverride" value="true"/>
	/**......**/
</bean>

注:两种方案都可以解决Cannot expose request attribute 'userName' because of an existing model object of the same name 问题

猜你喜欢

转载自blog.csdn.net/TimerBin/article/details/93497744
今日推荐