SpringBoot 同时接收表单数据(后端以实体类接收)和文件
问题背景
请求体
我们都知道,POST 请求可以经参数放入请求体中:
package com.aveovb.api.controller;
import com.aveovb.beans.vo.request.WhiteListReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;;
@RestController
@RequiredArgsConstructor
@Validated
@Api(tags = "白名单")
@RequestMapping(value = "/white/list")
public class WhiteListController {
@ApiOperation(value = "批量导入", notes = "添加数据库校验功能")
@PostMapping(value = "/upload")
public Result<Void> batchInsert(HttpServletResponse response, @RequestBody @Valid WhiteListReq) {
// 功能正常
}
实体类如下:
package com.ageovb.beans.vo.request;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ageovb.common.annotation.CheckTimeInterval;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* 白名单表(WhiteList)请求类
*
* @author : ageovb
* @date : 2022-03-09 10:47:39
*/
@Data
@ApiModel(value = "白名单表请求类")
// 自定义的时区区间校验注解
@CheckTimeInterval(beginTime = "startDate", endTime = "endDate")
public class WhiteListReq {
@ApiModelProperty(value = "白名单组别 ID", required = true, example = "1002")
@NotNull(message = "白名单组别 ID 不能为空")
private Long groupId;
@ApiModelProperty(value = "品牌", required = true, example = "GE")
@NotBlank(message = "品牌不能为空")
@Length(max = 32, message = "品牌长度上限为 32")
private String brand;
@ApiModelProperty(value = "组织代码", required = true, example = "D000002304")
@NotBlank(message = "组织代码不能为空")
@Length(max = 20, message = "组织代码长度上限为 20")
private String orgCode;
@ApiModelProperty(value = "开始日期", required = true, example = "2020-10-01 00:00:00")
@NotNull(message = "开始日期不能为空")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime startDate;
@ApiModelProperty(value = "结束日期", required = true, example = "2023-10-01 00:00:00")
@NotNull(message = "结束日期不能为空")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime endDate;
@ApiModelProperty(value = "用户 ID", required = true, example = "1B3FB2DC-BFB8-4F61-8E9A-44983685EAB6")
@NotBlank(message = "用户 ID 不能为空")
@Length(max = 50, message = "用户 ID 长度上限为 50")
private String userId;
@ApiModelProperty(value = "用户账号", required = true, example = "2283164982@qq.com")
@NotBlank(message = "用户账号不能为空")
@Length(max = 200, message = "用户账号长度上限为 200")
private String userAccount;
}
这样的话,调用接口的时候 SpringBoot 会自动将请求体中的 JSON 映射到实体 WhiteListReq
中。
上传文件
需要上传文件的时候,添加一个 MultipartFile
类型的请求参数即可:
package com.aveovb.api.controller;
import com.aveovb.beans.vo.request.WhiteListReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;;
@RestController
@Validated
@Api(tags = "白名单")
@RequestMapping(value = "/white/list")
public class WhiteListController {
@ApiOperation(value = "批量导入", notes = "添加数据库校验功能")
@PostMapping(value = "/upload")
public Result<Void> batchInsert(HttpServletResponse response, @RequestParam("file") MultipartFile file) {
// 代码略
}
同时使用请求体和上传文件
但是,当我们同时需要使用请求体和上传文件时,运行程序就会报错:
package com.aveovb.api.controller;
import com.aveovb.beans.vo.request.WhiteListReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;;
@RestController
@Validated
@Api(tags = "白名单")
@RequestMapping(value = "/white/list")
public class WhiteListController {
@ApiOperation(value = "批量导入", notes = "添加数据库校验功能")
@PostMapping(value = "/upload")
public Result<Void> batchInsert(HttpServletResponse response, @RequestBody @Valid WhiteListReq,
@RequestParam("file") MultipartFile file) {
// 代码略
}
问题分析
SpringBoot 是使用 HttpMessageConverter 来转换数据的:
- 请求体需要将 Content-Type 设置为 application/json;
- 文件需要将 Content-Type 设置为 multipart/form-data。
但是同时存在上述两种情况时,就出问题了,HTTP 请求的 Content-Type 不可能既是 application/json 又是 multipart/form-data。
解决方案
方案一:将请求实体拆为请求参数
package com.aveovb.api.controller;
import com.aveovb.beans.vo.request.WhiteListReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;;
@RestController
@Validated
@Api(tags = "白名单")
@RequestMapping(value = "/white/list")
public class WhiteListController {
@ApiOperation(value = "批量导入", notes = "添加数据库校验功能")
@PostMapping(value = "/upload")
public Result<Void> batchInsert(HttpServletResponse response, @RequestParam("file") MultipartFile file,
@RequestParam("groupId") Long groupId, @RequestParam("brand") String brand) {
// 代码略
}
参数如果太多,写起来不方便,而且如果需要校验字段,也不方便。
方案二:使用 @RequestPart
package com.aveovb.api.controller;
import com.aveovb.beans.vo.request.WhiteListReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;;
@RestController
@Validated
@Api(tags = "白名单")
@RequestMapping(value = "/white/list")
public class WhiteListController {
@ApiOperation(value = "批量导入", notes = "添加数据库校验功能")
@PostMapping(value = "/upload")
public Result<Void> batchInsert(HttpServletResponse response, @RequestPart @Valid WhiteListReq,
@RequestPart MultipartFile file) {
// 代码略
}
但是这种方式,需要将 WhiteListReq
放入 JSON 文件中,作为一个文件上传,一般不会使用。
方案三:去掉 @RequestBody
package com.aveovb.api.controller;
import com.aveovb.beans.vo.request.WhiteListReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;;
@RestController
@Validated
@Api(tags = "白名单")
@RequestMapping(value = "/white/list")
public class WhiteListController {
@ApiOperation(value = "批量导入", notes = "添加数据库校验功能")
@PostMapping(value = "/upload")
public Result<Void> batchInsert(HttpServletResponse response, @Valid WhiteListReq,
@RequestParam("file") MultipartFile file) {
// 代码略
}
这种方式最简单,也不改变使用方式,推荐使用。
本文作者:ageovb
本文链接:https://www.cnblogs.com/ageovb/p/16662694.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步