Multipart
在 启用 MultipartResolver
后,带有 multipart/form-data
的 POST 请求内容将被解析并作为常规请求参数访问。以下示例访问了一个常规表单字段和一个上传文件
-
Java
-
Kotlin
@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";
}
}
@Controller
class FileUploadController {
@PostMapping("/form")
fun handleFormUpload(@RequestParam("name") name: String,
@RequestParam("file") file: MultipartFile): String {
if (!file.isEmpty) {
val bytes = file.bytes
// store the bytes somewhere
return "redirect:uploadSuccess"
}
return "redirect:uploadFailure"
}
}
将参数类型声明为 List<MultipartFile>
允许解析同一参数名的多个文件。
当 @RequestParam
注解被声明为 Map<String, MultipartFile>
或 MultiValueMap<String, MultipartFile>
,且注解中未指定参数名时,该 Map 将填充每个给定参数名的 multipart 文件。
使用 Servlet 的 multipart 解析时,您也可以声明 jakarta.servlet.http.Part 而非 Spring 的 MultipartFile ,作为方法参数或集合值类型。 |
您还可以将 multipart 内容作为数据绑定的一部分绑定到命令对象。例如,前面示例中的表单字段和文件可以是表单对象上的字段,如下例所示
-
Java
-
Kotlin
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";
}
}
class MyForm(val name: String, val file: MultipartFile, ...)
@Controller
class FileUploadController {
@PostMapping("/form")
fun handleFormUpload(form: MyForm, errors: BindingResult): String {
if (!form.file.isEmpty) {
val bytes = form.file.bytes
// store the bytes somewhere
return "redirect:uploadSuccess"
}
return "redirect:uploadFailure"
}
}
在 RESTful 服务场景中,multipart 请求也可以由非浏览器客户端提交。以下示例展示了一个包含 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
作为 String
访问“元数据”部分,但您可能希望它从 JSON 反序列化(类似于 @RequestBody
)。使用 @RequestPart
注解在通过 HttpMessageConverter
转换后访问 multipart
-
Java
-
Kotlin
@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata,
@RequestPart("file-data") MultipartFile file) {
// ...
}
@PostMapping("/")
fun handle(@RequestPart("meta-data") metadata: MetaData,
@RequestPart("file-data") file: MultipartFile): String {
// ...
}
您可以将 @RequestPart
与 jakarta.validation.Valid
结合使用,或使用 Spring 的 @Validated
注解,这两者都会导致应用标准 Bean 校验。默认情况下,校验错误会引发 MethodArgumentNotValidException
,该异常会被转换为 400 (BAD_REQUEST) 响应。另外,您也可以在控制器内部通过 Errors
或 BindingResult
参数本地处理校验错误,如下例所示
-
Java
-
Kotlin
@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") MetaData metadata, Errors errors) {
// ...
}
@PostMapping("/")
fun handle(@Valid @RequestPart("meta-data") metadata: MetaData, errors: Errors): String {
// ...
}
如果因为其他参数带有 @Constraint
注解而应用了方法校验,则会引发 HandlerMethodValidationException
。更多详情,请参阅校验章节。