- // 读取数据,hutool读取数据成 List
> 的形式
- List
> list = excelReader.read();
-
- // 默认方式:对注解上的校验并转换
- List
qUserImportList = CheckUtil.check(list, QUserTemplet.class); -
-
-
- // 携带自定义校验方式:或做其他动作
- List
deptIds = departmentMapper.selectAll(); // 查询所有已知部门 - List
qUserImportList = CheckUtil.check(list, QUserTemplet.class, (qUserTemplet, row) -> { - // 判断部门是否存在
- if (!CollUtil.contains(deptIds, qUserTemplet.getDepartmentId())) {
- throw new CheckException("第" + row + "行,部门不存在,请输入正确ID");
- }
- // 生成 加密密码 和 盐
- String salt = IdUtil.simpleUUID();
- String pass = EncryptKit.encryptSha1(qUserTemplet.getPassword(), salt);
- qUserTemplet.setPassword(pass);
- qUserTemplet.setSalt(salt);
- });
-
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import lombok.experimental.SuperBuilder;
- import org.wsitm.web.basic.util.Constant;
- import org.wsitm.web.basic.util.check.Check;
- import org.wsitm.web.basic.util.export.Header;
-
- import java.io.Serializable;
-
- /**
- * 用户表参数
- *
- *
- * @author lzy on 2021/4/20 9:12
- */
- @Data
- @SuperBuilder
- @AllArgsConstructor
- @NoArgsConstructor
- public class QUserTemplet implements Serializable {
-
- /**
- * 用户(唯一)
- */
- @Check(regex = "^[a-z0-9_-]{3,16}$", message = "用户名不符合要求")
- private String account;
-
- /**
- * 用户名称
- */
- @Check(notEmpty = true, message = "用户名称不能为空")
- private String fullname;
-
- /**
- * 角色描述
- */
- @Check(regex = "^(((\\d+,)+\\d+)|\\d)$", message = "角色请输入数字且以逗号分隔")
- private String roles;
-
- /**
- * 用户密码
- */
- @Check(regex = "^(?![a-zA-Z]+$)(?!\\d+$)(?![!@#$%^&*]+$)[\\w!@#$%^&*]{6,18}$", message = "密码不符合要求")
- private String password;
-
- /**
- * 性别
- */
- @Check(regex = "[01]", message = "性别请输入1或0")
- private Integer sex;
-
- /**
- * 城市id
- */
- @Check(regex = "\\d+", message = "地市请输入数字")
- private Long cityId;
-
- /**
- * 电话
- */
- @Check(regex = "^[1][0-9]{10}$", message = "电话号码格式不正确")
- private String telephone;
-
- /**
- * 邮箱
- */
- @Check(regex = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$", message = "邮箱号码格式不正确")
- private String email;
-
- /**
- * 部门组织ID
- */
- @Check(regex = "\\d+", message = "部门ID请输入数字")
- private Long departmentId;
-
- /**
- * 描述
- */
- @Check()
- private String remark;
-
- private static final long serialVersionUID = 1L;
- }
- package org.wsitm.web.basic.util.check;
-
- import java.lang.annotation.*;
-
- /**
- * 检查校验数据注解
- *
- * @author lzy
- */
- @Target({ElementType.FIELD})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface Check {
-
- /**
- * 校验,不能为空
- *
- * @return true、不能为空,true:表示不能、false:可以为空
- */
- boolean notEmpty() default false;
-
- /**
- * 校验,正则
- *
- * @return 正则
- */
- String regex() default "";
-
- /**
- * 校验,时间的格式
- *
- * @return 时间的格式
- */
- String dateFormat() default "";
-
- /**
- * 异常的描述
- *
- * @return 异常的描述
- */
- String message() default "Incorrect field";
- }
-
注意:转换校验只转换携带@Check注解的字段,没有设置排序注解,所以排序默认是从上到下且携带@Check注解的字段
- package org.wsitm.web.basic.util.check;
-
- import java.io.Serializable;
- import java.util.List;
-
- /**
- * 业务异常
- *
- * @author lzy
- */
- @SuppressWarnings({"unused", "rawtypes"})
- public class CheckException extends RuntimeException implements Serializable {
- private static final long serialVersionUID = 1L;
-
- private int status = 500;
- private String detailedError;
- private List tempList;
-
- public CheckException(String message) {
- super(message);
- }
-
- public CheckException(String message, int status) {
- super(message);
- this.status = status;
- }
-
- public CheckException(String message, String detailedError) {
- super(message);
- this.detailedError = detailedError;
- }
-
- public CheckException(String message, String detailedError, int status) {
- super(message);
- this.detailedError = detailedError;
- this.status = status;
- }
-
- public CheckException(String message, String detailedError, List tempList) {
- super(message);
- this.detailedError = detailedError;
- this.tempList = tempList;
- }
-
- public CheckException(String message, String detailedError, List tempList, int status) {
- super(message);
- this.detailedError = detailedError;
- this.status = status;
- this.tempList = tempList;
- }
-
- public CheckException(String message, String detailedError, List tempList, int status, Throwable e) {
- super(message, e);
- this.detailedError = detailedError;
- this.tempList = tempList;
- this.status = status;
- }
-
- public int getStatus() {
- return status;
- }
-
- public void setStatus(int status) {
- this.status = status;
- }
-
- public String getDetailedError() {
- return detailedError;
- }
-
- public void setDetailedError(String detailedError) {
- this.detailedError = detailedError;
- }
-
- public List getTempList() {
- return tempList;
- }
-
- public void setTempList(List tempList) {
- this.tempList = tempList;
- }
-
- }
注意:自定义异常,主要用于携带校验异常的数据,便于业务记录
- package org.wsitm.web.basic.util.check;
-
- import cn.hutool.core.annotation.Alias;
- import cn.hutool.core.bean.BeanUtil;
- import cn.hutool.core.collection.CollUtil;
- import cn.hutool.core.date.DateTime;
- import cn.hutool.core.map.MapUtil;
- import cn.hutool.core.util.ReflectUtil;
- import cn.hutool.core.util.StrUtil;
-
- import java.lang.reflect.Field;
- import java.time.LocalDate;
- import java.time.LocalDateTime;
- import java.time.format.DateTimeFormatter;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.regex.Pattern;
-
- /**
- * 数据检测并转换工具
- *
- * @author lzy
- */
- public class CheckUtil {
-
- /**
- * 批量检测数据是否合理,并返回指定类型数
- *
- * @param list 原始数据
- * @param clazz 返回类型
- * @param
指定类型 - * @return 校验并转换后的数据
- */
- public static
List check(List> list, Class clazz)
throws CheckException { - return check(list, clazz, 1, true, null);
- }
-
- /**
- * 批量检测数据是否合理,并返回指定类型数
- *
- * @param list 原始数据
- * @param clazz 返回类型
- * @param checkRow 函数,自定义校验,参数:对象,行数
- * @param
指定类型 - * @return 校验并转换后的数据
- */
- public static
List check(List> list, Class clazz, CheckConsumer checkRow)
throws CheckException { - return check(list, clazz, 1, true, checkRow);
- }
-
- /**
- * 批量检测数据是否合理,并返回指定类型数
- *
- * @param list 原始数据
- * @param clazz 返回类型
- * @param skipRow 跳过的头部的行数
- * @param checkAll 是否校验全部,是:表示全部校验完成才返回结果集。否:表示一旦发生异常直接返回
- * @param checkRow 函数,自定义校验,参数:对象,行数
- * @param
指定类型 - * @return 校验并转换后的数据
- */
- public static
List check(List> list, Class clazz,
- int skipRow, boolean checkAll, CheckConsumer
checkRow) throws CheckException { -
- Field[] fields = ReflectUtil.getFields(clazz, field -> field.getAnnotation(Check.class) != null);
-
- Map
patternMap = new HashMap<>(); - List
msgList = new ArrayList<>(); - List
result = new ArrayList<>(); -
- for (int i = 0, size = list.size(); i < size; i++) {
- int row = i + 1;
- if (skipRow >= row) {
- continue;
- }
- List
-
- if (checkAll) {
- try {
- checkAllField(fields, line, patternMap, row, result, clazz, checkRow);
- } catch (Exception exception) {
- msgList.add(exception.getMessage());
- }
- } else {
- checkAllField(fields, line, patternMap, row, result, clazz, checkRow);
- }
- }
-
- if (CollUtil.isNotEmpty(msgList)) {
- String msg = String.format("校验通过个数:%s,校验失败个数:%s", (list.size() - skipRow - msgList.size()), msgList.size());
- throw new CheckException(msg, String.join("\n", msgList), result);
- }
-
- return result;
- }
-
- /**
- * 校验n行的所有字段
- *
- * @param fields 字段数组
- * @param line 行的原数据
- * @param patternMap 枚举MAP
- * @param row 行数
- * @param result 结果集
- * @param clazz 类型
- * @param checkRow 函数,自定义校验,参数:对象,行数
- * @param
类型 - */
- private static
void checkAllField(Field[] fields, List - Map
patternMap, int row, - List
result, Class clazz, CheckConsumer checkRow) throws CheckException { - Map
item = MapUtil.newHashMap(); - for (int i = 0, size = fields.length; i < size; i++) {
- if (CollUtil.isNotEmpty(line) && line.size() > i) {
- Field field = fields[i];
- Check check = field.getAnnotation(Check.class);
- String key = field.getName();
- String tranKey = null;
-
- Alias alias = field.getAnnotation(Alias.class);
- if (alias != null) {
- tranKey = alias.value();
- }
-
- Object value = line.get(i);
-
- if (check.notEmpty() && StrUtil.isEmpty(String.valueOf(value))) {
- throw new CheckException("第" + row + "行," + check.message());
- }
-
- if (StrUtil.isNotEmpty(check.regex())) {
- Pattern pattern = patternMap.computeIfAbsent(key, k -> Pattern.compile(check.regex(), Pattern.CASE_INSENSITIVE));
- if (!pattern.matcher(String.valueOf(value)).find()) {
- throw new CheckException("第" + row + "行," + check.message());
- }
- }
-
- if (StrUtil.isNotEmpty(check.dateFormat())) {
- value = checkDateTime(line, check, field.getType(), row);
- }
-
- item.put(StrUtil.emptyToDefault(tranKey, key), value);
- }
- }
- T t = BeanUtil.toBean(item, clazz);
-
- if (checkRow != null) {
- // 个性化校验回调
- checkRow.accept(t, row);
- }
-
- result.add(t);
- }
-
-
- private static Object checkDateTime(Object value, Check check, Class> type, int row) throws CheckException {
- try {
- if (type.isAssignableFrom(CharSequence.class) || type.isAssignableFrom(Number.class)) {
- // bean中的类型是 字符串/整形(yyyyMMdd) 时,校验是否符合格式
- if (value instanceof DateTime) {
- return ((DateTime) value).toString(check.dateFormat());
- }
- if (value instanceof LocalDate) {
- return ((LocalDate) value).format(DateTimeFormatter.ofPattern(check.dateFormat()));
- }
- if (value instanceof LocalDateTime) {
- return ((LocalDateTime) value).format(DateTimeFormatter.ofPattern(check.dateFormat()));
- }
- }
- return value;
- } catch (Exception e) {
- throw new CheckException("第" + row + "行," + check.message());
- }
- }
-
- @FunctionalInterface
- public interface CheckConsumer
{ - void accept(T t, U u) throws CheckException;
- }
-
- }