在 启用 MultipartResolver 后,带有 multipart/form-data
的 POST 请求的内容被解析并作为常规请求参数访问。下面的例子访问了一个普通的表单字段和一个上传的文件:
@Controller
public class FileUploadController {
@PostMapping("/form")
public String handleFormUpload(@RequestParam("name") String name,
@RequestParam("file") MultipartFile file) {
if (!file.isEmpty()) {
byte[] bytes = file.getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}
将参数类型声明为 List<MultipartFile>
允许为同一参数名解析多个文件。
当 @RequestParam
注解被声明为 Map<String, MultipartFile>
或 MultiValueMap<String, MultipartFile>
时,如果没有在注解中指定参数名称,那么该 map 将被填充为每个给定参数名称的多部件文件。
:::info
通过 Servlet 3.0 的多部件解析,你也可以声明 javax.servlet.http.Part
而不是 Spring 的 MultipartFile,作为方法参数或集合值类型。
:::
你也可以使用多部件内容作为数据绑定到 命令对象 的一部分。例如,前面的例子中的表单字段和文件可以是表单对象上的字段,如下例所示:
class MyForm {
private String name;
private MultipartFile file;
// ...
}
@Controller
public class FileUploadController {
@PostMapping("/form")
public String handleFormUpload(MyForm form, BindingResult errors) {
if (!form.getFile().isEmpty()) {
byte[] bytes = form.getFile().getBytes();
// store the bytes somewhere
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}
在 RESTful 服务场景中,多部件请求也可以从非浏览器客户端提交。下面的例子显示了一个带有 JSON 的文件:
POST /someUrl
Content-Type: multipart/mixed
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="meta-data"
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: 8bit
{
"name": "value"
}
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="file-data"; filename="file.properties"
Content-Type: text/xml
Content-Transfer-Encoding: 8bit
... File Data ...
你可以用 @RequestParam
作为一个字符串来访问 「meta-data」部分,但你可能希望它从 JSON 中反序列化(与 @RequestBody
类似)。使用@RequestPart
注解,在用 HttpMessageConverter 进行转换后访问一个多部件。
@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata,
@RequestPart("file-data") MultipartFile file) {
// ...
}
这里关于前端页面如何构造这个请求,可以参考笔者的另外一篇笔记
文件下载、上传、混合 JSON 提交
你可以将 @RequestPart
与 javax.validation.Valid
结合起来使用,或者使用 Spring 的 @Validated
注解,这两种方法都会导致标准 bean 验证被应用。默认情况下,验证错误会导致 MethodArgumentNotValidException,它被转化为 400(BAD_REQUEST)响应。另外,你可以通过 Errors 或 BindingResult 参数在控制器中本地处理验证错误,如下面的例子所示:
@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
BindingResult result) {
// ...
}