目錄
1.問題
2.解決過程
3.解決問題
4. 總結問題 就是 RequestPart的坑
1.問題
最近遇到個問題:
服務端定義了個上傳檔案的restful api接口如下.
@PostMapping
public void updateAvatar(@PathVariable("userName") String userName,
@RequestPart("avatarMpFile") MultipartFile avatarMpFile) throws IOException {
//....
}
在swagger接口中測試接口 上傳檔案很正常,然而自己寫個feign 用戶端:
/**
* 修改頭像接口
*/
@PostMapping(value = "/api/data/employee/{userName}/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Result uploadAvatar(
@PathVariable("userName") String userName,
@RequestPart("avatarMpFile") MultipartFile avatarMpFile);
上傳始是服務端終報錯:
org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'avatarMpFile' is not present
org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'avatarMpFile' is not present

百思不得其解.
2.解決過程
後來試了下自己在用戶端中照着服務端寫個一模一樣的controller ,
@PostMapping(value = "/photoUpload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ApiOperation("頭像上傳 測試用記得删去")
public Result upload(@RequestParam("avatarMpFile")
MultipartFile multipartFile) throws Exception {
return Result.ok(photoUpdateService.modify(multipartFile, UserUtil.getUserName()));
}
自己在swagger上調用用戶端,又可以在用戶端通過feign 傳到服務端了
分析可能是自己建立的 MultipartFile檔案出了問題.
之前有問題的multipartFile建立方式為:
通過自定義的dto 實作MultipartFile接口實作的.
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.file.Files;
import javax.activation.MimetypesFileTypeMap;
import org.apache.commons.io.FileUtils;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.annotations.ApiModel;
/**
* 檔案dto
* Created on 2019-12-23
*/
@ApiModel(value = "FileDTO")
public class FileDTO implements MultipartFile, Serializable {
private String fileName;
/**
* 檔案伺服器隻接受file參數
*/
private String attachmentName = "file";
private
byte[] fileData;
public FileDTO(String fileName,
byte[] fileData) {
this.fileName = fileName;
this.fileData = fileData;
this.attachmentName = attachmentName;
}
public FileDTO(String attachmentName, String fileName,
byte[] fileData) {
this.fileName = fileName;
this.fileData = fileData;
this.attachmentName = attachmentName;
}
public String getName() {
return attachmentName;
}
@Override
public String getOriginalFilename() {
return fileName;
}
@Override
public String getContentType() {
return new MimetypesFileTypeMap().getContentType(fileName);
}
@Override
public boolean isEmpty() {
return fileData == null || fileData.length == 0;
}
@Override
public long getSize() {
return fileData.length;
}
@Override
public byte[] getBytes() {
return fileData;
}
@Override
public InputStream getInputStream() {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(fileData);
return byteArrayInputStream;
}
@Override
public void transferTo(File dest) throws IOException {
FileUtils.writeByteArrayToFile(dest, fileData);
if (dest.isAbsolute() && !dest.exists()) {
FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest.toPath()));
}
}
}
然後傳入檔案名和檔案二進制位元組數組即可
// 擷取檔案二進制byte數組
ByteArrayResource file = simpleFileClient.getFileResource(fileId, "media", fileAppId);
// 建立MultipartFile對象
MultipartFile multipartFile = new FileDTO("filename", file.getByteArray());
這種寫法大多數情況都沒問題,然而當服務端使用 @RequestPart 接收時就有問題
因為 spring中 使用MultipartFile 接收檔案是,MultipartFile中還有很多内部結構,如下
而我自己new出來的卻是這個樣子:
3.解決問題
到此問題答案出來了:應該是自己new出來的 MultipartFile不夠完美
于是網上搜尋了下" multipartFile FieldName"關鍵字 , 找到一個更好的方案
MultipartFile mfile = new CommonsMultipartFile(createFileItem(avatarMpFile,"avatarMpFile"));
/**
* 建立FileItem
*/
private FileItem createFileItem(MultipartFile file, String fieldName) {
FileItemFactory factory = new DiskFileItemFactory(16, null);
FileItem item = factory.createItem(fieldName, "text/plain", true, file.getName());
int bytesRead = 0;
byte[] buffer = new byte[8192];
try {
InputStream fis = file.getInputStream();
OutputStream os = item.getOutputStream();
while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
return item;
}
(CommonsMultipartFile,FileItemFactory 需要依賴commons-fileupload-1.3.2.jar包)
參考出處: https://www.cnblogs.com/Big-Boss/p/10729618.html
用這種方式new出來的MultipartFile 就有了FileItem, 完美解決問題.
4. 總結問題 就是 RequestPart的坑
了解@RequestBody 、@requestParam,@RequestPart差別
參考:https://blog.csdn.net/zy1471162851/article/details/88702936
下篇寫下 RequestPart,分析下為啥出現這個問題, 先占個坑~