spring cloud feign 多文件上传实现
2017-12-28 00:00
609 查看
单文件上传网上有很多教程 多文件以及多文件附带其他参数 的教程 几乎没有 经过研究和参考其他文章 详细的原理不再讲解 实现过程如下:
加入feign 支持上传的组件:
实现 org.springframework.http.HttpOutputMessage
改写 org.springframework.core.io.InputStreamResource
实现mutipart的专属编码器 对逻辑进行了重新改动 参考了其他教程
加入配置:
feignclient 使用配置:
多图片 方法:
加入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);
相关文章推荐
- Spring Cloud Feign Client 实现MultipartFile上传文件功能
- Spring Cloud Feign的文件上传实现的示例代码
- Spring Cloud Feign Client 实现MultipartFile上传文件功能
- Spring Cloud中FeignClient添加上传文件功能
- spring cloud feign 上传文件报not a type supported by this encoder解决方案
- spring cloud feign实现远程调用服务传输文件的方法
- Spring Cloud Feign(1.5.9) 进行文件上传
- spring cloud feign 上传文件
- 使用Spring Cloud Feign上传文件的示例
- Spring Cloud中FeignClient支持上传文件的同时提交表单数据
- 使用Spring Cloud Feign上传文件
- spring cloud之利用zuul实现文件上传(十)
- spring mvc +uploadify2.1 实现文件上传
- FTP+SpringMVC+Uploadify实现带进度条多文件上传
- Spring实现文件上传
- Spring-MVC框架实现文件的上传、修改、下载
- spring实现文件上传
- springMVC+uploadify实现文件异步上传
- Spring中实现文件上传
- spring+jpg环境下,spring实现文件上传