记录一下
feign文件上传
- 环境 
  - spring-boot 2.3.7
 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent>- 依赖引入
 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.1.0.RELEASE</version> </dependency>- 网上版本的依赖
 <!-- Feign文件上传依赖--> <dependencies> <dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form</artifactId> <version>3.8.0</version> </dependency> <dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form-spring</artifactId> <version>3.8.0</version> </dependency> </dependencies>dependency>和你的feign依赖有关,自己判断下,2.1.0已经包含了  
配置文件
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
@Configuration
public class FeignMultipartSupportConfig {
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;
    @Bean
    @Primary
    @Scope("prototype")
    public Encoder multipartFormEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }
    @Bean
    public feign.Logger.Level multipartLoggerLevel() {
        return feign.Logger.Level.FULL;
    }
}
feign接口
import com.alibaba.fastjson.JSONObject;
import com.zzg.web.config.FeignMultipartSupportConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
/**
 * @program: atomic-upms
 * @description:
 * @author: zzg@xnj
 * @create: 2024-08-20 16:50
 **/
@FeignClient(value = "file-service", url = "${file-service}", configuration  = {FeignMultipartSupportConfig.class})
public interface FileFeign {
    @RequestMapping(value ="/file/fileUpload",method = RequestMethod.POST, consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    JSONObject fileupload(@RequestPart(value="uploadfile") MultipartFile uploadfile) ;
}
service
@Service
public class FileService {
    @Resource
    private FileFeign fileFeign;
    public void uploadFile(MultipartFile file) {
        fileFeign.fileupload(file);
    }
}
controller
注意两个接口的区别
@Api(tags = "文件")
@RestController
@RequestMapping("/file")
public class UploadController {
    @Resource
    private FileService fileService;
    @ApiOperation("上传文件")
    @PostMapping("/fileUpload")
    public ResponseModel uploadFile(@RequestPart MultipartFile uploadfile) {
        fileService.uploadFile(uploadfile);
        return new ResponseModel("200","ok");
    }
    @ApiOperation("上传文件2")
    @PostMapping("/fileUpload2")
    public ResponseModel uploadFile2(@RequestPart MultipartFile file) {
        fileService.uploadFile(file);
        return new ResponseModel("200","ok");
    }
}
- feign的对应的controller
 @ApiOperation("上传文件")
    @PostMapping("/fileUpload")
    public ResponseModel uploadFile(@RequestPart MultipartFile uploadfile) {
        fileService.uploadFile(uploadfile);
        return new ResponseModel("200","ok");
    }
运行结果
- 调用fileUpload 接口 --》上传成功
- 调用fileUpload2 接口 --》上传失败
远程端报错信息
解决
- 问题原因 :前后端参数名对应不一致
可能原因:
前后端参数名对应不一致
spring.servlet.multipart.enabled=false即关闭文件上传支持
配置文件中指定了文件上传时的大小值问题
切换内嵌容器tomcat到undertow的配置问题
spring.servlet.multipart.location=/tmp指定了临时文件站,但路径不存在
多次读取HttpServletRequest流
springboot已经有CommonsMultipartResolver,需要排除原有的Multipart配置@EnableAutoConfiguration(exclude = {MultipartAutoConfiguration.class})
摘抄文章链接
- 解决方案: 添加变量名,利用MultipartFile.getName
   @ApiOperation("上传文件2")
    @PostMapping("/fileUpload2")
    public ResponseModel uploadFile2(@RequestPart MultipartFile file) {
        try {
            file = new MultipartFileDto("uploadfile",file.getOriginalFilename(),file.getContentType(), file.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
        fileService.uploadFile(file);
        return new ResponseModel("200","ok");
    }
 
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
/**
 * @program: atomic-upms
 * @description:
 * @author: zzg@xnj
 * @create: 2024-08-20 20:24
 **/
public class MultipartFileDto implements MultipartFile {
    private final String name;
    private String originalFilename;
    private String contentType;
    private final byte[] content;
    /**
     * Create a new MultipartFileDto with the given content.
     * @param name the name of the file
     * @param content the content of the file
     */
    public MultipartFileDto(String name, byte[] content) {
        this(name, "", null, content);
    }
    /**
     * Create a new MultipartFileDto with the given content.
     * @param name the name of the file
     * @param contentStream the content of the file as stream
     * @throws IOException if reading from the stream failed
     */
    public MultipartFileDto(String name, InputStream contentStream) throws IOException {
        this(name, "", null, FileCopyUtils.copyToByteArray(contentStream));
    }
    /**
     * Create a new MultipartFileDto with the given content.
     * @param name the name of the file
     * @param originalFilename the original filename (as on the client's machine)
     * @param contentType the content type (if known)
     * @param content the content of the file
     */
    public MultipartFileDto(String name, String originalFilename, String contentType, byte[] content) {
        this.name = name;
        this.originalFilename = (originalFilename != null ? originalFilename : "");
        this.contentType = contentType;
        this.content = (content != null ? content : new byte[0]);
    }
    /**
     * Create a new MultipartFileDto with the given content.
     * @param name the name of the file
     * @param originalFilename the original filename (as on the client's machine)
     * @param contentType the content type (if known)
     * @param contentStream the content of the file as stream
     * @throws IOException if reading from the stream failed
     */
    public MultipartFileDto(String name, String originalFilename, String contentType, InputStream contentStream)
            throws IOException {
        this(name, originalFilename, contentType, FileCopyUtils.copyToByteArray(contentStream));
    }
    @Override
    public String getName() {
        return this.name;
    }
    @Override
    public String getOriginalFilename() {
        return this.originalFilename;
    }
    @Override
    public String getContentType() {
        return this.contentType;
    }
    @Override
    public boolean isEmpty() {
        return (this.content.length == 0);
    }
    @Override
    public long getSize() {
        return this.content.length;
    }
    @Override
    public byte[] getBytes() throws IOException {
        return this.content;
    }
    @Override
    public InputStream getInputStream() throws IOException {
        return new ByteArrayInputStream(this.content);
    }
    @Override
    public void transferTo(File dest) throws IOException, IllegalStateException {
        FileCopyUtils.copy(this.content, dest);
    }
}
事后诸葛亮
- feign调用
参数没有生效??

- 正常表单请求
  
  



















![[统计分析] 出现典型锯齿图的一种情况;资源泄露](https://i-blog.csdnimg.cn/direct/44cbae8686db4569a98d803dce3dd4b0.png#pic_center)

