亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

深入springMVC------文件上傳源碼解析(上篇)

2019-11-06 06:06:15
字體:
來源:轉載
供稿:網友

最近在項目中,使用sPRingmvc 進行上傳文件時,出現了一個問題:

org.springframework.web.multipart.MultipartException: The current request is not a multipart request

....

以上堆棧信息省略。

乍看一下,沒啥值得討論的地方,就是說當前這個請求不是一個multipart request,也就是說不是上傳文件的請求。但是,這結果還是令我稍感意外,為什么呢?因為,我本意是將文件這個參數作為非必要參數,類似下面這樣:

@RequestMapping(value = "/upload", method = RequestMethod.POST)public ResultView upload(@RequestParam(value = "file", required = false) MultipartFile file)

spring拋出上面的異常,就違背了我的本意,我明明設置了 “required = false”, 為什么還是不行? 于是,帶著疑問去看了一下spring的源碼,下面就跟大家分享一下spring mvc對于文件上傳的處理。

 

--------------------------------------------------我是華麗的分割線-------------------------------------------------------

 

在spring mvc通過DispatcherServlet處理請求時,會調用到 doDispatch這個方法,當然這也是spring mvc處理請求最核心的方法:

復制代碼
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {        HttpServletRequest processedRequest = request;        HandlerExecutionChain mappedHandler = null;        boolean multipartRequestParsed = false;                WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);        try {            ModelAndView mv = null;            Exception dispatchException = null;            try {                processedRequest = checkMultipart(request);                multipartRequestParsed = (processedRequest != request);復制代碼

上面就是給出的有關上傳文件的代碼片段,看以看到,當spring處理請求的時候,首先第一步就去檢查當前請求是否為上傳文件的請求,那么,它是怎么檢查的呢,接著往下看:

復制代碼
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {        if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {            if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {                logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +                        "this typically results from an additional MultipartFilter in web.xml");            }            else if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) instanceof MultipartException) {                logger.debug("Multipart resolution failed for current request before - " +                        "skipping re-resolution for undisturbed error rendering");            }            else {                return this.multipartResolver.resolveMultipart(request);            }        }        // If not returned before: return original request.        return request;    }復制代碼

通過以上方法,我們可以看到如下邏輯:

(1)當 MultipartResolver 不為null的時候, 就通過它去檢查當前請求是否為文件上傳請求(通過CommonsMultipartResolver的isMultipart方法)。

(2)如果當前請求不是MultipartHttpServletReques并且不包含MultipartException異常,那么,就通過CommonsMultipartResolver去處理當前請求(通過調用resolveMultipart方法將當前請求包裝為MultipartHttpServletRequest),返回包裝后的請求。

(3)返回當前請求(未經處理的請求)。

接下來我們重點看看,spring是如何判斷是否為文件上傳的請求的:

CommonsMultipartResolver:

@Override    public boolean isMultipart(HttpServletRequest request) {        return (request != null && ServletFileUpload.isMultipartContent(request));    }

這兒直接使用了Apache 的commons-fileupload中的ServletFileUpload, 那我們就來看看它究竟何許人也:

ServletFileUpload:

復制代碼
public static final boolean isMultipartContent(            HttpServletRequest request) {        if (!POST_METHOD.equalsIgnoreCase(request.getMethod())) {            return false;        }        return FileUploadBase.isMultipartContent(new ServletRequestContext(request));    }復制代碼

以上代碼說明:

(1)當前請求必須是post方法。

(2)如果是post方法,就通過 FileUploadBase 去進一步檢測。

FileUploadBase:

復制代碼
public static final boolean isMultipartContent(RequestContext ctx) {        String contentType = ctx.getContentType();        if (contentType == null) {            return false;        }        if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) {            return true;        }        return false;    }復制代碼

以上方法說明:

只有當當前請求的contentType是 "multipart/" 的時候,才會將此請求當做文件上傳的請求。

 

