Excel 数据导入,如何更优雅的进行数据校验?
- 2026-11-08 23:20:12
👉 这是一个或许对你有用的社群
🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料:
《项目实战(视频)》:从书中学,往事中“练” 《互联网高频面试题》:面朝简历学习,春暖花开 《架构 x 系统设计》:摧枯拉朽,掌控面试高频场景题 《精进 Java 学习指南》:系统学习,互联网主流技术栈 《必读 Java 源码专栏》:知其然,知其所以然

👉这是一个或许对你有用的开源项目
国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。
功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:
Boot 地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro Cloud 地址:https://gitee.com/zhijiantianya/yudao-cloud 视频教程:https://doc.iocoder.cn
来源:blog.csdn.net/jike11231/
article/details/123994833

一、产品需求:
excel数据模板下载 excel数据导入 导入得时候根据模板得校验规则来进行筛选,导入成功的返回成功列表,数据有问题得返回失败列表,失败列表支持数据编辑修正
看到需求第一眼可能就是第三列有点难度,我们知道,传统得数据校验是在DTO上面加注解
//第一种
public Result test1(@RequestBody @Validated TestDTO dto){...}
//第二种
public Result test2(@RequestBody @Valid TestDTO dto{...}
//第三种
public Result test3(@RequestBody @Validated(value = {SaveGroup.class}) TestDTO dto) {...}TestDTO里面呢会有一些类似 @NotNull、@NotBlank、@Size等校验注解,这里就不列了。
然后再在全局异常拦截那里进行统一封装,使其放回得数据结构尽量保持统一,所以一般还得有一个RestExceptionHandler
@ControllerAdvice
publicclassRestExceptionHandler{
/**
* 处理参数验证失败异常
* @param e
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
privateResponse<?> methodArgumentNotValidException(MethodArgumentNotValidExceptione) {
log.warn("MethodArgumentNotValidException", e);
FieldError fieldError = e.getBindingResult().getFieldError();
return ResponseUtils.create(CommonCodeEnum.VALIDATE_ERROR.getCode(), CommonCodeEnum.VALIDATE_ERROR.getMessage(), fieldError.getDefaultMessage());
}
}讲到常见得数据校验,那么我们画风一转,再回来看需求,可见以上需求是不满足得,首先,我们入参是一个文件,也就是用户传得那个excel,我们得先解析文件再进行数据判断,合法得放一个集合,不合法得放一个集合,再者,即使入参是一个数组,这种校验一旦不满足立马进异常处理了,无法返回给前端正确得数据结构,所以引入了我们今天解决这类需求得解决方案。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/ruoyi-vue-pro 视频教程:https://doc.iocoder.cn/video/
二、解决方案
1.基础数据
UserExcelVO
@Data
publicclassUserExcelVO{
/**
* 成功列表
*/
private List<UserExcel> success;
/**
* 失败列表
*/
private List<UserExcel> fail;
}UserExcel
@Data
@AllArgsConstructor
@NoArgsConstructor
publicclassUserExcelimplementsSerializable{
@NotBlank(message = "手机号不能为空")
@Size(max = 4)
@ExcelProperty(value = "用户名", index = 0)
private String name;
@ExcelProperty(value = "年龄", index = 1)
private Integer age;
@Pattern(regexp = "^[1][3,4,5,7,8][0-9]{9}$$", message = "手机号不合法")
@NotBlank(message = "手机号不能为空")
@ExcelProperty(value = "手机号", index = 2)
private String mobile;
@ExcelProperty(value = "性别", index = 3)
private String sex;
}easyexcel.xsl
用户名 年龄 手机号 性别
张三丰11123847235 男
张三丰21215813847236 男
张三丰31315813847237 男
张三丰41417813847238 男
张三丰51515818847239 男
张三丰61615813847240 男
张三丰717152247241 男
张三丰81815813847242 男
张三丰91915813847243 男
张三丰102015813847244 男
张三丰112115813847245 男方案一:大量if else判断校验
@PostMapping("/v1/importExcel")
public UserExcelVO importExcel(@RequestParam("file") MultipartFile file){
List<UserExcel> list = null;
List<UserExcel> fail = new ArrayList<>();
UserExcelVO userExcelVO = new UserExcelVO();
String mobieReg = "^[1][3,4,5,7,8][0-9]{9}$";
try {
list = EasyExcel.read(file.getInputStream(),UserExcel.class,newModelExcelListener()).sheet().doReadSync();
list.forEach(data->{
//处理姓名的校验
if(StringUtils.isEmpty(data.getName())||data.getName().length()> 4 ){
fail.add(data);
return;
}
//处理手机号的校验
if (StringUtils.isEmpty(data.getMobile())|| !data.getMobile().matches(mobieReg)) {
fail.add(data);
return;
}
//以下根据字段多少可能有n个if
});
userExcelVO.setFail(fail);
list.removeAll(fail);
userExcelVO.setSuccess(list);
} catch (IOException e) {
e.printStackTrace();
}
return userExcelVO;
}方案二:请求体加入注解进行校验
实际的业务场景,一个excel里面假如是订单数据,最少是几十个字段起步的,难道要写几十个if else吗?方案一明显是不合理的,因此使用注解的方式帮我们解决。
ValidationUtils
publicclassValidationUtils{
publicstatic Validator getValidator(){
return validator;
}
static Validator validator;
static{
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
validator=validatorFactory.getValidator();
}
}
@PostMapping("/v2/importExcel")
public UserExcelVO importExcelV2(@RequestParam("file") MultipartFile file){
List<UserExcel> list = null;
List<UserExcel> fail = new ArrayList<>();
UserExcelVO userExcelVO = new UserExcelVO();
try {
list = EasyExcel.read(file.getInputStream(),UserExcel.class,newModelExcelListener()).sheet().doReadSync();
list.forEach(data->{
Set<ConstraintViolation<UserExcel>> violations = ValidationUtils.getValidator().validate(data);
if(violations.size()>0){
fail.add(data);
}
});
userExcelVO.setFail(fail);
list.removeAll(fail);
userExcelVO.setSuccess(list);
} catch (IOException e) {
e.printStackTrace();
}
return userExcelVO;
}
publicstaticclassModelExcelListenerextendsAnalysisEventListener<UserExcel> {
private List<UserExcel> datas = new ArrayList<>();
/**
* 通过 AnalysisContext 对象还可以获取当前 sheet,当前行等数据
*/
@Override
publicvoidinvoke(UserExcel data, AnalysisContext context){
//数据存储到list,供批量处理,或后续自己业务逻辑处理。
log.info("读取到数据{}",data);
datas.add(data);
//根据业务自行处理,可以写入数据库等等
}
//所有的数据解析完了调用
@Override
publicvoiddoAfterAllAnalysed(AnalysisContext context){
log.info("所有数据解析完成");
}
}基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/yudao-cloud 视频教程:https://doc.iocoder.cn/video/
三、测试结果
访问
localhost:8086/user/v1/importExcel localhost:8086/user/v2/importExcel
结果


发现测试结果一致,后续写代码的时候,除了做功能,应该要考虑代码的扩展性,不然产品说加个功能,我们又得吭哧吭哧写代码,那这样也是太累了。
代码下载地址:
❝
https://gitee.com/jike11231/mybatis-plus-demo-test.git
❞
欢迎加入我的知识星球,全面提升技术能力。
👉 加入方式,“长按”或“扫描”下方二维码噢:

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。





文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)