1. 程式人生 > >SpringBoot服務端上傳檔案

SpringBoot服務端上傳檔案

最近做一個小程式服務端模組支援,小程式涉及到了檔案上傳,之前架構組提供了一個統一上傳的介面給前端呼叫,因此沒有服務端需要開發的部分。

然而上線前一天,問題出現了,正式環境上傳檔案介面 不能提供給外網呼叫!需要通過服務端做中轉,臨危受命,緊急開發一個介面接收檔案,然後通過httpClient呼叫架構組的介面上傳檔案資料。

問題點如下:1.如果接收前端檔案 需要跟前端約定 2.httpClient請求 需要用連線池管理 

為了更快解決,上網查了一些資料,瞭解到springBoot可以使用

upload(@RequestParam("file") MultipartFile file
接收檔案

之後寫http呼叫程式碼,構建請求物件

//檔案引數
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            builder.setContentType(ContentType.MULTIPART_FORM_DATA);
            builder.addPart("file", fileBody);
            builder.addPart("path", pathBody);
            builder.addPart("projectName", projectNameBody);
            builder.addPart("rename", reNameBody);
            post.setEntity(builder.build());
突然發現了一個問題,構造builder裡面檔案是用java.io.File型別的,但是springBoot接收的是MultipartFile,兩者需要轉換,不能直接拿來用,於是乎,又查了一些資料關於MultipartFile轉換成File,都是通過生成臨時檔案的方式,考慮到檔案上傳資料量還是挺大的,如果出現問題,臨時檔案沒有及時清除,對伺服器的磁碟記憶體會有很大壓力,因此該方案不可行。

之後換了個方向,考慮http請求能不能直接傳輸MultipartFile,結果發現還真有,程式碼就改動了一行 然後問題解決:

//檔案引數
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            builder.setContentType(ContentType.MULTIPART_FORM_DATA);
            builder.addBinaryBody("file", file.getInputStream(), ContentType.MULTIPART_FORM_DATA, file.getOriginalFilename());
            builder.addPart("path", pathBody);
            builder.addPart("projectName", projectNameBody);
            builder.addPart("rename", reNameBody);
            post.setEntity(builder.build());
httpClient連線管理器通過開源的構建了一個,設定了連線池大小,最大超時時間等等配置資料。完整程式碼如下:
 /**
     * 上傳
     *
     * @param file
     * @param projectName
     * @param path
     * @param reName
     * @return
     **/
    public String uploadFileToOss(MultipartFile file, String projectName, String path, String reName) {
        HttpResponse response = null;
        HttpPost post = new HttpPost(businessConfigProperties.getFileUploadUrl());
        try {
            StringBody projectNameBody = new StringBody(projectName, ContentType.APPLICATION_JSON);
            StringBody pathBody = new StringBody(path, ContentType.APPLICATION_JSON);
            StringBody reNameBody = new StringBody(reName, ContentType.APPLICATION_JSON);
            //檔案引數
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
            builder.setContentType(ContentType.MULTIPART_FORM_DATA);
            builder.addBinaryBody("file", file.getInputStream(), ContentType.MULTIPART_FORM_DATA, file.getOriginalFilename());
            builder.addPart("path", pathBody);
            builder.addPart("projectName", projectNameBody);
            builder.addPart("rename", reNameBody);
            post.setEntity(builder.build());
            response = apacheHttpDnsClientBuilder.build().execute(post);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.OK.value()) {
                HttpEntity resEntity = response.getEntity();
                String resultStr = EntityUtils.toString(resEntity);
                ResultMap<String> result = JSON.parseObject(resultStr, ResultMap.class);
                LogUtil.log(LogUtil.EXCEPTION_HANDLER, Level.INFO, LogUtil.formatLog(KVJsonFormat.title
                        ("uploadFileToOss").add("result", resultStr)));
                if (Objects.toString(ResultMap.SUCCESS).equals(Objects.toString(result.get(ResultMap.CODE)))) {
                    return businessConfigProperties.getFileDownloadUrl() + "/" + result.get(ResultMap.DATA);
                } else {
                    LogUtil.log(LogUtil.EXCEPTION_HANDLER, Level.ERROR, LogUtil.formatLog(KVJsonFormat.title
                            ("uploadFileToOss fail").add("result", resultStr)));
                    throw new MiniProgramException(FILE_UPLOAD_FAIL);
                }
            } else {
                LogUtil.log(LogUtil.EXCEPTION_HANDLER, Level.ERROR, LogUtil.formatLog(KVJsonFormat.title
                        ("uploadFileToOss fail").add("statusCode", statusCode)));
                throw new MiniProgramException(FILE_UPLOAD_FAIL);
            }
        } catch (Exception e) {
            throw new MiniProgramException(FILE_UPLOAD_FAIL);
        } finally {
            if (response != null) {
                EntityUtils.consumeQuietly(response.getEntity());
            }
            post.releaseConnection();
        }
    }

總結一下:專案管理流程出現了問題,前端也沒有及時提出這個問題,最後導致開發時間比較緊張,之前因為沒有接觸過這塊內容,因為unKnown感覺有點害怕,不過實際解決過程中,發現也沒有這麼困難,多去解決一些問題,在這個過程中肯定可以收收穫和成長

後記:踩了一個坑 專案環境執行一段時間之後 出現了這個提示Resolved exception caused by Handler execution: org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.

分析是因為上傳的檔案超過了1M,沒有配置檔案上傳的大小限制 預設限制1M