带有 JSON 的 Spring MVC 多部分请求
Posted
技术标签:
【中文标题】带有 JSON 的 Spring MVC 多部分请求【英文标题】:Spring MVC Multipart Request with JSON 【发布时间】:2014-02-15 06:08:00 【问题描述】:我想使用 Spring MVC 发布一个包含一些 JSON 数据的文件。所以我开发了一个休息服务作为
@RequestMapping(value = "/servicegenerator/wsdl", method = RequestMethod.POST,consumes = "multipart/mixed", "multipart/form-data" )
@ResponseBody
public String generateWSDLService(@RequestPart("meta-data") WSDLInfo wsdlInfo,@RequestPart("file") MultipartFile file) throws WSDLException, IOException,
JAXBException, ParserConfigurationException, SAXException, TransformerException
return handleWSDL(wsdlInfo,file);
当我从其余客户端发送请求时
content-Type = multipart/form-data or multipart/mixed
,我得到下一个异常:
org.springframework.web.multipart.support.MissingServletRequestPartException
谁能帮我解决这个问题?
我可以使用@RequestPart
将 Multipart 和 JSON 发送到服务器吗?
【问题讨论】:
您是否在 servlet 上下文中指定了org.springframework.web.multipart.commons.CommonsMultipartResolver
?
是的,它已添加到我的 spring.xml 中。 对于 Angular2+ 用户。尝试在混合部分请求中发送 JSON 有效负载,如下所示。
formData.append("jsonPayload", new Blob([JSON.stringify(json)],
type: "application/json"
));
给出以下完整功能。
submit()
const formData = new FormData();
formData.append('file', this.myForm.get('fileSource').value);
var json =
"key":"value"
;
formData.append("jsonPayload", new Blob([JSON.stringify(json)],
type: "application/json"
));
this.http.post('http://localhost:8080/api/mixed-part-endpoint', formData)
.subscribe(res =>
console.log(res);
alert('Uploaded Successfully.');
)
【讨论】:
【参考方案2】:我们在我们的项目中看到,带有 JSON 和文件的发布请求在前端和后端开发人员之间造成了很多混乱,从而导致不必要的时间浪费。
这里有一个更好的方法:将文件字节数组转换为 Base64 字符串并以 JSON 格式发送。
public Class UserDTO
private String firstName;
private String lastName;
private FileDTO profilePic;
public class FileDTO
private String base64;
// just base64 string is enough. If you want, send additional details
private String name;
private String type;
private String lastModified;
@PostMapping("/user")
public String saveUser(@RequestBody UserDTO user)
byte[] fileBytes = Base64Utils.decodeFromString(user.getProfilePic().getBase64());
....
将文件转换为base64字符串的JS代码:
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function ()
const userDTO =
firstName: "John",
lastName: "Wick",
profilePic:
base64: reader.result,
name: file.name,
lastModified: file.lastModified,
type: file.type
// post userDTO
;
reader.onerror = function (error)
console.log('Error: ', error);
;
【讨论】:
【参考方案3】:这就是我使用 JSON 数据实现 Spring MVC 多部分请求的方式。
带有 JSON 数据的多部分请求(也称为混合多部分):
基于 Spring 4.0.2 Release 中的 RESTful 服务,可以通过 @RequestPart 实现 HTTP 请求的第一部分为 XML 或 JSON 格式的数据,第二部分为文件。下面是示例实现。
Java 代码段:
Controller 中的 Rest 服务将混合使用 @RequestPart 和 MultipartFile 来服务此类 Multipart + JSON 请求。
@RequestMapping(value = "/executesampleservice", method = RequestMethod.POST,
consumes = "multipart/form-data")
@ResponseBody
public boolean executeSampleService(
@RequestPart("properties") @Valid ConnectionProperties properties,
@RequestPart("file") @Valid @NotNull @NotBlank MultipartFile file)
return projectService.executeSampleService(properties, file);
前端 (javascript) 代码段:
创建一个 FormData 对象。
使用以下步骤之一将文件附加到 FormData 对象。
-
如果文件已使用“文件”类型的输入元素上传,则将其附加到 FormData 对象。
formData.append("file", document.forms[formName].file.files[0]);
直接将文件附加到 FormData 对象。
formData.append("file", myFile, "myfile.txt");
或 formData.append("file", myBob, "myfile.txt");
使用字符串化的 JSON 数据创建一个 blob,并将其附加到 FormData 对象。这会导致多部分请求中第二部分的 Content-type 为“application/json”,而不是文件类型。
向服务器发送请求。
请求详情:Content-Type: undefined
。这会导致浏览器将 Content-Type 设置为 multipart/form-data 并正确填充边界。手动将 Content-Type 设置为 multipart/form-data 将无法填写请求的边界参数。
Javascript 代码:
formData = new FormData();
formData.append("file", document.forms[formName].file.files[0]);
formData.append('properties', new Blob([JSON.stringify(
"name": "root",
"password": "root"
)],
type: "application/json"
));
请求详情:
method: "POST",
headers:
"Content-Type": undefined
,
data: formData
请求负载:
Accept:application/json, text/plain, */*
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryEBoJzS3HQ4PgE1QB
------WebKitFormBoundaryvijcWI2ZrZQ8xEBN
Content-Disposition: form-data; name="file"; filename="myfile.txt"
Content-Type: application/txt
------WebKitFormBoundaryvijcWI2ZrZQ8xEBN
Content-Disposition: form-data; name="properties"; filename="blob"
Content-Type: application/json
------WebKitFormBoundaryvijcWI2ZrZQ8xEBN--
【讨论】:
做得很好。我不得不使用processData: false, contentType: false
和JQuery $ajax()
@SunilKumar,如果我需要将文件上传作为可选的..?使用表单数据。我该怎么做。因为如果没有选择图像,我会得到Required request part file is not present
对我来说,"new Blob([JSON.stringify(...)]" 部分做到了。我已经准备好了其他一切。谢谢。
@SunilKumar 您是否必须为 ConnectionProperties 指定转换器?如果我对 ConnectionProperties 使用如上所示的 pojo,我会得到...所以不清楚到 POJO 的转换是如何发生的?
只是为了说明这一点:MultipartFile 方法参数上的@NotBlank
注释实际上不会检查文件是否为空。仍然可以上传 0 字节的文档。【参考方案4】:
这一定行得通!
客户端(角度):
$scope.saveForm = function ()
var formData = new FormData();
var file = $scope.myFile;
var json = $scope.myJson;
formData.append("file", file);
formData.append("ad",JSON.stringify(json));//important: convert to JSON!
var req =
url: '/upload',
method: 'POST',
headers: 'Content-Type': undefined,
data: formData,
transformRequest: function (data, headersGetterFunction)
return data;
;
后端-Spring Boot:
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody
Advertisement storeAd(@RequestPart("ad") String adString, @RequestPart("file") MultipartFile file) throws IOException
Advertisement jsonAd = new ObjectMapper().readValue(adString, Advertisement.class);
//do whatever you want with your file and jsonAd
【讨论】:
【参考方案5】:如文档所述:
当“multipart/form-data”请求的一部分由 找不到它的名字。
这可能是因为请求也不是 multipart/form-data 因为请求中不存在该部件,或者因为网络 应用程序未正确配置以处理多部分 请求——例如没有 MultipartResolver。
【讨论】:
以上是关于带有 JSON 的 Spring MVC 多部分请求的主要内容,如果未能解决你的问题,请参考以下文章
使用 Spring MVC Test 对多部分 POST 请求进行单元测试
带有多部分请求的 Spring Boot 不受支持的媒体类型
Spring Boot REST 多部分请求(文件 + json)抛出 415 Unsupported Media Type 异常