com.github.qq275860560.common.encoder.MultipartFormDataEncoder Maven / Gradle / Ivy
package com.github.qq275860560.common.encoder;
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;
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 feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
/**
* @author [email protected]
*/
public class MultipartFormDataEncoder 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 MultipartFormDataEncoder() {
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((Map) 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 formMap
* @param template
* @throws EncodeException
*/
private void encodeMultipartFormRequest(Map formMap, RequestTemplate template) throws EncodeException {
if (formMap == null) {
throw new EncodeException("Cannot encode request with null form.");
}
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());
}
/**
* 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 the
* current request map.
* @param name
* the name of the array field in the multipart form.
* @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);
}
}
/**
* 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
© 2015 - 2024 Weber Informatics LLC | Privacy Policy