欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-12-10 19:00:34
项目概况:spring cloud搭的微服务,使用了eureka,feignclient,现在遇到feignclient调用接口时不支持上传文件, 百度到两种方案,一种是...

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

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

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

<dependency>
 <groupid>io.github.openfeign.form</groupid>
 <artifactid>feign-form-spring</artifactid>
 <version>3.2.2</version>
 </dependency>
 <dependency>
 <groupid>io.github.openfeign.form</groupid>
 <artifactid>feign-form</artifactid>
 <version>3.2.2</version>
</dependency>

注入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<string, object> 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 (!bodytype.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自带的注解,也因此我才扩展了第一种方法来做的文件上传功能。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。