您的位置:首页 > 编程语言 > Java开发

spring cloud feign 多文件上传实现

2017-12-28 00:00 609 查看
单文件上传网上有很多教程 多文件以及多文件附带其他参数 的教程 几乎没有 经过研究和参考其他文章 详细的原理不再讲解 实现过程如下:

加入feign 支持上传的组件:

<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>${feign.form.version}</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>${feign.form.version}</version>
</dependency>

实现 org.springframework.http.HttpOutputMessage

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpOutputMessage;

import java.io.OutputStream;

/**
* The type Http output message.
*
* @author dax.
* @version v1.0
* @since 2017 /12/27 11:21
*/
public class HttpOutputMessageImpl implements HttpOutputMessage {

private OutputStream body;
private HttpHeaders headers;

public HttpOutputMessageImpl(OutputStream body, HttpHeaders headers) {
this.body = body;
this.headers = headers;
}

@Override
public OutputStream getBody() {
return body;
}

@Override
public HttpHeaders getHeaders() {
return headers;
}

}

改写 org.springframework.core.io.InputStreamResource

import org.springframework.core.io.InputStreamResource;

import java.io.IOException;
import java.io.InputStream;

/**
* @author dax.
* @version v1.0
* @since 2017/12/27 11:15
*/

public class MultipartFileResource extends InputStreamResource {

private String filename;
private 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 {
//To change body of generated methods, choose Tools | Templates.
return super.getInputStream();
}

@Override
public long contentLength(){
return size;
}

}


实现mutipart的专属编码器 对逻辑进行了重新改动 参考了其他教程

import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
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.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
* The type Spring multipart encoder.
*
* @author dax.
* @version v1.0
* @since 2017 /12/26 14:16
*/
public class SpringMultipartEncoder implements Encoder {

private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private static final Class MULTIPART_ARRAY_CLAZZ = MultipartFile[].class;
private static final String FILES_KEY="multipartFiles";
private final List<HttpMessageConverter<?>> converters = new RestTemplate().getMessageConverters();
private final HttpHeaders multipartHeaders = new HttpHeaders();
private final HttpHeaders jsonHeaders = new HttpHeaders();

/**
* Instantiates a new Spring multipart encoder.
*/
public SpringMultipartEncoder() {
multipartHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
jsonHeaders.setContentType(MediaType.APPLICATION_JSON);
}

/**
* {@inheritDoc }
*/
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
if (isFormRequest(bodyType)) {

encodeMultipartFormRequest(object, template);
} else {
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 object
* @param template
* @throws EncodeException
*/
private void encodeMultipartFormRequest(Object object, RequestTemplate template) throws EncodeException {
if (object == null) {
throw new EncodeException("Cannot encode request with null form.");
}
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();

if (isMultipartFile(object)) {
MultipartFile multipartFile= (MultipartFile) object;

map.add(multipartFile.getName(), encodeMultipartFile(multipartFile));
} else if (isMultipartFileArray(object)) {
encodeMultipartFiles(map, FILES_KEY, Arrays.asList((MultipartFile[]) object));
} else {
map.add("", encodeJsonObject(object));
}

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 org.springframework.web.client.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 (Map.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(), DEFAULT_CHARSET);
}

/**
* Heuristic check for multipart requests.
*
* @param type the type
* @return boolean boolean
* @see feign.Types
*/
private static boolean isFormRequest(Type type) {

return MAP_STRING_WILDCARD.equals(type) || MULTIPART_ARRAY_CLAZZ.equals(type);
}

}


加入配置:

import feign.codec.Encoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
@Configuration
public class FeignMultipartSupportConfig {
/**
* Multipart form encoder encoder.
*
* @return the encoder
*/
@Bean
@Primary
@Scope("prototype")
public Encoder multipartFormEncoder() {
return new SpringMultipartEncoder();
}

/**
* Multipart logger level feign . logger . level.
*
* @return the feign . logger . level
*/
@Bean
public feign.Logger.Level multipartLoggerLevel() {
return feign.Logger.Level.FULL;
}

}


feignclient 使用配置:

@FeignClient(value = "UPLOAD-SERVICE", configuration = FeignMultipartSupportConfig.class)

多图片 方法:

@PostMapping(value = "/upload/feign/files", produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Rest multipartUpload(@RequestPart("multipartFiles") MultipartFile[] multipartFiles, @RequestParam("uploadPathEnums") UploadPathEnums uploadPathEnums);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: