マルチパート

MultipartResolver が有効になると、multipart/form-data による POST リクエストの内容が解析され、通常のリクエストパラメーターとしてアクセスできるようになります。次の例では、1 つの通常のフォームフィールドと 1 つのアップロードされたファイルにアクセスします。

  • 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> として宣言され、アノテーションにパラメーター名が指定されていない場合、指定された各パラメーター名のマルチパートファイルがマップに入力されます。

サーブレットのマルチパート解析では、メソッド引数またはコレクション値型として、Spring の MultipartFile の代わりに jakarta.servlet.http.Part を宣言することもできます。

コマンドオブジェクトへのデータバインディングの一部としてマルチパートコンテンツを使用することもできます。例: 次の例に示すように、前の例のフォームフィールドとファイルは、フォームオブジェクトのフィールドである可能性があります。

  • 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 と同様)。HttpMessageConverter で変換した後、@RequestPart アノテーションを使用してマルチパートにアクセスします。

  • 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 が発生します。詳細については、検証のセクションを参照してください。