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);