Spring Cloud中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自带的注解,也因此我才扩展了第一种方法来做的文件上传功能。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。