首页 > 编程 > Java > 正文

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

2019-11-26 09:03:42
字体:
来源:转载
供稿:网友

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

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

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

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

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

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

引用包

<dependency>  <groupId>com.netflix.feign</groupId>  <artifactId>feign-core</artifactId>  <version>8.17.0</version></dependency><dependency>  <groupId>com.netflix.feign</groupId>  <artifactId>feign-jackson</artifactId>  <version>8.17.0</version></dependency><dependency>  <groupId>com.netflix.feign</groupId>  <artifactId>feign-slf4j</artifactId>  <version>8.17.0</version></dependency>

调用方式 

@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 new ActionResult<>(ResultType.BAD_REQUEST,"文件与操作用户ID都不能为空");  String fileName = file.getOriginalFilename();  if (!fileName.matches("^.+//.(?i)(xls)$") && !fileName.matches("^.+//.(?i)(xlsx)$")) {    return new ActionResult<>(ResultType.BAD_REQUEST,"上传文件格式错误,请上传后缀为.xls或.xlsx的文件");  }  Feign.Builder encoder = Feign.builder()      .decoder(new JacksonDecoder())      .encoder(new FeignEncoder());  FileUpload complainFileUpload = encoder.target(FileUpload.class,LABEL_URL);  return complainFileUpload.imComplainExcel(file,operatorId); }

文件Encode

import feign.RequestTemplate;import feign.codec.EncodeException;import feign.codec.Encoder;import org.springframework.core.io.InputStreamResource;import org.springframework.core.io.Resource;import org.springframework.http.HttpEntity;import org.springframework.http.HttpHeaders;import org.springframework.http.HttpOutputMessage;import org.springframework.http.MediaType;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.util.CollectionUtils;import org.springframework.util.LinkedMultiValueMap;import org.springframework.web.client.RestTemplate;import org.springframework.web.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; /** * @author lxl */public class FeignEncoder implements Encoder {    private final List<HttpMessageConverter<?>> converters = new RestTemplate().getMessageConverters();  private final HttpHeaders multipartHeaders = new HttpHeaders();  private final HttpHeaders jsonHeaders = new 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) throws EncodeException {    if (isFormRequest(bodyType)) {      encodeMultipartFormRequest((Map<String, ?>) object, template);    } else {      encodeRequest(object, jsonHeaders, template);    }  }    private void encodeMultipartFormRequest(Map<String, ?> formMap, RequestTemplate template) throws EncodeException {    if (CollectionUtils.isEmpty(formMap)) {      throw new EncodeException("参数不能为空.");    }    LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();    for (Entry<String, ?> 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());  }   /**   * 设置头   * @param file   * @return   */  private HttpEntity<?> encodeMultipartFile(MultipartFile file) {    HttpHeaders filePartHeaders = new HttpHeaders();    filePartHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);    try {      Resource multipartFileResource = new MultipartFileResource(file.getOriginalFilename(), file.getSize(), file.getInputStream());      return new HttpEntity<>(multipartFileResource, filePartHeaders);    } catch (IOException ex) {      throw new EncodeException("Cannot encode request.", ex);    }  }   /**   * 映射   * @param map   * @param name   * @param files   */  private void encodeMultipartFiles(LinkedMultiValueMap<String, Object> map, String name, List<? extends MultipartFile> files) {    HttpHeaders filePartHeaders = new HttpHeaders();    filePartHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);    try {      for (MultipartFile file : files) {        Resource multipartFileResource = new MultipartFileResource(file.getOriginalFilename(), file.getSize(), file.getInputStream());        map.add(name, new HttpEntity<>(multipartFileResource, filePartHeaders));      }    } catch (IOException ex) {      throw new EncodeException("Cannot encode request.", ex);    }  }   /**   * {@link HttpEntity} {@code Content-type}   * {@code application/json}   *   * @param o   * @return   */  private HttpEntity<?> encodeJsonObject(Object o) {    HttpHeaders jsonPartHeaders = new HttpHeaders();    jsonPartHeaders.setContentType(MediaType.APPLICATION_JSON);    return new HttpEntity<>(o, jsonPartHeaders);  }   /**   * {@link org.springframework.web.client.RestTemplate}   *   * @param value   * @param requestHeaders   * @param template   * @throws EncodeException   */  private void encodeRequest(Object value, HttpHeaders requestHeaders, RequestTemplate template) throws EncodeException {    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();    HttpOutputMessage dummyRequest = new HttpOutputMessageImpl(outputStream, requestHeaders);    try {      Class<?> requestType = value.getClass();      MediaType requestContentType = requestHeaders.getContentType();      for (HttpMessageConverter<?> messageConverter : converters) {        if (messageConverter.canWrite(requestType, requestContentType)) {          ((HttpMessageConverter<Object>) messageConverter).write(              value, requestContentType, dummyRequest);          break;        }      }    } catch (IOException ex) {      throw new EncodeException("Cannot encode request.", ex);    }    HttpHeaders headers = dummyRequest.getHeaders();    if (headers != null) {      for (Entry<String, List<String>> entry : headers.entrySet()) {        template.header(entry.getKey(), entry.getValue());      }    }    /*    使用bytearray方式传输     */    template.body(outputStream.toByteArray(), UTF_8);  }   /**   * {@link org.springframework.http.HttpOutputMessage}   * {@link org.springframework.http.converter.HttpMessageConverter}   */  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() throws 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() throws IOException, IllegalStateException {      return super.getInputStream(); //To change body of generated methods, choose Tools | Templates.    }     @Override    public long contentLength() throws IOException {      return size;    }   } }

Feign调用接口

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

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表