javascript
Spring MVC上传文件原理和resolveLazily说明
問(wèn)題:使用Spring MVC上傳大文件,發(fā)現(xiàn)從頁(yè)面提交,到進(jìn)入后臺(tái)controller,時(shí)間很長(zhǎng)。懷疑是文件上傳完成后,才進(jìn)入。由于在HTTP首部自定義了“Token”字段用于權(quán)限校驗(yàn),Token的有效時(shí)間很短,因此上傳大文件時(shí),就會(huì)驗(yàn)證Token失敗。
示例代碼:
前端:
<form action="upload" enctype="multipart/form-data" method="post"><table><tr><td>文件描述:</td><td><input type="text" name="description"></td></tr><tr><td>請(qǐng)選擇文件:</td><td><input type="file" name="file"></td></tr><tr><td><input type="submit" value="上傳"></td></tr></table> </form>?
controller:
@RequestMapping(value="/upload",method=RequestMethod.POST) public String upload(HttpServletRequest request, @RequestParam("description") String description, @RequestParam("file") MultipartFile file) throws Exception {System.out.println("enter controller."); // 文件上傳完才打印}springmvc-config.xml配置:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize"> <value>524288000</value> </property> <property name="defaultEncoding"><value>UTF-8</value></property></bean>Spring MVC上傳文件使用了Commons FileUpload類(lèi)庫(kù),即CommonsMultipartResolver使用commons Fileupload來(lái)處理 multipart請(qǐng)求,將Commons FileUpload的對(duì)象轉(zhuǎn)換成了Spring MVC的對(duì)象。
那如果直接使用Commons FileUpload來(lái)進(jìn)行文件上傳下載呢?
示例代碼:
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {System.out.println("enter servlet"); // 頁(yè)面提交后,立馬打印// 省略獲取上傳文件的邏輯
// ...
}
發(fā)現(xiàn)從頁(yè)面提交,很快就進(jìn)入了servlet。
既然Spring也是使用了Commons FileUpload類(lèi)庫(kù),但為什么差別這么大呢?Spring在轉(zhuǎn)換過(guò)程中做了什么其他操作呢?
查看源碼,或者直接看([Java] SpringMVC工作原理之四:MultipartResolver)
發(fā)現(xiàn)有個(gè)resolveLazily參數(shù)是判斷是否要延遲解析文件(通過(guò)XML可以設(shè)置)。當(dāng)?resolveLazily為false(默認(rèn))時(shí),會(huì)立即調(diào)用 parseRequest() 方法對(duì)請(qǐng)求數(shù)據(jù)進(jìn)行解析,然后將解析結(jié)果封裝到 DefaultMultipartHttpServletRequest中;而當(dāng)resolveLazily為 true時(shí),會(huì)在DefaultMultipartHttpServletRequest的initializeMultipart()方法調(diào)用parseRequest()方法對(duì)請(qǐng)求數(shù)據(jù)進(jìn)行解析,而initializeMultipart()方法又是被getMultipartFiles()方法調(diào)用,即當(dāng)需要獲取文件信息時(shí)才會(huì)去解析請(qǐng)求數(shù)據(jù),這種方式用了懶加載的思想。
再次修改代碼:
1、在springmvc-config.xml增加一個(gè)配置resolveLazily,設(shè)置true(如何配置見(jiàn)文末);
2、將controller方法中將@RequestParam("file") MultipartFile file注釋
?
再次測(cè)試,發(fā)現(xiàn)還是不對(duì)。。增加打印日志后發(fā)現(xiàn):
@RequestMapping(value="/upload",method=RequestMethod.POST) public String upload(HttpServletRequest request, @RequestParam("description") String description /*@RequestParam("file") MultipartFile file*/) throws Exception {System.out.println("enter controller."); // 還是文件上傳完后,才打印System.out.println(request.getHeader("Accept"));System.out.println(request.getParam("description"));// 省略獲取上傳文件的邏輯}
再注釋@RequestParam("description") String description
@RequestMapping(value="/upload",method=RequestMethod.POST) public String upload(HttpServletRequest request/*@RequestParam("description") String description, *//*@RequestParam("file") MultipartFile file*/) throws Exception {System.out.println("enter controller."); // 頁(yè)面提交后,立刻打印System.out.println(request.getHeader("Accept")); // 幾乎也是立刻打印System.out.println(request.getParam("description")); // 文件上傳完,才打印// 省略獲取上傳文件的邏輯
}
這次,第1,2條日志很快打印,第3條日志仍是文件上傳完后才打印。簡(jiǎn)單分析下,應(yīng)該是后臺(tái)一直在接收數(shù)據(jù),HTTP首部很快就能獲取到并解析出來(lái)(首部和正文之間有一個(gè)空行),但請(qǐng)求正文部分必須在請(qǐng)求數(shù)據(jù)完全接收后才能解析,因此線程一直阻塞直到數(shù)據(jù)接收完成才打印第3條日志。因此解決方案是,把controller函數(shù)中的@RequestParam("description") String description也注釋掉,這樣頁(yè)面提交后,會(huì)立即進(jìn)入controller中。
?
總結(jié)下最終的解決方案:
1、springmvc-config.xml增加一項(xiàng)配置:
<property name="resolveLazily "><value>true</value> </property>2、在controller的方法參數(shù)中,不能附加請(qǐng)求參數(shù),應(yīng)在函數(shù)中自己解析參數(shù)。
?
轉(zhuǎn)載于:https://www.cnblogs.com/cyh706510441/p/8855320.html
與50位技術(shù)專(zhuān)家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的Spring MVC上传文件原理和resolveLazily说明的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【C#】list 去重(转载)
- 下一篇: SpringMVC中@RequestPa