记录一下
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调用
参数没有生效??
- 正常表单请求