Feign 마이크로서비스 간 파일 전송

10091 단어 코드 최적화
많은 경우에 우리는 마이크로 서비스 사이의 파일 전송을 만날 수 있고, 많은 경우에 우리는 서열화 등 방식으로 해결할 수 있다. (예를 들어 그림 등)
최근 프로젝트에 excel 업로드와 멀티미디어 파일 업로드가 있어서 직접 오류를 보고합니다.
두 가지 해결 방법도 시도해 보았지만 모두 실행할 수 없었다.
1. 파일 엔코더 해석기를 쓰면 다른rest 요청에 엔코더 오류가 발생합니다
2.springcloud feign은 하나의 규범이 있는데 두 개의 대상을 전송할 수 없고 한 대상이 몇 개의 매개 변수를 가지고 있을 수 있다.
그러면 전역 해상도를 설정하지 않고 Feign Builder를 통해 업로드 파일을 관리하는 방식이 필요합니다. 이런 방식도 관리하기에 비교적 편리합니다.
 

    com.netflix.feign
    feign-core
    8.17.0


    com.netflix.feign
    feign-jackson
    8.17.0


    com.netflix.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 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);

}

 
파일 엔코드
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> 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) object, template);
        } else {
            encodeRequest(object, jsonHeaders, template);
        }
    }


    private void encodeMultipartFormRequest(Map formMap, RequestTemplate template) throws EncodeException {
        if (CollectionUtils.isEmpty(formMap)) {
            throw new EncodeException(" .");
        }
        LinkedMultiValueMap map = new 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());
    }

    /**
     *  
     * @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 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) 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> 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> imPunishExcel(@Param("file") MultipartFile file, @Param("operatorId") Integer operatorId);

 
 
 

좋은 웹페이지 즐겨찾기