开发者

使用Java实现Excel导入并进行数据校验

目录
  • 一、产品需求
  • 二、解决方法
    • 方案一:大量if-else判断校验
    • 方案二:请求体加入注解进行校验
  • 三、测试结果

    一、产品需求

    1.下载指定的excel数据模板

    2.excel模板写入数据并导入

    3.导入的时候根据校验规则进行筛选,导入成功的返回成功列表,数据存在问题的返回失败列表,失败列表支持数据编辑修正

    看到需求的第一眼,可能就觉得第三点有点难度,我们知道,传统的数据校验可以通过在传输对象dto上面加注解实现。

    使用Java实现Excel导入并进行数据校验

    //第一种
    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模板数据

    使用Java实现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)其它相关文章!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