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可以將區分標識從文件的原始名稱中解析出來使用。不知道是否還有更簡單的方式滿足這個需求?
spring cloud實戰與思考(三) 微服務之間通過fiegn上傳一組文件(下)