使用JSON的Spring MVC多部分请求

p3rjfoxz  于 2022-11-14  发布在  Spring
关注(0)|答案(6)|浏览(153)

我想使用SpringMVC发布一个包含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从rest客户机发送请求时,我得到下一个异常:org.springframework.web.multipart.support.MissingServletRequestPartException
有人能帮我解决这个问题吗?
我可以使用@RequestPart将Multipart和JSON都发送到服务器吗?

voase2hg

voase2hg1#

这就是我如何使用JSON数据实现SpringMVC多部分请求。

包含JSON数据的多部分请求(也称为混合多部分):

基于Spring 4.0.2版本的RESTful服务,通过@RequestPart可以实现第一部分为XML或JSON格式数据,第二部分为文件的HTTP请求,下面是示例实现。

Java程式码片段:

控制器中的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)代码段:

1.建立FormData对象。
1.使用以下步骤之一将文件追加到FormData对象。
1.如果已使用类型为“file”的输入元素上载文件,则将其附加到FormData对象。formData.append("file", document.forms[formName].file.files[0]);
1.直接将文件追加到FormData对象。formData.append("file", myFile, "myfile.txt"); OR formData.append("file", myBob, "myfile.txt");
1.使用字符串化的JSON数据创建blob并将其附加到FormData对象。这将导致多部分请求中第二部分的Content-type为“application/json”,而不是文件类型。
1.将请求发送到服务器。
1.请求详细信息:
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--
gj3fmq9x

gj3fmq9x2#

这一定行!
客户端(Angular ):

$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
ecbunoof

ecbunoof3#

我们在项目中看到,使用JSON和文件的post请求在前端和后端开发人员之间造成了很多混乱,导致了不必要的时间浪费。
下面是一个更好的方法:将file bytes数组转换为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);
};
chhkpiq4

chhkpiq44#

如文件所述:
在找不到“multipart/form-data”请求中由其名称标识的部分时引发。
这可能是因为请求不是multipart/form-data,因为请求中不存在该部件,或者Web应用程序未正确配置为处理多部件请求-例如,没有MultipartResolver。

bsxbgnwa

bsxbgnwa5#

对于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.');
  })
}
of1yzvn4

of1yzvn46#

您也可以使用下一种方法,将列表List<MultipartFile>@RequestPart("myObj")作为@RestController内的方法中的参数

@PostMapping()
    @ResponseStatus(HttpStatus.CREATED)
    public String create(@RequestPart("file") List<MultipartFile> files, @RequestPart("myObj") MyJsonDTOClass myObj) throws GeneralSecurityException, IOException {
        // your code

    }

而在axios方面则有一点react:

const jsonStr = JSON.stringify(myJsonObj);
            const blob = new Blob([jsonStr], {
                type: 'application/json'
            });

            let formData = new FormData();
            formData.append("myObj",blob );
            formData.append("file", this.state.fileForm); // check your control 
            let url = `your url`            
            let method = `post`
            let headers =
                {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json'
                };
            }

            axios({
                method,
                url,
                data: formData,
                headers
            }).then(res => {
                console.log(res);
                console.log(res.data);
            });

相关问题