1. 程式人生 > >struts2檔案上傳大小預設限制問題

struts2檔案上傳大小預設限制問題

struts2中檔案上傳的二個限制,一個是struts.multipart.maxSize,如果不設定,struts2 的核心包下的default.properties檔案裡有預設的大小設定struts.multipart.maxSize=2097152,即2M. 這是struts2檔案上傳的第一道關.

第二道關是inteceptor中的maximumSize. 當真實的檔案大小能通過第一道關時.針對不同的action中配置的inteceptor,maximumSize才能發揮相應的攔截作用.

比如struts.multipart.maxSize=50M. actionA中inteceptorA的maximumSize=30M. actionB中inteceptorB的maximumSize=10M.

struts.multipart.maxSize=50M對於inteceptorA,B都會起到第一關的作用.而inteceptorA和inteceptorB可以在通過第一關之後,根據自己的業務定製各自針對攔截器起作用的maximumSize

如果真實的檔案>50M. 丟擲會丟擲the request was rejected because its size (XXXX) exceeds the configured maximum (XXXX)異常,他是不能被國際化的,因為這個資訊是commons-fileupload元件丟擲的,是不支援國際化這資訊.

struts2.2 org.apache.commons.fileupload.FileUploadBase.java中

/** 
  * Creates a new instance. 
  * @param ctx The request context. 
  * @throws FileUploadException An error occurred while 
  *   parsing the request. 
  * @throws IOException An I/O error occurred. 
  */  
 FileItemIteratorImpl(RequestContext ctx)  
         throws FileUploadException, IOException {  
     if (ctx == null) {  
         throw new NullPointerException("ctx parameter");  
     }  
   
     String contentType = ctx.getContentType();  
     if ((null == contentType)  
             || (!contentType.toLowerCase().startsWith(MULTIPART))) {  
         throw new InvalidContentTypeException(  
                 "the request doesn't contain a "  
                 + MULTIPART_FORM_DATA  
                 + " or "  
                 + MULTIPART_MIXED  
                 + " stream, content type header is "  
                 + contentType);  
     }  
   
     InputStream input = ctx.getInputStream();  
   
     if (sizeMax >= 0) {  
         int requestSize = ctx.getContentLength();  
         if (requestSize == -1) {  
             input = new LimitedInputStream(input, sizeMax) {  
                 protected void raiseError(long pSizeMax, long pCount)  
                         throws IOException {  
                     FileUploadException ex =  
                         new SizeLimitExceededException(  
                             "the request was rejected because"  
                             + " its size (" + pCount  
                             + ") exceeds the configured maximum"  
                             + " (" + pSizeMax + ")",  
                             pCount, pSizeMax);  
                     throw new FileUploadIOException(ex);  
                 }  
             };  
         } else {  
 ///問題就在這裡////////////////////////////////////  
             if (sizeMax >= 0 && requestSize > sizeMax) {  
                 throw new SizeLimitExceededException(  
                         "the request was rejected because its size ("  
                         + requestSize  
                         + ") exceeds the configured maximum ("  
                         + sizeMax + ")",  
                         requestSize, sizeMax);  
             }  
         }  
     }  
   
     String charEncoding = headerEncoding;  
     if (charEncoding == null) {  
         charEncoding = ctx.getCharacterEncoding();  
     }  
   
     boundary = getBoundary(contentType);  
     if (boundary == null) {  
         throw new FileUploadException(  
                 "the request was rejected because "  
                 + "no multipart boundary was found");  
     }  
   
     notifier = new MultipartStream.ProgressNotifier(listener,  
             ctx.getContentLength());  
     multi = new MultipartStream(input, boundary, notifier);  
     multi.setHeaderEncoding(charEncoding);  
   
     skipPreamble = true;  
     findNextItem();

如果InteceptorA上傳的是40M的真實檔案.那麼此時攔截器InteceptorA會訪問國際化資訊:struts.messages.error.file.too.larges對應的值.

當且僅當上傳檔案<=30M的時候,InteceptorA才會成功上傳.

下面是解決struts.multipart.maxSize提示資訊不友好的問題.

當超過50M時.commons-fileupload丟擲執行時異常,struts2會把這個異常看到是action級別的異常.所以會將異常資訊

the request was rejected because its size (XXXX) exceeds the configured maximum (XXXX)寫到actionError裡面.我們需要做的就是在action裡覆蓋addActionError方法

@Override
    public void addActionError(String anErrorMessage) {
        //改從國際化裡取值
        if (anErrorMessage
                .startsWith("the request was rejected because its size")) {
            super.addActionError(getText("struts.multipart.maxSize.limit"));
        } else {
            super.addActionError(anErrorMessage);
        }
    }

相應的配置檔案

struts.multipart.maxSize.limit=系統上傳的檔案最大為50M
struts.messages.error.file.too.larges=新廣告批量上傳的檔案最大為5M
struts.messages.error.content.type.not.allowed=上傳的檔案格式目前僅支援xls格式
struts.messages.error.uploading=上傳檔案失敗
struts.messages.invalid.token=您已經提交了表單,請不要重複提交。
fileupload.filenums.exceed=已經有超過5個檔案在執行,請稍候再試
filedownload.rows.exceed=由於您選擇的廣告組內廣告數量太多,請分組下載
accountNotExist=客戶不存在
invalidTask=無效的任務

注意,由於inteceptor中途返回,原來頁面上輸入的其他文字內容也都不見了,也就是說params注入失敗。

這個是沒辦法的,因為這個異常是在檔案上傳之前捕獲的,檔案未上傳,同時params也為注入,所以這時最好重定向到一個jsp檔案,提示上傳失敗,然後重寫填寫相應資訊。

解決辦法:最好跳到一個專門顯示錯誤的頁.而不要返回操作頁.

-------------------------------------------------------------------------------------------

注意,攔截器所謂的同名配置覆蓋,是重複執行的,比如defaultStack中是包含fileUpload,token的. 如果將<interceptor-ref name="defaultStack" />放到顯示定義的攔截器之後,會覆蓋顯示定義的攔截器.

下面是正確的攔截器順序:

<action name="BatchMIADOperation!*" method="{1}"
            class="com.*****.***.action.multiidea.batchad.BatchMIADOperationAction">
            <interceptor-ref name="defaultStack" />
            <interceptor-ref name="fileUpload">
                <param name="maximumSize">5242880</param>
                <!--
                    <param name="allowedTypes">
                    application/vnd.ms-excel
                    </param>
                -->
            </interceptor-ref>
            <interceptor-ref name="token">
                <param name="excludeMethods">
                    init,search,updateBatchCpcMatch,batchExportMIAD,downloadWhenError
                </param>
            </interceptor-ref>
            <result name="input">
                /WEB-INF/jsp/multiidea/batchad/BatchMIAD.jsp
            </result>
            <result name="success">
                /WEB-INF/jsp/multiidea/batchad/BatchMIAD.jsp
            </result>
            <result name="invalid.token">
                /WEB-INF/jsp/multiidea/batchad/BatchMIAD.jsp
            </result>
        </action>

原文連結:http://www.cnblogs.com/highriver/archive/2011/06/01/2065557.html