1. Write a custom annotation CommonFieldValidate that needs to be validated
import com.anglin.common.validate.CommonFieldValidator; import com.anglin.common.validate.enums.CommonFieldValidateOperatesEnum; import com.anglin.common.validate.enums.CommonFieldValidateOptionEnum; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Custom Annotation--Field Validation * * @author zhuzhibin * @date 2023/5/16 14:25 **/ @Target({ElementType. TYPE}) //Must be added when using validator, specified to be used with CommonFieldValidator custom validator @Constraint(validatedBy = CommonFieldValidator.class) @Retention(RetentionPolicy. RUNTIME) public @interface CommonFieldValidate { String message() default "The input content verification failed"; /** * Option types are connected with AND or OR */ CommonFieldValidateOptionEnum option() default CommonFieldValidateOptionEnum.AND; CommonFieldValidateOperatesEnum [] operates() default {CommonFieldValidateOperatesEnum. UNIQUE}; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
2. Write custom unique annotations and annotations on whether the data exists
import com.baomidou.mybatisplus.extension.activerecord.Model; import java.lang.annotation.*; /** * Custom annotation verification field uniqueness * * @author zhuzhibin * @date 2023/5/16 14:25 **/ //Only used for non-null verification of request fields @Target({ElementType. FIELD}) //Requires jvm runtime to use @Retention(RetentionPolicy. RUNTIME) public @interface CommonFieldUniqueValidate { /**exist * Validated field */ String fieldName() default ""; /** * Error message */ String message() default "Input content verification failed"; /** * Alias Joint query for fields under the same alias */ String alias() default ""; Class<? extends Model> clazz(); }
package com.anglin.common.annotation; import com.baomidou.mybatisplus.extension.activerecord.Model; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Custom annotation verification -- field -- whether the data exists * * @author zhuzhibin * @date 2023/5/16 14:25 **/ //Only used for non-null verification of request fields @Target({ElementType. FIELD}) //Requires jvm runtime to use @Retention(RetentionPolicy. RUNTIME) public @interface CommonFieldYNExistValidate { /**exist * Validated field */ String fieldName() default ""; /** * Error message */ String message() default "Input content verification failed"; /** * Alias Joint query for fields under the same alias */ String alias() default ""; Class<? extends Model> clazz(); }
3. Write annotation parser
package com.anglin.common.validate; import com.anglin.common.annotation.CommonFieldValidate; import com.anglin.common.util.FieldValidatorUtil; import com.anglin.common.validate.enums.CommonFieldValidateOperatesEnum; import com.anglin.common.validate.enums.CommonFieldValidateOptionEnum; import org.springframework.beans.factory.annotation.Autowired; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; /** * @Title: FieldUniqueValidator * @ProjectName online-plus * @Description: field validation * @Author ZhuZhiBin * @Version * @Date 2023/5/16 11:44 */ public class CommonFieldValidator implements ConstraintValidator<CommonFieldValidate, Object> { @Autowired FieldValidatorUtil validatorUtil; private String message; private CommonFieldValidateOperatesEnum[] operates; private CommonFieldValidateOptionEnum option; @Override public void initialize(CommonFieldValidate validator) { this. message = validator. message(); this.operates = validator.operates(); this.option = validator.option(); } @Override public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) { if(operates != null & amp; & amp; operates. length == 0){ return true; } return validatorUtil. validator(message, operates, option, o); } }
4. Write enumeration classes used in annotations
package com.anglin.common.validate.enums; import com.anglin.common.exception.CommonException; import lombok. Getter; /** * field validation * * @date 2023/5/17 14:02 **/ @Getter public enum CommonFieldValidateOperatesEnum { /** Uniqueness */ UNIQUE("UNIQUE"), /** does it exist */ YN_EXIST("YN_EXIST"); private final String value; CommonFieldValidateOperatesEnum(String value) { this.value = value; } public static void validate(String value) { boolean flag = UNIQUE.getValue().equals(value) || YN_EXIST.getValue().equals(value); if(!flag) { throw new CommonException("This verification method is not supported: {}", value); } } }
package com.anglin.common.validate.enums; import com.anglin.common.exception.CommonException; import lombok. Getter; /** * Validate whether the field option is and or or * * @date 2023/5/17 14:02 **/ @Getter public enum CommonFieldValidateOptionEnum { /** Association **/ AND("AND"), /** non-associated **/ OR("OR"); private final String value; CommonFieldValidateOptionEnum(String value) { this.value = value; } public static void validate(String value) { boolean flag = AND.getValue().equals(value) || OR.getValue().equals(value); if(!flag) { throw new CommonException("This verification method is not supported: {}", value); } } }
5. Write the verification Util
package com.anglin.common.util; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; import com.anglin.common.annotation.CommonFieldUniqueValidate; import com.anglin.common.annotation.CommonFieldYNExistValidate; import com.anglin.common.validate.enums.CommonFieldValidateOperatesEnum; import com.anglin.common.validate.enums.CommonFieldValidateOptionEnum; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Component; import javax.validation.ValidationException; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.*; import java.util.stream.Collectors; /** * @Title: FieldUniqueUtils * @ProjectName online-plus * @Description: Field uniqueness verification tool class * @Author ZhuZhiBin * @Version * @Date 2023/5/16 11:48 */ @Slf4j @Component public class FieldValidatorUtil { /** * The id field in the entity class */ private String idColumnName; /** * The value of id in the entity class */ private Object idColumnValue; private final String declaredField = "memberValues"; private final String annotateAttribute = "fieldName"; private final String objKey = "obj"; private final String msgKey = "msg"; /** * First, obtain the list under different options of custom annotations on vo or dto by traversing * Annotation on the null value field does not proceed to the next step of judgment * @param message * @param operates * @param option * @param o * @return */ public boolean validator(String message, CommonFieldValidateOperatesEnum[] operates, CommonFieldValidateOptionEnum option, Object o) { Field[] fields = ReflectUtil. getFields(o. getClass()); List<CommonFieldUniqueValidate> commonFieldUniqueValidateList = new LinkedList<>(); List<CommonFieldYNExistValidate> commonFieldYNExistValidateList = new LinkedList<>(); Map<String,Object> queryUniqueValidateMap = new HashMap<>(); Map<String,Object> queryYNExistValidateMap = new HashMap<>(); boolean unique = ArrayUtil.contains(operates, CommonFieldValidateOperatesEnum.UNIQUE); boolean ynExist = ArrayUtil.contains(operates, CommonFieldValidateOperatesEnum.YN_EXIST); for (Field f : fields) { Object fieldValue = ReflectUtil. getFieldValue(o, f); // exclude empty fields if (ObjectUtil. isNull(fieldValue)) { continue; } // unique verification if(unique){ uniqueBuilder(f, fieldValue, commonFieldUniqueValidateList, queryUniqueValidateMap); } //Is there a verification if(ynExist){ ynExistBuilder(f, fieldValue, commonFieldYNExistValidateList, queryYNExistValidateMap); } } boolean res = true; if(ArrayUtil.contains(operates, CommonFieldValidateOperatesEnum.UNIQUE) & amp; & amp; CollectionUtil.isNotEmpty(commonFieldUniqueValidateList)){ res = uniqueValidator(CommonFieldValidateOperatesEnum.UNIQUE, message, option, commonFieldUniqueValidateList, queryUniqueValidateMap, o); } if(ArrayUtil.contains(operates, CommonFieldValidateOperatesEnum.YN_EXIST) & amp; & amp; CollectionUtil.isNotEmpty(commonFieldYNExistValidateList)){ res = yNExistValidator(CommonFieldValidateOperatesEnum.YN_EXIST, message, option,commonFieldYNExistValidateList, queryYNExistValidateMap, o); } return res; } /** * does it exist * Assemble our attributes and values in the map to facilitate subsequent splicing conditions * @param f * @param fieldValue * @param commonFieldYNExistValidateList * @param queryYNExistValidateMap */ private void ynExistBuilder(Field f, Object fieldValue, List<CommonFieldYNExistValidate> commonFieldYNExistValidateList, Map<String, Object> queryYNExistValidateMap) { CommonFieldYNExistValidate commonFieldYNExistValidate = f.getAnnotation(CommonFieldYNExistValidate.class); if(commonFieldYNExistValidate != null){ String fieldName = StrUtil.isEmpty(commonFieldYNExistValidate.fieldName()) ? StrUtil.toUnderlineCase(f.getName()) : commonFieldYNExistValidate.fieldName(); dynamicAnnotateAttribute(commonFieldYNExistValidate, fieldName); commonFieldYNExistValidateList.add(commonFieldYNExistValidate); queryYNExistValidateMap.put(fieldName, fieldValue); } } /** * uniqueness * Assemble our attributes and values in the map to facilitate subsequent splicing conditions * Dynamically assign values to annotation attributes Code processing is mainly for fear of irregularities in the later use of annotations * @param f * @param fieldValue * @param commonFieldUniqueValidateList * @param queryUniqueValidateMap */ private void uniqueBuilder(Field f, Object fieldValue, List<CommonFieldUniqueValidate> commonFieldUniqueValidateList, Map<String, Object> queryUniqueValidateMap) { CommonFieldUniqueValidate commonFieldUniqueValidate = f.getAnnotation(CommonFieldUniqueValidate.class); if(commonFieldUniqueValidate != null){ String fieldName = StrUtil.isEmpty(commonFieldUniqueValidate.fieldName()) ? StrUtil.toUnderlineCase(f.getName()) : commonFieldUniqueValidate.fieldName(); dynamicAnnotateAttribute(commonFieldUniqueValidate, fieldName); commonFieldUniqueValidateList.add(commonFieldUniqueValidate); queryUniqueValidateMap.put(fieldName, fieldValue); } } /** * Dynamically adjust the fieldName attribute value of the custom annotation * * @param annotate annotation * @param fieldName */ private void dynamicAnnotateAttribute(Object annotate, String fieldName) { //Get the InvocationHandler held by the proxy instance of foo InvocationHandler h = Proxy. getInvocationHandler(annotate); // Get the memberValues field of AnnotationInvocationHandler Field hField = null; try { hField = h. getClass(). getDeclaredField(declaredField); } catch (NoSuchFieldException e) { e.printStackTrace(); } //Because this field is private final decoration, so you need to open the permission hField. setAccessible(true); // get memberValues Map memberValues = null; try { memberValues = (Map) hField. get(h); } catch (IllegalAccessException e) { e.printStackTrace(); } // Modify the value attribute value memberValues. put(annotateAttribute, fieldName); } /** * Field information unique verification * Perform logical processing according to the attribute information on the custom annotation * Acquire objects according to class Perform subsequent persistence and other operations according to mybatis-plus active-record operations * * * @param unique * @param option * @param commonFieldUniqueValidates * @param queryUniqueValidateMap * @param o * @return */ public boolean uniqueValidator(CommonFieldValidateOperatesEnum unique, String message, CommonFieldValidateOptionEnum option, List<CommonFieldUniqueValidate> commonFieldUniqueValidates, Map<String, Object> queryUniqueValidateMap, Object o){ //alias to group Map<String, List<CommonFieldUniqueValidate>> collect = commonFieldUniqueValidates.stream().collect(Collectors.groupingBy(CommonFieldUniqueValidate::alias)); boolean res = true; for (String key : collect. keySet()) { if(CommonFieldValidateOptionEnum.AND.equals(option)) { Map<String, Object> stringObjectMap = uniqueValidatorBuilder(collect.get(key).get(0), message, o); checkUpdateOrSave(stringObjectMap. get(objKey)); Object msg = stringObjectMap. get(msgKey); res = checkBuilder(unique, queryUniqueValidateMap, stringObjectMap.get(objKey), msg.toString()); } else { List<CommonFieldUniqueValidate> commonFieldUniqueValidateList = collect.get(key); for (CommonFieldUniqueValidate commonFieldUniqueValidate : commonFieldUniqueValidateList) { Map<String,Object> queryMap = new HashMap<>(); Map<String, Object> stringObjectMap = uniqueValidatorBuilder(commonFieldUniqueValidate, message, o); checkUpdateOrSave(stringObjectMap. get(objKey)); Object msg = stringObjectMap. get(msgKey); queryMap.put(commonFieldUniqueValidate.fieldName(), queryUniqueValidateMap.get(commonFieldUniqueValidate.fieldName())); res = checkBuilder(unique, queryMap, stringObjectMap.get(objKey), msg.toString()); if(!res){ return res; } } } } return res; } private Map<String,Object> uniqueValidatorBuilder(CommonFieldUniqueValidate commonFieldUniqueValidate, String message, Object o) { Map<String,Object> map = new HashMap(); Object obj = null; if(ObjectUtil.isNotNull(commonFieldUniqueValidate.clazz())){ try { obj = commonFieldUniqueValidate.clazz().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } String msg = commonFieldUniqueValidate. message(); if (null == obj) { obj = o; } else { BeanUtils. copyProperties(o, obj); } msg = StrUtil.isEmpty(msg) ? message : msg; map.put(objKey, obj); map.put(msgKey, msg); return map; } /** * Field information unique verification * Perform logical processing according to the attribute information on the custom annotation * Acquire objects according to class Perform subsequent persistence and other operations according to mybatis-plus active-record operations * * * @param ynExist * @param option * @param commonFieldYNExistValidates * @param queryYNExistValidateMap * @param o * @return */ public boolean yNExistValidator(CommonFieldValidateOperatesEnum ynExist, String message, CommonFieldValidateOptionEnum option, List<CommonFieldYNExistValidate> commonFieldYNExistValidates, Map<String, Object> queryYNExistValidateMap, Object o){ //alias to group Map<String, List<CommonFieldYNExistValidate>> collect = commonFieldYNExistValidates.stream().collect(Collectors.groupingBy(CommonFieldYNExistValidate::alias)); boolean res = true; for (String key : collect. keySet()) { if(CommonFieldValidateOptionEnum.AND.equals(option)) { Map<String, Object> stringObjectMap = yNExistValidatorBuilder(collect.get(key).get(0), message, o); checkUpdateOrSave(stringObjectMap. get(objKey)); Object msg = stringObjectMap. get(msgKey); res = checkBuilder(ynExist, queryYNExistValidateMap, stringObjectMap.get(objKey), msg.toString()); } else { for (CommonFieldYNExistValidate commonFieldYNExistValidate : collect.get(key)) { Map<String,Object> queryMap = new HashMap<>(); Map<String, Object> stringObjectMap = yNExistValidatorBuilder(commonFieldYNExistValidate, message, o); checkUpdateOrSave(stringObjectMap. get(objKey)); Object msg = stringObjectMap. get(msgKey); queryMap.put(commonFieldYNExistValidate.fieldName(), queryYNExistValidateMap.get(commonFieldYNExistValidate.fieldName())); res = checkBuilder(ynExist, queryMap, stringObjectMap.get(objKey), msg.toString()); if(!res){ return res; } } } } return res; } private Map<String, Object> yNExistValidatorBuilder(CommonFieldYNExistValidate commonFieldYNExistValidate, String message, Object o) { Map<String,Object> map = new HashMap(); Object obj = null; if(ObjectUtil.isNotNull(commonFieldYNExistValidate.clazz())){ try { obj = commonFieldYNExistValidate.clazz().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } String msg = commonFieldYNExistValidate. message(); if (null == obj) { obj = o; } else { BeanUtils. copyProperties(o, obj); } msg = StrUtil.isEmpty(msg) ? message : msg; map.put(objKey, obj); map.put(msgKey, msg); return map; } /** * Determine whether to update or save by whether the value of the @TableId annotation in the incoming entity class is empty * Assign the value id value and id column name * The value of id is not empty, it is an update, otherwise it is an insert * @param o Annotated entity class * @return */ public void checkUpdateOrSave(Object o){ Field[] fields = getAllFields(o. getClass()); for (Field f: fields) { // Set private properties to be readable f. setAccessible(true); if(f.isAnnotationPresent(TableId.class)){ TableId tableId = f. getAnnotation(TableId. class); idColumnName = tableId. value(); try { idColumnValue = f. get(o); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } /** * Method to get the attributes of this class and its parent class * @param clazz current class object * @return field array */ private static Field[] getAllFields(Class<?> clazz) { List<Field> fieldList = new ArrayList<>(); while (clazz != null){ fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()))); clazz = clazz. getSuperclass(); } Field[] fields = new Field[fieldList. size()]; return fieldList.toArray(fields); } /** * Obtain whether the data is repeated through the incoming field value * @param operate * @param queryMap * @param o * @param message * @return */ public boolean checkBuilder(CommonFieldValidateOperatesEnum operate, Map<String, Object> queryMap, Object o, String message){ Model model = (Model) o; QueryWrapper queryWrapper = new QueryWrapper(); for(String key : queryMap. keySet()){ queryWrapper.eq(key, queryMap.get(key)); } if(operate.equals(CommonFieldValidateOperatesEnum.UNIQUE)){ if(idColumnValue != null){ //Update, the condition must exclude itself queryWrapper.ne(idColumnName, idColumnValue); } if (model. selectCount(queryWrapper) > 0){ log. error(message); throw new ValidationException(message); } } else if(operate.equals(CommonFieldValidateOperatesEnum.YN_EXIST) & amp; & amp; model.selectCount(queryWrapper) < 0){ log. error(message); throw new ValidationException(message); } return true; } }
6. Write the verified dto
package com.anglin.biz.modular.user.param; import com.anglin.biz.modular.user.entity.BizUser; import com.anglin.common.annotation.CommonFieldUniqueValidate; import com.anglin.common.annotation.CommonFieldValidate; import com.anglin.common.annotation.CommonPhoneOrEmail; import com.anglin.common.validate.enums.CommonFieldValidateOperatesEnum; import com.anglin.common.validate.enums.CommonFieldValidateOptionEnum; import com.anglin.common.validate.enums.CommonPhoneOrEmailTypeEnum; import io.swagger.annotations.ApiModelProperty; import lombok. Getter; import lombok. Setter; import javax.validation.constraints.NotBlank; /** * Personnel addition parameters * * @date 2022/7/26 15:36 **/ @Getter @Setter @CommonFieldValidate(operates = {CommonFieldValidateOperatesEnum.UNIQUE}, option = CommonFieldValidateOptionEnum.OR, message = "User data validation failed, please re-enter") public class BizUserAddParam { /** account */ @ApiModelProperty(value = "Account", required = true, position = 1) @NotBlank(message = "account cannot be empty") @CommonFieldUniqueValidate(fieldName = "account", message = "Duplicate account exists, please re-enter", clazz = BizUser.class, alias = "bizUser") private String account; /** Name */ @ApiModelProperty(value = "Name", required = true, position = 2) @NotBlank(message = "name cannot be empty") private String name; /** organization id */ @ApiModelProperty(value = "Organization id", required = true, position = 3) @NotBlank(message = "orgId cannot be empty") private String orgId; /** post id */ @ApiModelProperty(value = "post id", required = true, position = 4) @NotBlank(message = "positionId cannot be empty") private String positionId; /** post level */ @ApiModelProperty(value = "post level", position = 5) private String positionLevel; /** supervisor id */ @ApiModelProperty(value = "Supervisor id", position = 6) private String directorId; /** avatar */ @ApiModelProperty(value = "Avatar, picture base64", position = 7) private String avatar; /** sign */ @ApiModelProperty(value = "signature, image base64", position = 8) private String signature; /** Nick name */ @ApiModelProperty(value = "nickname", position = 9) private String nickname; /** gender */ @ApiModelProperty(value = "gender", position = 10) private String gender; /** age */ @ApiModelProperty(value = "age", position = 11) private String age; /** date of birth */ @ApiModelProperty(value = "Date of Birth", position = 12) private String birthday; /** nationality */ @ApiModelProperty(value = "ethnicity", position = 13) private String nation; /** Native place */ @ApiModelProperty(value = "Hometown", position = 14) private String nativePlace; /** Home address */ @ApiModelProperty(value = "home address", position = 15) private String homeAddress; /** contact address */ @ApiModelProperty(value = "communication address", position = 16) private String mailingAddress; /** type of certificate */ @ApiModelProperty(value = "Certificate Type", position = 17) private String idCardType; /** ID number */ @ApiModelProperty(value = "ID number", position = 18) private String idCardNumber; /** Culture level */ @ApiModelProperty(value = "education level", position = 19) private String cultureLevel; /** political status */ @ApiModelProperty(value = "Political Aspect", position = 20) private String politicalOutlook; /** graduated school */ @ApiModelProperty(value = "graduate school", position = 21) private String college; /** Educational background */ @ApiModelProperty(value = "education", position = 22) private String education; /** School system */ @ApiModelProperty(value = "School System", position = 23) private String eduLength; /** Bachelor of Science */ @ApiModelProperty(value = "degree", position = 24) private String degree; /** cell phone */ @ApiModelProperty(value = "Mobile phone", position = 25) @CommonPhoneOrEmail(message = "The phone number format is incorrect", type = CommonPhoneOrEmailTypeEnum.PHONE) @CommonFieldUniqueValidate(fieldName = "phone", message = "There is a duplicate phone number, please re-enter", clazz = BizUser.class, alias = "bizUser") private String phone; /** Mail */ @ApiModelProperty(value = "Mailbox", position = 26) @CommonPhoneOrEmail(message = "The email format is incorrect", type = CommonPhoneOrEmailTypeEnum.EMAIL) @CommonFieldUniqueValidate(fieldName = "email", message = "Duplicate email exists, please re-enter", clazz = BizUser.class, alias = "bizUser") private String email; /** home phone */ @ApiModelProperty(value = "Home Phone", position = 27) private String homeTel; /** Office Phone */ @ApiModelProperty(value = "office phone", position = 28) private String officeTel; /** emergency contact */ @ApiModelProperty(value = "Emergency Contact", position = 29) private String emergencyContact; /** Emergency contact number */ @ApiModelProperty(value = "Emergency contact number", position = 30) private String emergencyPhone; /** Emergency contact address */ @ApiModelProperty(value = "emergency contact address", position = 31) private String emergencyAddress; /** employee ID */ @ApiModelProperty(value = "employee number", position = 32) private String empNo; /** Entry date */ @ApiModelProperty(value = "employee number", position = 33) private String entryDate; /** concurrent information */ @ApiModelProperty(value = "concurrent information", position = 34) private String positionJson; /** Sort code */ @ApiModelProperty(value = "sort code", position = 35) private Integer sortCode; /** Extended Information */ @ApiModelProperty(value = "extended information", position = 36) private String extJson; }
Seven, write the controller
/** * Add people * * @date 2022/4/24 20:47 */ @ApiOperationSupport(order = 2) @ApiOperation("Add Person") @CommonLog("Add Person") @SaCheckPermission("/biz/user/add") @PostMapping("/biz/user/add") public CommonResult<String> add(@RequestBody @Valid BizUserAddParam bizUserAddParam) { bizUserService.add(bizUserAddParam); return CommonResult.ok(); }