Spring?Boot?處理帶文件表單的方式匯總
更新時間:2025年12月12日 11:54:51 作者:zwjapple
本文詳細介紹了六種處理文件上傳的方式,包括@RequestParam、@RequestPart、@ModelAttribute、@ModelAttribute+@RequestPart、@RequestPart接收JSON和HttpServletRequest原生方式,每種方式都有其特點和適用場景,感興趣的朋友跟隨小編一起看看吧
方式 1:@RequestParam接收文件
后端代碼
@PostMapping("/upload1")
public Result upload1(
@RequestParam("file") MultipartFile file,
@RequestParam("name") String name,
@RequestParam("age") Integer age
) {
// 處理文件
String filename = file.getOriginalFilename();
long size = file.getSize();
return Result.success();
}前端代碼
const formData = new FormData();
formData.append('file', fileBlob);
formData.append('name', 'John');
formData.append('age', '25');
fetch('/api/upload1', {
method: 'POST',
body: formData
});特點
- ? 最簡單直接
- ? 適合少量參數(shù)
- ? 參數(shù)多時代碼冗長
- ? 無法使用
@Valid統(tǒng)一驗證
方式 2:@RequestPart接收文件
后端代碼
@PostMapping("/upload2")
public Result upload2(
@RequestPart("file") MultipartFile file,
@RequestPart("name") String name,
@RequestPart("age") Integer age
) {
return Result.success();
}前端代碼
// 與方式1相同
const formData = new FormData();
formData.append('file', fileBlob);
formData.append('name', 'John');
formData.append('age', '25');特點
- ? 語義更明確(專為 multipart 設(shè)計)
- ? 可以指定每個 part 的 Content-Type
- ? 與
@RequestParam功能類似,參數(shù)多時也冗長
方式 3:@ModelAttribute接收(文件在 DTO 中)
后端代碼
@Data
public class UploadDTO {
@NotNull(message = "文件不能為空")
private MultipartFile file;
@NotBlank(message = "姓名不能為空")
private String name;
@NotNull(message = "年齡不能為空")
@Min(value = 0, message = "年齡不能為負數(shù)")
private Integer age;
private String description;
}
@PostMapping("/upload3")
public Result upload3(@Valid @ModelAttribute UploadDTO dto) {
MultipartFile file = dto.getFile();
// 額外檢查文件是否為空
if (file.isEmpty()) {
throw new BusinessException("文件內(nèi)容不能為空");
}
return Result.success();
}前端代碼
const formData = new FormData();
formData.append('file', fileBlob);
formData.append('name', 'John');
formData.append('age', '25');
formData.append('description', '這是描述');
fetch('/api/upload3', {
method: 'POST',
body: formData
});特點
- ? 代碼簡潔,參數(shù)封裝在 DTO 中
- ? 支持
@Valid統(tǒng)一驗證 - ? DTO 可復(fù)用
- ? 適合傳統(tǒng)表單提交
- ? 只支持扁平數(shù)據(jù)結(jié)構(gòu)
方式 4:@ModelAttribute+@RequestPart混合(推薦)
后端代碼
@Data
public class LoanRequest {
@NotBlank(message = "姓名不能為空")
private String name;
@NotNull(message = "貸款金額不能為空")
private BigDecimal amount;
@NotBlank(message = "貸款類型不能為空")
private String loanType;
private String description;
}
@PostMapping("/upload4")
public Result upload4(
@Valid @ModelAttribute LoanRequest request,
@RequestPart(value = "propProofDocs", required = false) MultipartFile file
) {
// 文件驗證
if (file == null || file.isEmpty()) {
throw new BusinessException("財產(chǎn)證明文件不能為空");
}
return Result.success();
}前端代碼
const formData = new FormData();
// 普通字段
formData.append('name', 'John');
formData.append('amount', '100000');
formData.append('loanType', 'mortgage');
formData.append('description', '購房貸款');
// 文件單獨處理
formData.append('propProofDocs', fileBlob);
fetch('/api/upload4', {
method: 'POST',
body: formData
});特點
- ? 最靈活,業(yè)務(wù)數(shù)據(jù)和文件分離
- ? 支持 DTO 驗證
- ? 文件驗證可以單獨處理
- ? 適合復(fù)雜業(yè)務(wù)場景
- ? 推薦用于大多數(shù)項目
方式 5:@RequestPart接收 JSON + 文件
后端代碼
@Data
public class UserInfo {
@NotBlank(message = "姓名不能為空")
private String name;
@NotNull(message = "年齡不能為空")
private Integer age;
private List<String> hobbies; // 支持復(fù)雜結(jié)構(gòu)
private Address address; // 支持嵌套對象
}
@Data
class Address {
private String city;
private String street;
}
@PostMapping("/upload5")
public Result upload5(
@Valid @RequestPart("userInfo") UserInfo userInfo,
@RequestPart("avatar") MultipartFile avatar
) {
return Result.success();
}前端代碼
const userInfo = {
name: 'John',
age: 25,
hobbies: ['reading', 'coding'],
address: {
city: 'Beijing',
street: 'Chang\'an Ave'
}
};
const formData = new FormData();
// 將 JSON 對象轉(zhuǎn)為 Blob,指定 Content-Type
formData.append('userInfo', new Blob([JSON.stringify(userInfo)], {
type: 'application/json'
}));
formData.append('avatar', fileBlob);
fetch('/api/upload5', {
method: 'POST',
body: formData
});特點
- ? 支持復(fù)雜 JSON 結(jié)構(gòu)(數(shù)組、嵌套對象)
- ? 前后端分離友好
- ? RESTful 風(fēng)格
- ? 前端需要額外構(gòu)造 JSON Blob
- ? 推薦用于復(fù)雜數(shù)據(jù)結(jié)構(gòu)
方式 6:多文件上傳
后端代碼
// 方式 6.1:數(shù)組接收
@PostMapping("/upload6-1")
public Result upload6(
@RequestParam("files") MultipartFile[] files,
@RequestParam("description") String description
) {
for (MultipartFile file : files) {
// 處理每個文件
}
return Result.success();
}
// 方式 6.2:List 接收
@PostMapping("/upload6-2")
public Result upload6(
@RequestParam("files") List<MultipartFile> files,
@RequestParam("description") String description
) {
files.forEach(file -> {
// 處理每個文件
});
return Result.success();
}
// 方式 6.3:不同字段多個文件
@PostMapping("/upload6-3")
public Result upload6(
@RequestPart("idCard") MultipartFile idCard,
@RequestPart("bankCard") MultipartFile bankCard,
@RequestPart("propProof") MultipartFile propProof
) {
return Result.success();
}前端代碼
// 多個文件同名
const formData = new FormData();
files.forEach(file => {
formData.append('files', file); // 注意:相同的 key
});
formData.append('description', '批量上傳');
// 多個文件不同名
const formData2 = new FormData();
formData2.append('idCard', idCardFile);
formData2.append('bankCard', bankCardFile);
formData2.append('propProof', propProofFile);方式 7:HttpServletRequest 原生方式
后端代碼
@PostMapping("/upload7")
public Result upload7(HttpServletRequest request) throws Exception {
// 判斷是否為 multipart 請求
if (!ServletFileUpload.isMultipartContent(request)) {
throw new BusinessException("請求格式錯誤");
}
// 使用 Apache Commons FileUpload
ServletFileUpload upload = new ServletFileUpload();
List<FileItem> items = upload.parseRequest(new ServletRequestContext(request));
for (FileItem item : items) {
if (item.isFormField()) {
// 普通字段
String fieldName = item.getFieldName();
String value = item.getString("UTF-8");
} else {
// 文件字段
String filename = item.getName();
InputStream inputStream = item.getInputStream();
// 處理文件
}
}
return Result.success();
}特點
- ? 完全控制
- ? 適合特殊需求
- ? 代碼復(fù)雜
- ? 不推薦常規(guī)使用
完整對比表
| 方式 | 適用場景 | 代碼簡潔度 | 驗證支持 | 復(fù)雜結(jié)構(gòu) | 推薦度 |
|---|---|---|---|---|---|
| @RequestParam | 簡單場景,少量參數(shù) | ?? | ? | ? | ?? |
| @RequestPart | 與 @RequestParam 類似 | ?? | ? | ? | ?? |
| @ModelAttribute(文件在DTO) | 傳統(tǒng)表單,扁平數(shù)據(jù) | ???? | ? | ? | ???? |
| @ModelAttribute + @RequestPart | 通用場景 | ????? | ? | ? | ????? |
| @RequestPart (JSON) | 復(fù)雜JSON結(jié)構(gòu) | ??? | ? | ? | ???? |
| 多文件上傳 | 批量上傳 | ??? | ? | ? | ???? |
| HttpServletRequest | 特殊需求 | ? | ? | ? | ? |
實際項目推薦
場景 1:簡單表單 + 單文件
@PostMapping("/simple")
public Result simple(
@Valid @ModelAttribute SimpleDTO dto,
@RequestPart("file") MultipartFile file
) { }場景 2:復(fù)雜業(yè)務(wù)數(shù)據(jù) + 多文件
@PostMapping("/complex")
public Result complex(
@Valid @RequestPart("data") ComplexDTO data, // JSON
@RequestPart("idCard") MultipartFile idCard,
@RequestPart("bankCard") MultipartFile bankCard
) { }場景 3:可選文件 + 表單驗證
@PostMapping("/optional")
public Result optional(
@Valid @ModelAttribute FormDTO form,
@RequestPart(value = "attachment", required = false) MultipartFile file
) {
if (file != null && !file.isEmpty()) {
// 處理文件
}
}文件驗證最佳實踐
自定義驗證注解
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FileValidator.class)
public @interface ValidFile {
String message() default "文件不合法";
long maxSize() default 10 * 1024 * 1024; // 10MB
String[] allowedTypes() default {}; // {"image/jpeg", "image/png"}
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
// 驗證器
public class FileValidator implements ConstraintValidator<ValidFile, MultipartFile> {
private long maxSize;
private String[] allowedTypes;
@Override
public void initialize(ValidFile annotation) {
this.maxSize = annotation.maxSize();
this.allowedTypes = annotation.allowedTypes();
}
@Override
public boolean isValid(MultipartFile file, ConstraintValidatorContext context) {
if (file == null || file.isEmpty()) {
return false;
}
// 檢查大小
if (file.getSize() > maxSize) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(
"文件大小不能超過 " + (maxSize / 1024 / 1024) + "MB"
).addConstraintViolation();
return false;
}
// 檢查類型
if (allowedTypes.length > 0) {
String contentType = file.getContentType();
boolean typeMatched = Arrays.asList(allowedTypes).contains(contentType);
if (!typeMatched) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(
"只支持以下文件類型: " + String.join(", ", allowedTypes)
).addConstraintViolation();
return false;
}
}
return true;
}
}
// 使用
@PostMapping("/validated")
public Result validated(
@Valid @ModelAttribute FormDTO form,
@ValidFile(
maxSize = 5 * 1024 * 1024, // 5MB
allowedTypes = {"image/jpeg", "image/png", "application/pdf"},
message = "文件不符合要求"
)
@RequestPart("file") MultipartFile file
) {
return Result.success();
}總結(jié)
日常開發(fā)推薦:
- ?? 方式 4(
@ModelAttribute+@RequestPart)- 最靈活通用 - ?? 方式 3(
@ModelAttribute包含文件)- 簡單場景 - ?? 方式 5(
@RequestPartJSON)- 復(fù)雜數(shù)據(jù)結(jié)構(gòu)
根據(jù)實際業(yè)務(wù)需求選擇合適的方式,優(yōu)先考慮代碼的可維護性和可讀性!
到此這篇關(guān)于Spring Boot 處理帶文件表單的方式匯總的文章就介紹到這了,更多相關(guān)springboot文件表單內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java Selenium實現(xiàn)多窗口切換的示例代碼
這篇文章主要介紹了Java Selenium實現(xiàn)多窗口切換的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
java如何使用jdbc連接TDSQL數(shù)據(jù)庫
TDSQL是騰訊打造的一款分布式數(shù)據(jù)庫產(chǎn)品,具備強一致高可用、全球部署架構(gòu)、分布式水平擴展、高性能、企業(yè)級安全等特性,本文我們就來看看Java如何使用jdbc連接TDSQL數(shù)據(jù)庫吧2025-06-06
Mybatis-plus自動填充不生效或自動填充數(shù)據(jù)為null原因及解決方案
本文主要介紹了Mybatis-plus自動填充不生效或自動填充數(shù)據(jù)為null原因及解決方案,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05

