Spring 引导:post 并处理 multipart/form-data 具有多个正文部分的请求
Spring Boot: post and process multipart/form-data request with multiple body parts
我有以下处理 multipart/form-data 请求的端点:
@RequestMapping(value = "/test", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Response> handleRequest(
@RequestPart(value = "image") MultipartFile image,
@RequestPart(value = "data") Request request, HttpServletRequest request) throws IOException {
}
当我使用 IDEA rest 客户端对其进行测试时,端点已按预期到达:
POST http://myUrl/test
Accept: */*
Cache-Control: no-cache
Content-Type: multipart/form-data; boundary=xxxx
Authorization: Basic username pass
--xxxx
Content-Disposition: form-data; name="image"; filename="image.jpg"
Content-Type: image/jpg
< C:\pathToImage\image.jpg
--xxxx
Content-Disposition: form-data; name="data"
Content-Type: application/json
{
"firstName":"John",
"lastName":"Doe"
}
--xxxx
但是当我尝试通过 Spring RestTemplate 到达此端点时,我观察到 400 响应和以下错误:
Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'image' is not present]
.
我用于 post 请求的代码如下:
public Response test(final byte[] image, MediaType imageMimeType, final Request request) {
String url = "http://myUrl/test";
HttpHeaders headers = HeaderUtils.headerBasicAuth("username", "pass");
headers.set(HttpHeaders.ACCEPT,MediaType.APPLICATION_JSON_VALUE);
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("image", new InputStreamResource(new ByteArrayInputStream(image)));
map.add("data", request.toJson());
HttpEntity<?> requestEntity = new HttpEntity<>(map, headers);
ResponseEntity<Response> result = template.exchange(url, HttpMethod.POST, requestEntity, Response.class);
return result.getBody();
}
请求class的大致代码如下:
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.joda.JodaModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.io.Serializable;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.json.JSONObject;
@AllArgsConstructor(access = AccessLevel.PUBLIC)
@Getter
@JsonInclude(Include.NON_NULL)
public final class VerifyRequest implements Cloneable, Serializable {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final String firstName;
private final String lastName;
public JSONObject toJson() {
String json;
try {
json = OBJECT_MAPPER.writeValueAsString(this);
} catch (JsonProcessingException var3) {
throw new IllegalStateException(var3);
}
return new JSONObject(json);
}
....
}
有什么建议我怎么会post这样的要求?
您收到该错误是因为您没有在图像字段的 MultiValueMap 中使用有效对象。通常你会使用 FileSystemResource 从磁盘加载图像,有很多这样的例子。
但是,如果您仍然想从字节数组中获取它,您可以使用 ByteArrayResource 覆盖 getFilename(),这在控制器端是必需的。所以代替:
map.add("image", new InputStreamResource(new ByteArrayInputStream(image)));
只需输入:
ByteArrayResource byteArrayResource = new ByteArrayResource(image) {
@Override
public String getFilename() {
return "image.jpg";
}
};
map.add("image", byteArrayResource);
我有以下处理 multipart/form-data 请求的端点:
@RequestMapping(value = "/test", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Response> handleRequest(
@RequestPart(value = "image") MultipartFile image,
@RequestPart(value = "data") Request request, HttpServletRequest request) throws IOException {
}
当我使用 IDEA rest 客户端对其进行测试时,端点已按预期到达:
POST http://myUrl/test
Accept: */*
Cache-Control: no-cache
Content-Type: multipart/form-data; boundary=xxxx
Authorization: Basic username pass
--xxxx
Content-Disposition: form-data; name="image"; filename="image.jpg"
Content-Type: image/jpg
< C:\pathToImage\image.jpg
--xxxx
Content-Disposition: form-data; name="data"
Content-Type: application/json
{
"firstName":"John",
"lastName":"Doe"
}
--xxxx
但是当我尝试通过 Spring RestTemplate 到达此端点时,我观察到 400 响应和以下错误:
Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'image' is not present]
.
我用于 post 请求的代码如下:
public Response test(final byte[] image, MediaType imageMimeType, final Request request) {
String url = "http://myUrl/test";
HttpHeaders headers = HeaderUtils.headerBasicAuth("username", "pass");
headers.set(HttpHeaders.ACCEPT,MediaType.APPLICATION_JSON_VALUE);
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("image", new InputStreamResource(new ByteArrayInputStream(image)));
map.add("data", request.toJson());
HttpEntity<?> requestEntity = new HttpEntity<>(map, headers);
ResponseEntity<Response> result = template.exchange(url, HttpMethod.POST, requestEntity, Response.class);
return result.getBody();
}
请求class的大致代码如下:
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.joda.JodaModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.IOException;
import java.io.Serializable;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.json.JSONObject;
@AllArgsConstructor(access = AccessLevel.PUBLIC)
@Getter
@JsonInclude(Include.NON_NULL)
public final class VerifyRequest implements Cloneable, Serializable {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final String firstName;
private final String lastName;
public JSONObject toJson() {
String json;
try {
json = OBJECT_MAPPER.writeValueAsString(this);
} catch (JsonProcessingException var3) {
throw new IllegalStateException(var3);
}
return new JSONObject(json);
}
....
}
有什么建议我怎么会post这样的要求?
您收到该错误是因为您没有在图像字段的 MultiValueMap 中使用有效对象。通常你会使用 FileSystemResource 从磁盘加载图像,有很多这样的例子。
但是,如果您仍然想从字节数组中获取它,您可以使用 ByteArrayResource 覆盖 getFilename(),这在控制器端是必需的。所以代替:
map.add("image", new InputStreamResource(new ByteArrayInputStream(image)));
只需输入:
ByteArrayResource byteArrayResource = new ByteArrayResource(image) {
@Override
public String getFilename() {
return "image.jpg";
}
};
map.add("image", byteArrayResource);