|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
多部分(Multipart)
在启用了 MultipartResolver 之后,xref page 类型的 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 Validation 验证。
默认情况下,验证错误会抛出 MethodArgumentNotValidException 异常,该异常会被转换为 400(BAD_REQUEST)响应。或者,你也可以通过在控制器方法中添加 Errors 或 BindingResult 参数来本地处理验证错误,如下例所示:
-
Java
-
Kotlin
@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") MetaData metadata,
BindingResult result) {
// ...
}
@PostMapping("/")
fun handle(@Valid @RequestPart("meta-data") metadata: MetaData,
result: BindingResult): String {
// ...
}