總結:

綜合來看,spring其實是通過Apache的 commons-fileupload來檢測請求是否為文件上傳的請求。而commons-fileupload又是通過如下兩個條件來判斷:

1. 請求方法必須是 post.

2. 請求的contentType 必須設置為以 "multipart/" 開頭。

這下你該明白為什么我們在上傳文件的時候必須要做的那些設置了吧。

 

好啦,回到文章開始的問題:

org.springframework.web.multipart.MultipartException: The current request is not a multipart request

這個問題是怎么導致的呢?

其實springmvc 在處理方法入參的時候,發現了你的一個參數為 MultipartFile 類型或者是其數組或者包含他的容器類型,那么springmvc 就會通過上面類似的方法去檢驗(通過contentType)。代碼如下:

復制代碼
private void assertIsMultipartRequest(HttpServletRequest request) {        String contentType = request.getContentType();        if (contentType == null || !contentType.toLowerCase().startsWith("multipart/")) {            throw new MultipartException("The current request is not a multipart request");        }    }復制代碼

那么這個問題該如何解決呢?

(1)ContentType 必須設置為 multipart/ 開頭的(通常是multipart/form-data)。我之所以會遇到這個問題,其實是因為在APP請求的時候明明使用的multipart/form-data,但是卻始終通不過,嘗試用瀏覽器OK。

(2)在保證(1)的情況,如果還是這個錯誤,那么通過上面的分析,其實也很好解決,怎么解決?

  spring在處理入參的時候, 不是遇到MultipartFile相關就會先去校驗么,OK,利用這個,那么咱們可以改寫入參(直接接收原生的http request),然后自己手動去校驗啊對吧,這不就繞過了。當繞過這一步之后,springmvc會通過之前分析的代碼,對收到的請求進行校驗轉換,最終也會得到MultipartHttpServletRequest。修改如下:

