File对象转MultipartFile 如何new出高仿MultipartFile对象

目录

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,分析下为啥出现这个问题, 先占个坑~

 

 


​​​​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值