spring cloud实战与思考(三) 微服务之间通过fiegn上传一组文件(下)
需求场景:
用户调用微服务1的接口上传一组图片和对应的描述信息。微服务1处理后,再将这组图片上传给微服务2进行处理。各个微服务能区分开不同的图片进行不同处理。
上一篇博客已经讨论了在微服务之间传递一组图片和对应参数的解决方案。现在来看看如何对组内文件进行区分。当前项目中使用了“commons-fileupload”和“feign-form”两个库进行文件传输。
“commons-fileupload”库可以将http request转换成“MultipartHttpServletRequest”,最终能够获取到“MultipartFile”列表:
@RequestMapping(value="/psts/add/insertWithFiles", method = RequestMethod.POST) public Object pastsAddTripInfo(HttpServletRequest request) { //创建一个通用的多部分解析器 CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext()); //转换成多部分request MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest)request; Map<String, MultipartFile> files = multiRequest.getFileMap(); for(Map.Entry<String, MultipartFile> entry : files.entrySet()) { System.out.println("file key name: " + entry.getKey()); //文件对象名称 System.out.println("file original name: " + entry.getValue().getOriginalFilename()); //文件原始名称 System.out.println("file name: " + entry.getValue().getName()); //文件对象名称 } }
“MultipartFile”的“getName()”能获取到form表单中指定的对象名称。对这个名称进行约定就能区分不同的文件。
选择文件: <input type="file" name="file1" /> <br/><br/> <input type="file" name="file2" /> <br/><br/> <input type="submit" value="上传" />
使用文件对象名称,微服务1可以区分开组内的各文件。微服务1向微服务2上传一组文件的时候使用“feign-form”库。在上一篇微博中已经找到了解决方案。但是方案的“@RequestPart(value = "files") MultipartFile[] photoFiles”接口方式将这组文件的对象名称都限定为“files”。貌似微服务2只能用文件的原始名称“getOriginalFilename()”对文件进行区分。但是对文件名称进行约定不利于用户使用体验。
既然微服务1拥有文件的区分标识,即文件对象名称,并且文件原始名称在传输过程中保持不变。不妨在封装文件时使用“对象名称.原始名称”替换文件原始名称。这样即保留了文件原始名称信息,又加入了文件区分标识。只要小小的改动一下“feign-form”库中封装“MultipartFile[]”的接口,就能实现这个目的。
封装“MultipartFile[]”的类是“SpringManyMultipartFilesWriter”,它使用“SpringSingleMultipartFileWriter”做具体的封装工作。所以声明一个新类“FeignSpringSingleMultipartFileWriter”继承自“SpringSingleMultipartFileWriter”,然后修改其“write()”函数。
import feign.form.multipart.Output; import feign.form.spring.SpringSingleMultipartFileWriter; import org.springframework.web.multipart.MultipartFile; public class FeignSpringSingleMultipartFileWriter extends SpringSingleMultipartFileWriter { public FeignSpringSingleMultipartFileWriter() { } @Override protected void write(Output output, String key, Object value) throws Exception { MultipartFile file = (MultipartFile)value; //file.getName()就是文件区分标识 this.writeFileMetadata(output, key, file.getName()+"."+file.getOriginalFilename(), file.getContentType()); output.write(file.getBytes()); } }
声明一个“FeignSpringManyMultipartFilesWriter”类,引用“FeignSpringSingleMultipartFileWriter”类:
import feign.form.multipart.AbstractWriter; import feign.form.multipart.Output; import org.springframework.web.multipart.MultipartFile; import java.util.Iterator; public class FeignSpringManyMultipartFilesWriter extends AbstractWriter { //引用“FeignSpringSingleMultipartFileWriter” private final FeignSpringSingleMultipartFileWriter fileWriter = new FeignSpringSingleMultipartFileWriter(); public FeignSpringManyMultipartFilesWriter() { } public void write(Output output, String boundary, String key, Object value) throws Exception { if (value instanceof MultipartFile[]) { MultipartFile[] files = (MultipartFile[])((MultipartFile[])value); MultipartFile[] var6 = files; int var7 = files.length; for(int var8 = 0; var8 < var7; ++var8) { MultipartFile file = var6[var8]; this.fileWriter.write(output, boundary, key, file); } } else if (value instanceof Iterable) { Iterable iterable = (Iterable)value; Iterator var11 = iterable.iterator(); while(var11.hasNext()) { Object file = var11.next(); this.fileWriter.write(output, boundary, key, file); } } } public boolean isApplicable(Object value) { if (value == null) { return false; } else if (value instanceof MultipartFile[]) { return true; } else { if (value instanceof Iterable) { Iterable iterable = (Iterable)value; Iterator iterator = iterable.iterator(); if (iterator.hasNext() && iterator.next() instanceof MultipartFile) { return true; } } return false; } } }
修改上一个博客中新增的“FeignSpringFormEncoder”类,在构造函数中使用“FeignSpringManyMultipartFilesWriter”替换原来的“SpringManyMultipartFilesWriter”类。
public class FeignSpringFormEncoder extends FormEncoder { public FeignSpringFormEncoder() { this(new Default()); } public FeignSpringFormEncoder(Encoder delegate) { super(delegate); MultipartFormContentProcessor processor = (MultipartFormContentProcessor)this.getContentProcessor(ContentType.MULTIPART); processor.addWriter(new SpringSingleMultipartFileWriter()); //使用新的封装类“FeignSpringManyMultipartFilesWriter” processor.addWriter(new FeignSpringManyMultipartFilesWriter()); }
至此修改完毕,微服务2可以将区分标识从文件的原始名称中解析出来使用。不知道是否还有更简单的方式满足这个需求?