启用 MultipartResolver 后,带有 multipart/form-data的 POST 请求的内容被解析并作为常规请求参数访问。下面的例子访问了一个普通的表单字段和一个上传的文件:

    1. @Controller
    2. public class FileUploadController {
    3. @PostMapping("/form")
    4. public String handleFormUpload(@RequestParam("name") String name,
    5. @RequestParam("file") MultipartFile file) {
    6. if (!file.isEmpty()) {
    7. byte[] bytes = file.getBytes();
    8. // store the bytes somewhere
    9. return "redirect:uploadSuccess";
    10. }
    11. return "redirect:uploadFailure";
    12. }
    13. }

    将参数类型声明为 List<MultipartFile>允许为同一参数名解析多个文件。

    @RequestParam注解被声明为 Map<String, MultipartFile>MultiValueMap<String, MultipartFile>时,如果没有在注解中指定参数名称,那么该 map 将被填充为每个给定参数名称的多部件文件。

    :::info 通过 Servlet 3.0 的多部件解析,你也可以声明 javax.servlet.http.Part 而不是 Spring 的 MultipartFile,作为方法参数或集合值类型。 :::

    你也可以使用多部件内容作为数据绑定到 命令对象 的一部分。例如,前面的例子中的表单字段和文件可以是表单对象上的字段,如下例所示:

    1. class MyForm {
    2. private String name;
    3. private MultipartFile file;
    4. // ...
    5. }
    6. @Controller
    7. public class FileUploadController {
    8. @PostMapping("/form")
    9. public String handleFormUpload(MyForm form, BindingResult errors) {
    10. if (!form.getFile().isEmpty()) {
    11. byte[] bytes = form.getFile().getBytes();
    12. // store the bytes somewhere
    13. return "redirect:uploadSuccess";
    14. }
    15. return "redirect:uploadFailure";
    16. }
    17. }

    在 RESTful 服务场景中,多部件请求也可以从非浏览器客户端提交。下面的例子显示了一个带有 JSON 的文件:

    1. POST /someUrl
    2. Content-Type: multipart/mixed
    3. --edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
    4. Content-Disposition: form-data; name="meta-data"
    5. Content-Type: application/json; charset=UTF-8
    6. Content-Transfer-Encoding: 8bit
    7. {
    8. "name": "value"
    9. }
    10. --edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
    11. Content-Disposition: form-data; name="file-data"; filename="file.properties"
    12. Content-Type: text/xml
    13. Content-Transfer-Encoding: 8bit
    14. ... File Data ...

    你可以用 @RequestParam作为一个字符串来访问 「meta-data」部分,但你可能希望它从 JSON 中反序列化(与 @RequestBody类似)。使用@RequestPart注解,在用 HttpMessageConverter 进行转换后访问一个多部件。

    1. @PostMapping("/")
    2. public String handle(@RequestPart("meta-data") MetaData metadata,
    3. @RequestPart("file-data") MultipartFile file) {
    4. // ...
    5. }

    这里关于前端页面如何构造这个请求,可以参考笔者的另外一篇笔记
    文件下载、上传、混合 JSON 提交

    你可以将 @RequestPartjavax.validation.Valid结合起来使用,或者使用 Spring 的 @Validated注解,这两种方法都会导致标准 bean 验证被应用。默认情况下,验证错误会导致 MethodArgumentNotValidException,它被转化为 400(BAD_REQUEST)响应。另外,你可以通过 Errors 或 BindingResult 参数在控制器中本地处理验证错误,如下面的例子所示:

    1. @PostMapping("/")
    2. public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
    3. BindingResult result) {
    4. // ...
    5. }