异常消息
HTTP Status 500 - Session attribute 'employee' required - not found in session
type Exception report
message Session attribute 'employee' required - not found in session
description The server encountered an internal error that prevented it from fulfilling this request.
exception
org.springframework.web.HttpSessionRequiredException: Session attribute 'employee' required - not found in session org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.raiseSessionRequiredException(AnnotationMethodHandlerAdapter.java:791) org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveModelAttribute(HandlerMethodInvoker.java:766) org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:363) org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:170) org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:446) org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:434) org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945) org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876) org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:931) org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:833) javax.servlet.http.HttpServlet.service(HttpServlet.java:646) org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:807) javax.servlet.http.HttpServlet.service(HttpServlet.java:727) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.55 logs.
异常原因
当使用SessionAttributes注解缓存对象时,handler处理类的处理方法中存在对应的入参时,SpringMVC在implicitModel中找不到对应的对象时,SpringMVC会去判断是否使用SessionAttributes注解缓存了对应的类。如果缓存了,就会去查找对应的对象,如果找不到,就会抛出此异常。
源码:
private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { // Bind request parameter onto object... String name = attrName; if ("".equals(name)) { name = Conventions.getVariableNameForParameter(methodParam); } Class<?> paramType = methodParam.getParameterType(); Object bindObject; if (implicitModel.containsKey(name)) { bindObject = implicitModel.get(name); } else if (this.methodResolver.isSessionAttribute(name, paramType)) { bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name); if (bindObject == null) { raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session"); } } else { bindObject = BeanUtils.instantiateClass(paramType); } WebDataBinder binder = createBinder(webRequest, bindObject, name); initBinder(handler, name, binder, webRequest); return binder; }
解决方法
1. 方法入参的@ModelAttribute注解的value值不要与@SessionAttributes注解的value值一致。
@SessionAttributes(value={"employee"}) @Controller @RequestMapping("/emp") public class EmployeeController { @RequestMapping("/save") public ModelAndView save(@ModelAttribute(value="abc") Employee emp) throws Exception { System.out.println(emp); if(emp.getId() == null) { Date date = new Date(); SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd"); emp.setHiredate(format.format(date)); employeeDao.addEmployee(emp); } else { //更新数据,实际上丢失表单中没有的数据:no,hiredate employeeDao.updateEmployeeById(emp); } ModelAndView modelAndView = new ModelAndView(); List<Employee> emps = employeeDao.getAllEmployees(); modelAndView.addObject("emps", emps); modelAndView.setViewName(VIEW_NAME_LIST); return modelAndView; } }
2. 如果方法中不使用注解@ModelAttribute改变value值的默认值(类名首字母小写),而且@SessionAttributes注解的value值又习惯性使用类名首字母小写,则只能添加@ModelAttribute标注的方法,且在map中添加对应的对象。
@ModelAttribute public void getEmployee(@RequestParam(value="id",required=false) Integer id,Map<String,Object> map) throws Exception { System.out.println("从数据库中获取一个对象: " + id); System.out.println("-----------getEmployee-------------"); //从数据库中获取对象 if(id != null) { Employee emp = employeeDao.getById(id); map.put("employee", emp); } }