多部分
在 啟用 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 將填充每個給定引數名稱的多部分檔案。
使用 Servlet 多部分解析時,您還可以將 jakarta.servlet.http.Part 宣告為方法引數或集合值型別,而不是 Spring 的 MultipartFile。 |
您還可以將多部分內容作為資料繫結的一部分,繫結到命令物件。例如,上一個示例中的表單欄位和檔案可以是表單物件上的欄位,如下例所示:
-
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 服務場景中,非瀏覽器客戶端也可以提交多部分請求。以下示例展示了一個包含 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 轉換後訪問多部分:
-
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。有關更多詳細資訊,請參閱 驗證 部分。