Spring Boot 控制器 - 将 Multipart 和 JSON 上传到 DTO

新手上路,请多包涵

我想将表单内的文件上传到 Spring Boot API 端点。

UI 是用 React 编写的:

 export function createExpense(formData) {
  return dispatch => {
    axios.post(ENDPOINT,
      formData,
      headers: {
        'Authorization': //...,
        'Content-Type': 'application/json'
      }
      ).then(({data}) => {
        //...
      })
      .catch(({response}) => {
        //...
      });
    };
}

  _onSubmit = values => {
    let formData = new FormData();
    formData.append('title', values.title);
    formData.append('description', values.description);
    formData.append('amount', values.amount);
    formData.append('image', values.image[0]);
    this.props.createExpense(formData);
  }

这是java端代码:

 @RequestMapping(path = "/{groupId}", method = RequestMethod.POST)
public ExpenseSnippetGetDto create(@RequestBody ExpensePostDto expenseDto, @PathVariable long groupId, Principal principal, BindingResult result) throws IOException {
   //..
}

但是我在 Java 端得到了这个异常:

 org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form-data;boundary=----WebKitFormBoundaryapHVvBsdZYc6j4Af;charset=UTF-8' not supported

我应该如何解决这个问题?类似的 API 端点和 JavaScript 端代码已经在运行。

笔记

我见过一个解决方案,它建议请求正文应该有 2 个属性:一个是 JSON 部分,另一个是图像。我想看看是否可以将它自动转换为 DTO。


更新 1

客户端发送的上传负载应该转换为以下DTO:

 public class ExpensePostDto extends ExpenseBaseDto {

    private MultipartFile image;

    private String description;

    private List<Long> sharers;

}

所以你可以说它是 JSON 和 multipart 的混合体。


解决方案

该问题的解决方案是在前端使用 FormData ModelAttribute 在后端使用—:

 @RequestMapping(path = "/{groupId}", method = RequestMethod.POST,
        consumes = {"multipart/form-data"})
public ExpenseSnippetGetDto create(@ModelAttribute ExpensePostDto expenseDto, @PathVariable long groupId, Principal principal) throws IOException {
   //...
}

在前端,摆脱 Content-Type 因为它应该由浏览器本身决定,并使用 FormData (标准 JavaScript)。那应该可以解决问题。

原文由 Arian 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.3k
2 个回答

是的,您可以简单地通过包装类来完成。

1)创建一个 Class 来保存表单数据:

 public class FormWrapper {
    private MultipartFile image;
    private String title;
    private String description;
}

  1. 创建一个 HTML form 用于提交数据:
 <form method="POST" enctype="multipart/form-data" id="fileUploadForm" action="link">
    <input type="text" name="title"/><br/>
    <input type="text" name="description"/><br/><br/>
    <input type="file" name="image"/><br/><br/>
    <input type="submit" value="Submit" id="btnSubmit"/>
</form>

3)创建一个方法来接收表单的 text 数据和 multipart 文件:

 @PostMapping("/api/upload/multi/model")
public ResponseEntity<?> multiUploadFileModel(@ModelAttribute FormWrapper model) {
    try {
        // Save as you want as per requiremens
        saveUploadedFile(model.getImage());
        formRepo.save(mode.getTitle(), model.getDescription());
    } catch (IOException e) {
        return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
    }

    return new ResponseEntity("Successfully uploaded!", HttpStatus.OK);
}

4)保存方法 file

 private void saveUploadedFile(MultipartFile file) throws IOException {
    if (!file.isEmpty()) {
        byte[] bytes = file.getBytes();
        Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
        Files.write(path, bytes);
    }
}

原文由 UsamaAmjad 发布,翻译遵循 CC BY-SA 4.0 许可协议

我使用纯 JS 和 Spring Boot 创建了一个类似的东西。这是 回购协议。 我要发送一个 User File multipart/form-data JSON

相关片段如下

Controller 代码

@RestController
public class FileUploadController {

    @RequestMapping(value = "/upload", method = RequestMethod.POST, consumes = { "multipart/form-data" })
    public void upload(@RequestPart("user") @Valid User user,
            @RequestPart("file") @Valid @NotNull @NotBlank MultipartFile file) {
            System.out.println(user);
            System.out.println("Uploaded File: ");
            System.out.println("Name : " + file.getName());
            System.out.println("Type : " + file.getContentType());
            System.out.println("Name : " + file.getOriginalFilename());
            System.out.println("Size : " + file.getSize());
    }

    static class User {
        @NotNull
        String firstName;
        @NotNull
        String lastName;

        public String getFirstName() {
            return firstName;
        }

        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }

        public String getLastName() {
            return lastName;
        }

        public void setLastName(String lastName) {
            this.lastName = lastName;
        }

        @Override
        public String toString() {
            return "User [firstName=" + firstName + ", lastName=" + lastName + "]";
        }

    }
}

HTMLJS 代码

<html>
<head>
    <script>
        function onSubmit() {

            var formData = new FormData();

            formData.append("file", document.forms["userForm"].file.files[0]);
            formData.append('user', new Blob([JSON.stringify({
                "firstName": document.getElementById("firstName").value,
                "lastName": document.getElementById("lastName").value
            })], {
                    type: "application/json"
                }));
            var boundary = Math.random().toString().substr(2);
            fetch('/upload', {
                method: 'post',
                body: formData
            }).then(function (response) {
                if (response.status !== 200) {
                    alert("There was an error!");
                } else {
                    alert("Request successful");
                }
            }).catch(function (err) {
                alert("There was an error!");
            });;
        }
    </script>
</head>

<body>
    <form name="userForm">
        <label> File : </label>
        <br/>
        <input name="file" type="file">
        <br/>
        <label> First Name : </label>
        <br/>
        <input id="firstName" name="firstName" />
        <br/>
        <label> Last Name : </label>
        <br/>
        <input id="lastName" name="lastName" />
        <br/>
        <input type="button" value="Submit" id="submit" onclick="onSubmit(); return false;" />
    </form>
</body>
</html>

原文由 GSSwain 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题