0

私の Spring MVC アプリケーションの機能の 1 つは、後で処理する必要がある大きなファイル (約 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 分です。アップロードにそれ以上かかると、コントローラーに届きません。このセッションの損失を回避する方法はありますか?

4

1 に答える 1

1

セッションタイムアウトの問題であるに違いないことはすでにわかっています。アップロードが開始された後に特定のセッションにヒットする新しいリクエストがない場合、「アクティビティがない」と見なされますが、これは正しくありません。

これに対処するには、いくつかの方法があります。

web.xml

でタイムアウトを増やしweb.xmlます。Tomcat のデフォルトは 30 です (つまり、で指定されていない場合web.xml)。

<session-config>
  <session-timeout>45</session-timeout>
</session-config>

ただし、経験則として、タイムアウトは「できるだけ低く」する必要があるため、これは望ましくない場合があります。通常は 5' を使用します。

セッションの変更

一般的なセッション タイムアウトを 5 に設定できますが、アップロードが開始されたら次のように増やしますHttpSession#setMaxInactiveInterval

サーブレット コンテナがこのセッションを無効にするまでのクライアント リクエスト間の時間を秒単位で指定します。負の時間は、セッションがタイムアウトしないことを示します。

ただし、コントローラーが呼び出されていない場合は、Spring の前にこれを行う必要があります。最有力候補はServletFilter.

AJAX

アップロードが送信された直後に、クライアントからハートビート リクエストを開始します。次に、ハートビートをループで繰り返します。セッション タイムアウトが 5 秒の場合、ハートビート間隔を 4 秒に設定できます。

于 2013-05-30T14:23:14.453 に答える