復制代碼
@RequestMapping(value = "/upload", method = RequestMethod.POST)public ResultView upload(HttpServletRequest request) {    if (request instanceof MultipartHttpServletRequest) {        // process    }}復制代碼

OK, 這樣就通過了。

好啦,本篇就先寫到這兒,下篇將向大家談談springmvc上傳文件的效率問題。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲奶大毛多的老太婆| 国产一区二区三区丝袜| 亚洲美女喷白浆| 久久精品91久久久久久再现| 色伦专区97中文字幕| 日本高清久久天堂| 欧美激情一区二区三区久久久| 国产欧美在线播放| 丝袜情趣国产精品| 久久久久久国产| 亚洲欧美激情一区| 久久韩国免费视频| 一区二区av在线| 国产精品视频一区二区高潮| 欧美日韩福利视频| 最新国产成人av网站网址麻豆| 精品久久中文字幕久久av| 欧美激情xxxx| 中文字幕不卡av| 66m—66摸成人免费视频| 亚洲欧美日韩精品久久奇米色影视| 久久视频在线观看免费| 国产精品一区二区三区毛片淫片| x99av成人免费| 日韩在线视频网站| 亚洲精品视频久久| 亚洲韩国日本中文字幕| 国产精品视频xxx| 91av视频导航| 亚洲一区二区三区成人在线视频精品| 懂色av中文一区二区三区天美| 国产精品久久久久久久久久新婚| 欧美色视频日本高清在线观看| 国产热re99久久6国产精品| 欧美最顶级的aⅴ艳星| 精品国产91乱高清在线观看| 久久青草福利网站| 97久久久免费福利网址| 精品亚洲精品福利线在观看| 午夜精品久久久久久久久久久久久| 国产一区二区丝袜| 成人在线视频网站| 久久精彩免费视频| 亚洲欧美激情在线视频| www.亚洲成人| 国产精品久久久久久久久借妻| 亚洲free性xxxx护士hd| 国产午夜精品一区理论片飘花| 一个人www欧美| 国产精品亚洲第一区| 亚洲综合一区二区不卡| 国产精品吹潮在线观看| 欧美日韩亚洲精品内裤| 8x海外华人永久免费日韩内陆视频| 久久久久久久久久av| 永久免费看mv网站入口亚洲| 国产精品稀缺呦系列在线| 欧美插天视频在线播放| 日本欧美一二三区| 亚洲午夜国产成人av电影男同| 97在线看免费观看视频在线观看| 久久这里有精品| 亚洲国产99精品国自产| 久久久999国产| 在线亚洲国产精品网| 欧美老女人bb| 国产亚洲欧美一区| 国产久一一精品| 久久久免费电影| 国产亚洲欧洲在线| 国产精品福利网站| 久久99国产精品久久久久久久久| 日韩网站在线观看| 日韩成人在线视频| 成人福利网站在线观看11| 精品成人国产在线观看男人呻吟| 日韩av网址在线观看| 亚洲成人av片在线观看| 午夜精品免费视频| 欧美日韩另类在线| 亚洲免费av电影| 国产+成+人+亚洲欧洲| 国产视频综合在线| 精品无人区乱码1区2区3区在线| 久久综合网hezyo| 国产精品天天狠天天看| 九九综合九九综合| 久久成人精品一区二区三区| 欧美做受高潮1| 欧美成人免费全部观看天天性色| 成人在线视频网| 亚洲免费伊人电影在线观看av| 最近2019中文字幕第三页视频| 国产亚洲精品va在线观看| 国产一区二区三区直播精品电影| 亚洲国产精品va在看黑人| 国产亚洲激情视频在线| 日韩高清人体午夜| 青青草国产精品一区二区| 久久久久国产精品免费网站| 最近中文字幕日韩精品| 久久久av亚洲男天堂| 国产精品第8页| 欧美日韩综合视频网址| 91av在线影院| 国产精品欧美日韩久久| 最近2019免费中文字幕视频三| 91亚洲精品久久久久久久久久久久| 91国语精品自产拍在线观看性色| 国产精欧美一区二区三区| 欧美激情xxxx性bbbb| 欧美激情一区二区三区高清视频| 国内伊人久久久久久网站视频| 亚洲人成在线播放| 97精品国产aⅴ7777| 亚洲国产精品女人久久久| 国产精品扒开腿做爽爽爽视频| 欧美在线视频观看免费网站| 91高清免费在线观看| 色婷婷av一区二区三区在线观看| 亚洲色无码播放| 亚洲欧洲一区二区三区在线观看| 国产性猛交xxxx免费看久久| 欧美性猛交99久久久久99按摩| 青青草成人在线| 日韩激情第一页| 亚洲国产成人91精品| 91精品久久久久久久久| 国产欧美精品va在线观看| 欧美自拍大量在线观看| 欧美美女18p| 成人激情av在线| 欧美日韩国产va另类| 国产精品一区二区久久精品| 4444欧美成人kkkk| 亚州精品天堂中文字幕| 成人xxxxx| 欧美另类xxx| 亚洲欧美日韩一区二区在线| 久久91精品国产91久久久| 成人免费视频在线观看超级碰| 亚洲**2019国产| 九九热这里只有精品免费看| 国产精品九九九| 欧美最猛性xxxxx亚洲精品| 91免费看片在线| 懂色aⅴ精品一区二区三区蜜月| 国产精品av免费在线观看| 国产精品精品视频| 亚洲激情视频网| 日韩高清电影免费观看完整| 国产精品7m视频| 亚洲国产精品电影| 亚洲天堂成人在线| 色多多国产成人永久免费网站| 欧美激情欧美激情| 亚洲a区在线视频| 亚洲最新中文字幕| 久久精品91久久香蕉加勒比| 欧美激情综合色综合啪啪五月| 日本sm极度另类视频| 国产精品成久久久久三级| 久久综合色影院| 亚洲国产精品成人va在线观看|