使用Feign实现微服务间文件传输

家电修理 2023-07-16 19:17www.caominkang.com电器维修

在很多时候我们会遇到微服务之间文件传输,很多时候我们可以通过序列化等方式解决(如图片等)。

最近项目中有个excel上传,以及多媒体文件上传,直接报错。

也试了2种解决方式,都不可行。

1.写一个文件Encoder解析器,会出现其他的rest请求出现encoder错误

2.springcloud feign有一个规范,不可以传输2个对象,可以是一个对象带几个参数方式。

那么我们现在需要一种方式,不配置全局的解析器,而是通过Feign Builder 去管理上传文件,这种方式管理起来也较为方便。

引用包


  .flix.feign
  feign-core
  8.17.0


  .flix.feign
  feign-jackson
  8.17.0


  .flix.feign
  feign-slf4j
  8.17.0

调用方式 

@ApiOperation(value = "上传Excel", notes = "上传Excel")
@RequestMapping(value = "/imExcel", method = RequestMethod.POST, produces = request_headers)
public ActionResult imExcel(@RequestBody MultipartFile file,@RequestParam("operatorId") Integer operatorId){
 
  if(file == null || file.isEmpty()|| operatorId==null)
 return ne ActionResult<>(ResultType.BAD_REQUEST,"文件与操作用户ID都不能为空");
  String fileName = file.getOriginalFilename();
  if (!fileName.matches("^.+\.(?i)(xls)$") && !fileName.matches("^.+\.(?i)(xlsx)$")) {
 return ne ActionResult<>(ResultType.BAD_REQUEST,"上传文件格式错误,请上传后缀为.xls或.xlsx的文件");
  }
  Feign.Builder encoder = Feign.builder()
   .decoder(ne JacksonDecoder())
   .encoder(ne FeignEncoder());
  FileUpload plainFileUpload = encoder.target(FileUpload.class,LABEL_URL);
  return plainFileUpload.imComplainExcel(file,operatorId);
 
}

文件Encode

import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import .springframeork.core.io.InputStreamResource;
import .springframeork.core.io.Resource;
import .springframeork.http.HttpEntity;
import .springframeork.http.HttpHeaders;
import .springframeork.http.HttpOutputMessage;
import .springframeork.http.MediaType;
import .springframeork.http.converter.HttpMessageConverter;
import .springframeork.util.CollectionUtils;
import .springframeork.util.linkedMultiValueMap;
import .springframeork.eb.client.RestTemplate;
import .springframeork.eb.multipart.MultipartFile;
 
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
 

public class FeignEncoder implements Encoder {
 
 
  private final List> converters = ne RestTemplate().getMessageConverters();
  private final HttpHeaders multipartHeaders = ne HttpHeaders();
  private final HttpHeaders jsonHeaders = ne HttpHeaders();
 
  public static final Charset UTF_8 = Charset.forName("UTF-8");
 
  public FeignEncoder() {
 multipartHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
 jsonHeaders.setContentType(MediaType.APPLICATION_JSON);
  }
 
 
  @Override
  public void encode(Object object, Type bodyType, RequestTemplate template) thros EncodeException {
 if (isFormRequest(bodyType)) {
   encodeMultipartFormRequest((Map) object, template);
 } else {
   encodeRequest(object, jsonHeaders, template);
 }
  }
 
 
  private void encodeMultipartFormRequest(Map formMap, RequestTemplate template) thros EncodeException {
 if (CollectionUtils.isEmpty(formMap)) {
   thro ne EncodeException("参数不能为空.");
 }
 linkedMultiValueMap map = ne linkedMultiValueMap<>();
 for (Entry entry : formMap.entrySet()) {
   Object value = entry.getValue();
   if (isMultipartFile(value)) {
 map.add(entry.getKey(), encodeMultipartFile((MultipartFile) value));
   } else if (isMultipartFileArray(value)) {
 encodeMultipartFiles(map, entry.getKey(), Arrays.asList((MultipartFile[]) value));
   } else {
 map.add(entry.getKey(), encodeJsonObject(value));
   }
 }
 encodeRequest(map, multipartHeaders, template);
  }
 
