Springファイルアップロードコンポーネント

15935 ワード

アップロードにFileUploadExceptionが現れます.Stream closed
  • 簡単な説明
  • シーン
  • 原因分析
  • 解決方法
  • 拡張
  • 簡単に述べる
    プロジェクトでは、CommonsMultiiprtResoloverをファイルとして使用して、ファイル上の解像度をアップロードします.ブロックの中で権限検査といくつかのパラメータチェックを行います.フロントエンドがアップロードインターフェースを呼び出す過程で、フロントエンドパラメータが正しくないため、スクリーンは直接エラー情報を返しましたが、意外にもFileUploadException:Stream closedが異常です.
    シーン
    以下はフロントエンドにエラーメッセージを直接書き込むコードです.contentはエラーメッセージのjson列です.通常の場合、このようなIOフロー操作の書き方は全く問題ありません.
    // response          
    public static void returnMessage(HttpServletResponse response, String content) {
    		response.setCharacterEncoding("UTF-8");
    		response.setContentType("application/json");
    		PrintWriter pWriter = null;
    		try {
    			pWriter = response.getWriter();
    			pWriter.write(content);
    		} catch (IOException e) {
    			logger.error("returnMessage", e);
    		} finally {
    			if (pWriter != null) {
    				pWriter.flush();
    				pWriter.close();
    			}
    		}
    	}
    
    原因分析
    異常情報を分析すると、Commons MultiiprtResolaverのcleanultipad方法で異常発生し、コードの断片は以下の通りである.
    public void cleanupMultipart(MultipartHttpServletRequest request) {
    		try {
    			cleanupFileItems(request.getMultiFileMap());
    		}
    		catch (Throwable ex) {
    			logger.warn("Failed to perform multipart cleanup for servlet request", ex);
    		}
    	}
    
    request.get MultiFileMap()を呼び出したときに実行されるのはAbstractMultiiPad HttpServletRequest類のget Multifiles()です.この方法は怠惰なロード方法で、MultiiprtFile Mapが必要な時だけ呼び出します.要求はブロックでブロックされます.つまり、掃除時に初めて使用します.ここで初期化します.続いてパーrseRequest()解析要求を呼び出し、入力ストリームreadBoddData()を使用すると、ストリームが閉じられていることが分かり、異常が発生しました.
    解決方法
    大雑把に探究したところ、レスリングの出力ストリームはオフにされているが、対応するRequestの入力ストリームは同時にオフにされていることがわかった.debugとTomcatのAPIから、RequestオブジェクトはTomcatによってFacadeモードで包装され、Requestオブジェクトには対応するResponse参照が含まれていることがわかる.RequestストリームはReponseフローをシャットダウンすることが証明されました.原因はTomcatの原理を結び付けて深く探究する必要があります.以下は改造後のコードです.
    public void returnMessage(HttpServletRequest request, HttpServletResponse response, String content) {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json");
            PrintWriter pWriter = null;
            try {
                pWriter = response.getWriter();
                pWriter.write(content);
            } catch (IOException e) {
                log.error("returnMessage", e);
            } finally {
                if (!ServletFileUpload.isMultipartContent(request)) {
                    if (pWriter != null) {
                        pWriter.flush();
                        pWriter.close();
                    }
                }
            }
        }
    
    Springフレームでは手動でストリームを閉じないでください.システムに任せて自分で閉じます.
    拡張
    1、Spring MVCのアップロード解像器は2種類に分けられています.それぞれCommonsMultiiPad ResolaverとStanddardServletMultilertResolaverです.2、Standard ServletMultiResolaverはservlet 3.0に基づいて、MultiiprtResolaverの標準的な実現であり、Spring Bootのデフォルトのアップロードコンポーネントでもあります.Webプロジェクトには、web.xmlに影響が必要なservletにmultiipad-configを配置する必要がある.SpringBoot項目については、直接にappicationプロファイルに属性を配置したり、MultiiprtConfigElementをカスタマイズしたりすることができます.カスタムservletに対して、servlet classにMultiiprtConfig注釈を加えることもできます.3、CommonsMultiiprtResolaverはウェブプロジェクトでよく使われるアップロードコンポーネントであり、容器の中で定義する必要があります.
    Spring Bootを例にして、構成を説明します.StandardServletMultipartResolver ( ): 1、 application.yml application.properties ,
    spring.http.multipart.maxFileSize=10MB
    spring.http.multipart.maxRequestSize=50MB
    
    2、 MultipartConfigElement
        @Bean
        public MultipartConfigElement getMultipartElement() {
            //  MultipartConfigElement   
            MultipartConfigFactory factory = new MultipartConfigFactory();
            //        ,        ,        
            factory.setMaxFileSize("50MB");
            //       
            factory.setMaxRequestSize("100MB");
            MultipartConfigElement element = factory.createMultipartConfig();
            return element;
        }
    
    CommonsMultipartResolver
         @Bean
         public CommonsMultipartResolver getMultipartResolver() {
            CommonsMultipartResolver resolver = new CommonsMultipartResolver();
            resolver.setMaxUploadSize(439426520l);
            resolver.setResolveLazily(true);//   ,                  
            resolver.setDefaultEncoding("UTF-8");
            return resolver;
        }
    
    そのXML設定方式は以下の通りです.
         <bean id="multipartResolver"	class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    		<property name="resolveLazily" value="true" />
    		<!--             10MB -->
    		<property name="maxUploadSize" value="10485760" />
    		<property name="defaultEncoding" value="UTF-8" />
    	 </bean>