我的 Spring MVC 应用程序的功能之一是上传大文件(大约 500MB),这些文件应该稍后处理。
控制器是:
@RequestMapping("/folderManagement/")
@Controller("FolderFormController")
@SessionAttributes({ "tabTitle", "selectedFolder" })
public class FolderFormController {
@RequestMapping(method = RequestMethod.GET, value = FOLDER_FORM)
protected ModelAndView showFolderManager(@RequestParam(value = "selectedFolderId", required = false) Long selectedFolderId,
@RequestParam(value = "selectedDocId", required = false) Long selectedDocId, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Generates the page attributes
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName(FOLDER_FORM_VIEW);
return modelAndView;
}
@RequestMapping(value = UPLOAD_FILES, method = RequestMethod.POST)
public ModelAndView postUploadFile(HttpServletRequest request, @ModelAttribute("uploadItem") UploadItem upitem, @ModelAttribute("selectedFolder") FolderForm root, BindingResult result,
SessionStatus status, ModelAndView modelAndView) {
// Process upitem
Log.debug("INIT");
}
}
UploadItem 是一个内部有一个 CommonsMultipartFile (org.springframework.web.multipart.commons) 的对象。
它通常工作正常。无论文件大小(甚至 800MB),也不管处理时间。但是,有时用户会收到以下异常:
org.springframework.web.HttpSessionRequiredException: Expected session attribute 'selectedFolder'
at org.springframework.web.method.annotation.ModelFactory.initModel(ModelFactory.java:103)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:614)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptorFilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:183)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.ajp.AjpAprProcessor.process(AjpAprProcessor.java:448)
at org.apache.coyote.ajp.AjpAprProtocol$AjpConnectionHandler.process(AjpAprProtocol.java:403)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1703)
at java.lang.Thread.run(Thread.java:662)
此方法捕获此异常:
@ExceptionHandler({ Exception.class})
public ModelAndView handleExceptionArray(Exception ex) {
Log.error("Recogida excepcion " + ex.getClass().getSimpleName(), ex);
String errorMessage = "Internal error";
ModelAndView modelAndView = new ModelAndView();
// modelAndView.setViewName("error/error");
modelAndView.addObject("name", "");
modelAndView.addObject("exception", errorMessage);
modelAndView.setViewName("redirect:" + FolderFormController.getRedirectUrl());
saveError(modelAndView, errorMessage);
return modelAndView;
}
此外,日志“INIT”没有打印出来,所以它没有进入控制器方法。
发生了什么?而且,更重要的是,我怎样才能避免这种情况?有任何想法吗?
更新:原因
好吧,似乎原因是用户会话到期。Tomcat 的过期时间为 30 分钟。如果上传需要的时间不止这些,那么它就不会到达我的控制器。有什么办法可以避免会话丢失?