feign No serializer found for class java.io.FileDescriptor and no properties discovered to create Be

No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.util.LinkedMultiValueMap[“media[file]”]->java.util.LinkedList[0]->java.io.FileInputStream[“fd”]) feign远程上传文件报错

  • feign服务端代码:
    在这里插入图片描述
    • feign客户端调用远程代码:
      在这里插入图片描述
  • 远程调用配置:
    在这里插入图片描述
  • 这样的配置普通数据接口调用没问题,传输图片报错,经排查:改成红框1的配置
    在这里插入图片描述
  • 还需要添加这两个类
    在这里插入图片描述
  • FeignSpringFormEncoder
    package com.kingdom.kdum.event.config.feign.decode;
    
     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.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;
     
     /**
      * A custom {@link Encoder} that supports Multipart requests. It uses
      * {@link HttpMessageConverter}s like {@link RestTemplate} does.
      *
      * @author Pierantonio Cangianiello
      */
     public class FeignSpringFormEncoder implements Encoder {
     
     
         private final List<HttpMessageConverter<?>> converters = new RestTemplate().getMessageConverters();
     
         public static final Charset UTF_8 = Charset.forName("UTF-8");
     
         public FeignSpringFormEncoder() {
         }
     
         /**
          * {@inheritDoc }
          */
         @Override
         public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
             if (isFormRequest(bodyType)) {
                 final HttpHeaders multipartHeaders = new HttpHeaders();
                 multipartHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
                 encodeMultipartFormRequest((Map<String, ?>) object, multipartHeaders, template);
             } else {
                 final HttpHeaders jsonHeaders = new HttpHeaders();
                 jsonHeaders.setContentType(MediaType.APPLICATION_JSON);
                 encodeRequest(object, jsonHeaders, template);
             }
         }
     
         /**
          * Encodes the request as a multipart form. It can detect a single {@link MultipartFile}, an
          * array of {@link MultipartFile}s, or POJOs (that are converted to JSON).
          *
          * @param formMap
          * @param template
          * @throws EncodeException
          */
         private void encodeMultipartFormRequest(Map<String, ?> formMap, HttpHeaders multipartHeaders, RequestTemplate template) throws EncodeException {
             if (formMap == null) {
                 throw new EncodeException("Cannot encode request with null form.");
             }
             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());
         }
     
         /**
          * Wraps a single {@link MultipartFile} into a {@link HttpEntity} and sets the
          * {@code Content-type} header to {@code application/octet-stream}
          *
          * @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);
             }
         }
     
         /**
          * Fills the request map with {@link HttpEntity}s containing the given {@link MultipartFile}s.
          * Sets the {@code Content-type} header to {@code application/octet-stream} for each file.
          *
          * @param map current request map.
          * @param name the name of the array field in the multipart form.
          * @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);
             }
         }
     
         /**
          * Wraps an object into a {@link HttpEntity} and sets the {@code Content-type} header to
          * {@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);
         }
     
         /**
          * Calls the conversion chain actually used by
          * {@link RestTemplate}, filling the body of the request
          * template.
          *
          * @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());
                 }
             }
             /*
             we should use a template output stream... this will cause issues if files are too big, 
             since the whole request will be in memory.
              */
             template.body(outputStream.toByteArray(), UTF_8);
         }
     
         /**
          * Minimal implementation of {@link HttpOutputMessage}. It's needed to
          * provide the request body output stream to
          * {@link HttpMessageConverter}s
          */
         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;
             }
     
         }
     
         /**
          * Heuristic check for multipart requests.
          *
          * @param type
          * @return
          * @see feign.Types
          */
         static boolean isFormRequest(Type type) {
             return MAP_STRING_WILDCARD.equals(type);
         }
     
         /**
          * Dummy resource class. Wraps file content and its original name.
          */
         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;
             }
     
         }
     
     }
    
    
  • ListDecoder
    package com.kingdom.kdum.event.config.feign.decode;
    
      import com.fasterxml.jackson.core.type.TypeReference;
      import com.fasterxml.jackson.databind.DeserializationFeature;
      import com.fasterxml.jackson.databind.Module;
      import com.fasterxml.jackson.databind.ObjectMapper;
      import com.fasterxml.jackson.databind.RuntimeJsonMappingException;
      import feign.Response;
      import feign.Util;
      import feign.codec.Decoder;
      
      import java.io.BufferedReader;
      import java.io.IOException;
      import java.io.Reader;
      import java.lang.reflect.Type;
      import java.util.Collections;
      import java.util.List;
      
      public class ListDecoder implements Decoder {
      
          private final ObjectMapper mapper;
      
          public ListDecoder() {
              this(Collections.<Module>emptyList());
          }
      
          public ListDecoder(Iterable<Module> modules) {
              this(new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                      .registerModules(modules));
          }
      
          public ListDecoder(ObjectMapper mapper) {
              this.mapper = mapper;
          }
      
          @Override
          public Object decode(Response response, Type type) throws IOException {
              if (response.status() == 404) return Util.emptyValueOf(type);
              if (response.body() == null) return null;
              Reader reader = response.body().asReader();
              if (!reader.markSupported()) {
                  reader = new BufferedReader(reader, 1);
              }
              try {
                  reader.mark(1);
                  if (reader.read() == -1) {
                      return null;
                  }
                  reader.reset();
                  return mapper.readValue(reader, new TypeReference<List>(){});
              } catch (RuntimeJsonMappingException e) {
                  if (e.getCause() != null && e.getCause() instanceof IOException) {
                      throw IOException.class.cast(e.getCause());
                  }
                  throw e;
              }
          }
      }
    
    
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王子様~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值