Spring Cloud中FeignClient实现文件上传功能

网友投稿 250 2023-01-08


Spring Cloud中FeignClient实现文件上传功能

项目概况:Spring Cloud搭的微服务,使用了eureka,FeignClient,现在遇到FeignClient调用接口时不支持上传文件,

百度到两种方案,一种是使用feign-form和feign-form-spring库来做,源码地址。

具体的使用方法是加入maven依赖

io.github.openfeign.form

feign-form-spring

3.2.2

io.github.openfeign.form

feign-form

3.2.2

注入SpringFormEncoder类

@Bean

@Primary

@Scope("prototype")

public Encoder multipartFormEncoder() {

return new SpringFormEncoder();

}

FeignClient接口里方法参数是文件类型的要用@RequestPart注解,且要设置ContentType为multipart/form-data

@ResponseBody

@RequestMapping(value = "/ctstestcase/updateTestCase", method = {RequestMethod.POST}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)

Map updateTestCase(@RequestParam("testcaseId") String testcaseId,

@RequestParam("name") String name, @RequestParam("assignId") String assignId,

@RequestParam("areaId") String areaId, @RequestParam("state") Integer state,

@RequestParam("iterationId") String iterationId,@RequestParam("priority") Integer priority,

@RequestParam("moduleId") String moduleId, @RequestParam("executionType") Integer executionType,

@RequestParam("summary") String summary, @RequestParam("tcsteps") String tcsteps,

@RequestParam("relations") String relations,@RequestParam("attachments") String attachments,

@RequestPart("files") MultipartFile[] files);

但遇到一个问题,就是不支持文件数组类型,我看了源码,发现源码里底层是有对MultipartFile[]类型的支持的,源码中有个类叫SpringManyMultipartFilesWriter,是专门针对文件数组类型进行操作的,但是配置到项目里的SpringFormEncoder类里却没有对文件数组类型的判断,以致不能支持文件数组的上传.。

SpringManyMultipartFilesWriter源码:

@FieldDefaults(level = PRIVATE, makeFinal = true)

public class SpringManyMultipartFilesWriter extends AbstractWriter {

SpringSingleMultipartFileWriter fileWriter = new SpringSingleMultipartFileWriter();

@Override

public void write (Output output, String boundary, String key, Object value) throws Exception {

if (value instanceof MultipartFile[]) {

val files = (MultipartFile[]) value;

for (val file : files) {

fileWriter.write(output, boundary, key, file);

}

} else if (value instanceof Iterable) {

val iterable = (Iterable>) value;

for (val file : iterable) {

fileWriter.write(output, boundary, key, file);

}

}

}

@Override

public boolean isApplicable (Object value) {

if (value == null) {

return false;

}

if (value instanceof MultipartFile[]) {

return true;

}

if (value instanceof Iterable) {

val iterable = (Iterable>) value;

val iterator = iterable.iterator();

if (iterator.hasNext() && iterator.next() instanceof MultipartFile) {

return true;

}

}

return false;

}

SpringFormEncoder源码:

public class SpringFormEncoder extends FormEncoder {

/**

* Constructor with the default Feign's encoder as a delegate.

*/

public SpringFormEncoder () {

this(new Encoder.Default());

}

/**

* Constructor with specified delegate encoder.

*

* @param delegate delegate encoder, if this encoder couldn't encode object.

*/

public SpringFormEncoder (Encoder delegate) {

super(delegate);

val processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);

processor.addWriter(new SpringSingleMultipartFileWriter());

processor.addWriter(new SpringManyMultipartFilesWriter());

}

@Override

public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException {

if (!boddFQWTyType.equals(MultipartFile.class)) {

super.encode(object, bodyType, template);

return;

}

val file = (MultipartFile) object;

val data = singletonMap(file.getName(), object);

super.encode(data, MAP_STRING_WILDCARD, template);

}

}

从上面SpringFormEncoder的源码上可以看到SpringFormEncoder类构造时把SpringManyMultipartFilesWriter实例添加到了处理器列表里了,但是在encode方法里又只判断了MultipartFile类型,没有判断数组类型,这就比较奇怪了,底层有对数组的支持但上层却缺少了相应判断,而且在源码里的test包里也没有对文件数组类型的测试,难道只是encode方法里漏掉了?还是说那个文件数组的支持有问题?所以encode方法里才没有加入对其的判断?

于是我先试着对encode方法进行扩展加入对文件数组的判断,应该就可以支持文件数组的上传了,于是把SpringFormEncoder类源码复制出来重命名为FeignSpringFormEncoder,源码如下:

public class FeignSpringFormEncoder extends FormEncoder {

/**

* Constructor with the default Feign's encoder as a delegate.

*/

public FeignSpringFormEncoder() {

this(new Encoder.Default());

}

/**

* Constructor with specified delegate encoder.

*

* @param delegate delegate encoder, if this encoder couldn't encode object.

*/

public FeignSpringFormEncoder(Encoder delegate) {

super(delegate);

val processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);

processor.addWriter(new SpringSingleMultipartFileWriter());

processor.addWriter(new SpringManyMultipartFilesWriter());

}

@Override

public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {

if (bodyType.equals(MultipartFile.class)) {

val file = (MultipartFile) object;

val data = singletonMap(file.getName(), object);

super.encode(data, MAP_STRING_WILDCARD, template);

return;

} else if (bodyType.equals(MultipartFile[].class)) {

val file = (MultipartFile[]) object;

if(file != null) {

val data = singletonMap(file.length == 0 ? "" : file[0].getName(), object);

super.encode(data, MAP_STRING_WILDCARD, template);

return;

}

}

super.encode(object, bodyType, template);

}

}

经过测试,已经可以支持文件数组了,完美解决。

这里再顺便说一下当时还百度到另一个解决文件上传的方案,这个方案就不细说了,直接上我用到的那个开源代码的地址

这个我试过也是可以解决文件上传问题的,但问题是FeignClient不能用SpringMVC的注解,得用Feign自带的注解,也因此我才扩展了第一种方法来http://做的文件上传功能。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:微服务网关有什么用(微服务网关的功能有哪些)
下一篇:微服务网关有什么特性(微服务网关的主要功能)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~