目录
- 一、产品需求
- 二、解决方法
- 方案一:大量if-else判断校验
- 方案二:请求体加入注解进行校验
- 三、测试结果
一、产品需求
1.下载指定的excel数据模板
2.excel模板写入数据并导入
3.导入的时候根据校验规则进行筛选,导入成功的返回成功列表,数据存在问题的返回失败列表,失败列表支持数据编辑修正
看到需求的第一眼,可能就觉得第三点有点难度,我们知道,传统的数据校验可以通过在传输对象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) {...}js
TestDTO里面会有一些类似 @NotNull、@NotBlank、@Size等校验注解,这里就不列了。
然后在全局异常拦截那里进行统一封装,使其返回的数据结构尽量保持统一,所以一般还得有一个RestExceptionHandler类。
@ControllerAdvice public class RestExceptionHandler { /** * 处理参数验证失败异常 * @param e * @return */ @ExceptionHandler(MethodArgumentNotValidException.class) @ResponseBody @ResponseStatus(HttpStatus.OK) private Response<?> methodArgumentNotValidException(MethodArgumentNotValidException e) { log.warn("MethodArgumentNotValidException", e); FieldError fieldError = e.getBindingResult().getFieldError(); return ResponseUtils.create(CommonCodeEnum.VALIDATE_ERROR.getCode(), CommonCodeEnum.VALIDATE_ERROR.getMessage(), fieldError.getDefaultMessage()); } }
讲到常见的数据校验,那么我们画风一转,再回来看需求,可见以上是不满足需求的,首先,我们的入参是一个文件流(指定的Excel模板文件),我们得先解析文件再进行数据校验,合法的放一个集合,不合法的放另一个集合;再者,即使入参是一个数组,这种校验一旦不满足立马进异常处理了,无法返回给前端正确的数据结构,所以今天就分享解决这类需求的解决方案。
二、解决方法
基础数据
UserExcelVO
import lombok.Data; import Java.util.List; /** * */ @Data public class UserExcelVO { /** * 成功列表 */ private List<UserExcel> success; /** * 失败列表 */ private List<UserExcel> fail; }
UserExcel
import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import java.io.Serializable; /** * */ @Data @AllArgsConstructor @NoArgsConstructor public class UserExcel implements Serializable { @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 =http://www.devze.com 2) private String mobile; @ExcelProperty(value = "性别", index = 3) private String sex; }
excel模板数据:
方案一:大量if-else判断校验
import com.alibaba.excel.EasyExcel; import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * */ @RestController @RequestMapping("/excel") public class ExcelController { @PostMapping("/importExcel1") public UserExcelVO importExcel(@RequestParam("file") MultipartFile file) { List<UserExcel> list; List<UserExcel> fail = new ArrayList<>(); UserExcelVO userExcelVO = new UserExcelVO(); String mobileReg = "^[1][3,4,5,7,8][0-9]{9}$"; try { list = EasyExcel.read(file.getInputStream(), UserExcel.class, new ModelExcelListener()).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(mobileReg)) { 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
import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; /** * */ public class ValidationUtils { public static Validator getValidator() { return validator; } static Validator validator; static { ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); validator = validatorFactory.getValidator(); } }
ModelExcelListener
import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; import java.util.List; /** * */ @Slf4j public class ModelExcelListener extends AnalysisEventListener<UserExcel> { private List<UserExcel> datas = new ArrayList<>(); /** * 通过 AnalysisContext 对象还可以获取当前 sheet,当前行等数据 */ @Override public void invoke(UserExcel data, AnalysisContext context) { //数据存储到list,供批量处理,或后续自己业务逻辑处理。 log.info("读取到数据{}",data); datas.add(data); //根据业务自行处理,可以写入数据库等等 } //所有的数据解析完了调用 @Override public void doAfterAllAnalysed(AnalysisContext context) { log.info("所有数据解析完成"); } }
请求:
import com.alibaba.excel.EasyExcel; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.validation.ConstraintViolation; import java.io.IOException; import 编程客栈java.util.ArrayList; import java.util.List; import java.util.Set; /** * */ @RestController @RequestMapping("/excel") public class ExcelController { @PostMapping("/importExcel2") public UserExcelVO importExcelV2(@RequestParam("file") MultipartFile file) { List<UserExcel> list; List<UserExcel> fail = new ArrayList<>(); UserExcelVO userExcelVO = new UserExcelVO(); try { list = EasyExcel.read(file.getInputStream(), UserExcel.class, new ModelExcelListener()).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(); } returnhttp://www.devze.com userExcelVO; } }
三、测试结果
方案一的结果:
{ "success": [ { "name": "张2", "age": 19, "mobile": "13056781235", "sex": "女" }, { "name": "张3", "age": 20, "mobile": "13056781236", "sex": "男" }, { "name": "张4", "age": 21, "mobile": "13056781237", "sex": "女" }, { "name": "张5", "age": 22, "mobile": "13056781238", "sex": "男" }, { "name": "张6", "age": 23, "mobile": "13056781239", "sex": "男" }, { "name": "张7", "age": 24, "mobile": "13056781240", "sex": "男" }, { "name": "张8", "age": 25, "mobile": "13056781241", "sex": "男" }, { "name": "张9", "age": 26, "mobile": "13056781242", "sex": "男" } ], "fail": [ { "name": "张1", "age": 18, "mobile": "3056781234", "sex": "男" }, { "name": "张10", "age": 27, "mobile": "130567812436", "sex": "男" } ] }
方案二的结果:
{ "success": [ { "name": "张2", "age": 19, "mobile": "13056781235", "sex": "女" }, { "name": "张3", "age": 20, "mobile": "13056781236", "sex": "男" }, { "name": "张4", "age": 21, "mobile": "13056781237", "sex": "女" }, { "name": "张5", "age": 22, "mobile": "13056781238", "sex": "男" }, http://www.devze.com { "name": "张6", "age": 23, "mobile": "13056781239", "sex": "男" }, { "name": "张7", "age": 24, "mobile": "13056781240", "sex": "男" }, { "name": "张8", "age": 25, "mobile": "13056781241", "sex": "男" }, { "name": "张9", "age": 26, "mobile": "13056781242", "sex": "男" } ], "fail": [ { "name": "张1", "age": 18, "mobile": "3056781234", "sex": "男" }, { "name": "张10", "age": 27, "mobile": "130567812436", "sex": "男" } ] }
发现两种方案的测试结果虽然是一样的,但是很明显,方案二更优秀。我们后续写代码的时候,除了做功能,也要考虑代码的扩展性,不然产品说加个功能,我们又得吭哧吭哧写代码了。
以上就是使用Java实现Excel导入并进行数据校验的详细内容,更多关于Java Excel导入与数据校验的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论