  private boolean isMultipartFile(Object object) {
 return object instanceof MultipartFile;
  }
 
  private boolean isMultipartFileArray(Object o) {
 return o != null && o.getClass().isArray() && MultipartFile.class.isAssignableFrom(o.getClass().getComponentType());
  }
 
  
  private HttpEntity encodeMultipartFile(MultipartFile file) {
 HttpHeaders filePartHeaders = ne HttpHeaders();
 filePartHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
 try {
   Resource multipartFileResource = ne MultipartFileResource(file.getOriginalFilename(), file.getSize(), file.getInputStream());
   return ne HttpEntity<>(multipartFileResource, filePartHeaders);
 } catch (IOException ex) {
   thro ne EncodeException("Cannot encode request.", ex);
 }
  }
 
  
  private void encodeMultipartFiles(linkedMultiValueMap map, String name, List files) {
 HttpHeaders filePartHeaders = ne HttpHeaders();
 filePartHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
 try {
   for (MultipartFile file : files) {
 Resource multipartFileResource = ne MultipartFileResource(file.getOriginalFilename(), file.getSize(), file.getInputStream());
 map.add(name, ne HttpEntity<>(multipartFileResource, filePartHeaders));
   }
 } catch (IOException ex) {
   thro ne EncodeException("Cannot encode request.", ex);
 }
  }
 
  
  private HttpEntity encodeJsonObject(Object o) {
 HttpHeaders jsonPartHeaders = ne HttpHeaders();
 jsonPartHeaders.setContentType(MediaType.APPLICATION_JSON);
 return ne HttpEntity<>(o, jsonPartHeaders);
  }
 
  
  private void encodeRequest(Object value, HttpHeaders requestHeaders, RequestTemplate template) thros EncodeException {
 ByteArrayOutputStream outputStream = ne ByteArrayOutputStream();
 HttpOutputMessage dummyRequest = ne HttpOutputMessageImpl(outputStream, requestHeaders);
 try {
   Class requestType = value.getClass();
   MediaType requestContentType = requestHeaders.getContentType();
   for (HttpMessageConverter messageConverter : converters) {
 if (messageConverter.canWrite(requestType, requestContentType)) {
   ((HttpMessageConverter) messageConverter).rite(
value, requestContentType, dummyRequest);
   break;
 }
   }
 } catch (IOException ex) {
   thro ne EncodeException("Cannot encode request.", ex);
 }
 HttpHeaders headers = dummyRequest.getHeaders();
 if (headers != null) {
   for (Entry> entry : headers.entrySet()) {
 template.header(entry.getKey(), entry.getValue());
   }
 }
 
 template.body(outputStream.toByteArray(), UTF_8);
  }
 
  
  private class HttpOutputMessageImpl implements HttpOutputMessage {
 
 private final OutputStream body;
 private final HttpHeaders headers;
 
 public HttpOutputMessageImpl(OutputStream body, HttpHeaders headers) {
   this.body = body;
   this.headers = headers;
 }
 
 @Override
 public OutputStream getBody() thros IOException {
   return body;
 }
 
 @Override
 public HttpHeaders getHeaders() {
   return headers;
 }
 
  }
 
 
  static boolean isFormRequest(Type type) {
 return MAP_STRING_WILDCARD.equals(type);
  }
 
 
  static class MultipartFileResource extends InputStreamResource {
 
 private final String filename;
 private final long size;
 
 public MultipartFileResource(String filename, long size, InputStream inputStream) {
   super(inputStream);
   this.size = size;
   this.filename = filename;
 }
 
 @Override
 public String getFilename() {
   return this.filename;
 }
 
 @Override
 public InputStream getInputStream() thros IOException, IllegalStateException {
   return super.getInputStream(); //To change body of generated methods, choose Tools | Templates.
 }
 
 @Override
 public long contentLength() thros IOException {
   return size;
 }
 
  }
 
}


Feign调用接口

@RequestLine("POST /punish/imExcel")
ActionResult> imPunishExcel(@Param("file") MultipartFile file, @Param("operatorId") Integer operatorId);

Copyright © 2016-2025 www.caominkang.com 曹敏电脑维修网 版权所有 Power by