JAVA利⽤切⾯、注解动态判断请求信息中字段是否需要为空
项⽬中遇到⼀个需求,保存医⽣信息时,执业范围在医师编号为23开头时为必填项,其他医师编号时,执业范围为⾮必填项。当然这样的需求可以使⽤简单的if判断来解决,但
是最近学习了注解的使⽤,刚好此需求可以⽤到,基本思路如下:
1、创建有条件判断字段为空的注解 ConditionalNotEmpty
2、在医⽣实体类--》执业范围字段上添加 ConditionalNotEmpty,并给出相应条件
3、切⾯类中使⽤java反射机制拿到注解信息,并根据传⼊的条件动态判断配置了该注解的字段是否需要校验空值
以下是⼤致代码:
1、注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConditionalNotEmpty {
//分组标识
String groupIdentify() default "";
//错误提⽰信息
String message();
//业务操作标识
String[] operation() default {};
//判断依据的字段名称,如医师编号
String conditionFiledName() default "";
//判断条件,如本例中为医师编号起始值为23或者25,那么配置23,25
String contionString() default "";
}
2、医⽣信息实体中,在执业范围字段配置该注解
@Data
@Table(name = "t_doctor")
public class Doctor implements Serializable{
private static final long serialVersionUID = -7355208328761399457L;
@Id
private String id;
@NotEmpty(message = "职务代码不能为空",groups = {InsertGroup.class})
@Length(max = 3,message = "专业技术职务代码不能超过3位",groups = {InsertGroup.class})
private String zwdm;
@Length(max = 30,message = "证书编码不能超过30位",groups = {InsertGroup.class})
@ConditionalNotEmpty(groupIdentify = "1",message = "当职务代码前缀为 aa及前缀为 bb的编码时,证书编码必填",operation =  {ValidateConstants.INSERT},conditionFiledName = "zwdm",contionString = "aa,bb")
private String zsbm;
}
3、切⾯类中获取注解并进⾏判断
package mypackage;
import org.apachemons.lang3.ArrayUtils;
import org.apachemons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.flect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.io.IOException;
import java.lang.annotation.Annotation;
import flect.Field;
import flect.Method;
import java.util.*;
/**
* @desc 校验结果处理
*/
@Aspect
@Component
java反射获取父类属性public class CustomValidatedAop {
@Autowired
protected Validator validator;
/**
* @desc 判断是否存在@CustomValidated注解
*/
@Before("@annotation(org.springframework.web.bind.annotation.PostMapping) || @annotation(org.springframework.web.bind.annotation.DeleteMapping) || @annotation(org.springframework.web.bind.annotation.PutMapping) || @annotation(org.s    public void doBefore(JoinPoint joinPoint) throws IOException {
//切⼊点⽅法参数
Object[] params = Args();
MethodSignature methodSignature = (MethodSignature) Signature();
Method method = Method();
//获取⽅法参数类型
Class<?>[] paramsType = ParameterTypes();
Set<String> errorMessages = new HashSet<>();
//获取⽅法参数上的注解(因为⽅法可以有多参数;参数上可以有注解,返回⼆维数组)
Annotation[][] an = ParameterAnnotations();
int index = 0;
//循环参数
for (Annotation[] an1 : an) {
Object param = params[index];
//循环参数上的注解
for (Annotation an2 : an1) {
//有⾃定义校验注解
if (an2 instanceof CustomValidated) {
/
/参数是List
if (param instanceof List) {
List list = (List) param;
for (Object l : list) {
errorMessages.addAll(this.beanValidator(l, ((CustomValidated) an2).value()));
}
} else {//参数⾮list
//获取该参数类型
Class clazz = paramsType[index];
//反射所有字段
Field[] fields = DeclaredFields();
for(Field field : fields){
ValidateObj validateObj = Annotation(ValidateObj.class);
//如果字段上有⾃定义注解@ValidateObj
if(validateObj != null){
field.setAccessible(true);
try {
Object obj = (param);
errorMessages.addAll(this.beanValidator(obj, ((CustomValidated) an2).value()));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
errorMessages.addAll(this.beanValidator(param, ((CustomValidated) an2).value()));
}
//执⾏分组校验  begin
Set<String> errorMessage = upNotEmpty(param,((CustomValidated) an2).operation());
if(errorMessage != null && errorMessage.size() > 0){
errorMessages.addAll(errorMessage);
}
//执⾏分组校验  end
//执⾏有条件动态校验  begin
Set<String> errorMessageCon = ditionalNotEmpty(param,((CustomValidated) an2).operation());                    if(errorMessageCon != null && errorMessageCon.size() > 0){
errorMessages.addAll(errorMessageCon);
}
//执⾏有条件动态校验  end
if (errorMessages.size() > 0) {
List rtnStr = new ArrayList<>();
rtnStr.addAll(errorMessages);
throw new BusinessException(this.listToString(rtnStr));
}
}
}
index++;
}
}
/**
* @desc 通过validator进⾏分组校验返回错误信息
*/
protected List<String> beanValidator(Object object, Class<?>... groups) {
List<String> errorMessages = new ArrayList();
try {
Set constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty()) {
actMessage(constraintViolations);
}
} catch (ConstraintViolationException ex) {
return errorMessages;
}
return errorMessages;
}
/**
* 转换Set<ConstraintViolation>为List<message>
*/
protected List<String> extractMessage(Set<? extends ConstraintViolation> constraintViolations) {
List<String> errorMessages = new ArrayList();
for (ConstraintViolation violation : constraintViolations) {
errorMessages.Message());
}
return errorMessages;
}
/**
* ⼯具⽅法 list转string
*/
protected String listToString(List<String> mList) {
String convertedListStr = "";
if (null != mList && mList.size() > 0) {
String[] mListArray = Array(new String[mList.size()]);
for (int i = 0; i < mListArray.length; i++) {
if (i < mListArray.length - 1) {
convertedListStr += mListArray[i] + ",";
} else {
convertedListStr += mListArray[i];
}
}
return convertedListStr;
} else {
return "";
}
}
/***
* Description: 分组校验属性不能同时为空
* @param
* @return
*/
protected Set<String> groupNotEmpty(Object param,String[] operation){
//本类及其⽗类的属性集合
List<Field> fieldList = new ArrayList<>() ;
Class tempClass = Class();
//递归获取本⾝及⽗类的属性
//当⽗类不是object并且为null的时候说明到达了最上层的⽗类(form继承的Entity类).
while (tempClass != null && !Name().toLowerCase().equals("java.lang.object")) {
//反射本类所有属性,包括私有属性
fieldList.addAll(Arrays.DeclaredFields()));
//得到⽗类,然后赋给⾃⼰
tempClass = Superclass();
}
// key--groupId value true 都为空 false 不全为空
Map<String, Boolean> isNotEmptyMap = new HashMap<>();
/
/ key--groupId value 所有message
Map<String, Set> emptyMessageMap = new HashMap<>();
for(Field field : fieldList){
GroupNotEmpty groupNotEmpty = Annotation(GroupNotEmpty.class);
if(groupNotEmpty != null){
//分组标识
String groupId = upIdentify();
if(StringUtils.isBlank(groupId)) {
groupId = ateUuid();
}
//操作标识
String[] operations = groupNotEmpty.operation();
//判断是否匹配controller中的校验操作
boolean isValidat = this.checkArray(operations,operation);
//不匹配跳出本次循环
if(isValidat){
continue;
}
//错误提⽰
String message = ssage();
field.setAccessible(true);
try {
/
/带GroupNotEmpty注解的字段的值
Object obj = (param);
boolean isNull = this.isNull(obj);
if (isNull) {
// 1. 为空则
if (ainsKey(groupId)) {
<(groupId).add(message);
} else {
isNotEmptyMap.put(groupId, true);
Set set = new HashSet();
set.add(message);
emptyMessageMap.put(groupId, set);
}
} else {
// 2. 不为空
isNotEmptyMap.put(groupId, false);
emptyMessageMap.put(groupId, new HashSet());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
Set returnSet = new HashSet();
for(String groupId: isNotEmptyMap.keySet()) {
if ((groupId)) {
returnSet.(groupId));
}
}
return returnSet;
}
/***
* Description: 校验当某属性属于特定值时,该注解字段校验⾮空
* @param
* @return
*/
protected Set<String> conditionalNotEmpty(Object param,String[] operation){
//本类及其⽗类的属性集合
List<Field> fieldList = new ArrayList<>() ;
Class tempClass = Class();
//递归获取本⾝及⽗类的属性
//当⽗类不是object并且为null的时候说明到达了最上层的⽗类(form继承的Entity类).
while (tempClass != null && !Name().toLowerCase().equals("java.lang.object")) {                //反射本类所有属性,包括私有属性
fieldList.addAll(Arrays.DeclaredFields()));
//得到⽗类,然后赋给⾃⼰
tempClass = Superclass();
}
Set returnSet = new HashSet();
try{
for(Field field : fieldList){
ConditionalNotEmpty conditionalNotEmpty = Annotation(ConditionalNotEmpty.class);                if(conditionalNotEmpty != null){
String ditionFiledName();
String ionString();
String[] prefixStrs=null;
if(StringUtils.isNotEmpty(contionString)){
prefixStrs=contionString.split(",");
}
//根据conditionFiledName 的值动态判断当前field是否需要不为空
boolean needCheckEmptyFlag=false;
//获取条件字段的值
Field conditionField = Class().getDeclaredField(conditionFiledName);
conditionField.setAccessible(true);
//该参数为想要获取值得对象
Object conditionFieldValue = (param);
for(String prefixStr:prefixStrs){
String().startsWith(prefixStr)){
/
/需要校验当前字段不为空
needCheckEmptyFlag=true;
}
}
if(needCheckEmptyFlag){
//操作标识
String[] operations = conditionalNotEmpty.operation();
//判断是否匹配controller中的校验操作
boolean isValidat = this.checkArray(operations,operation);
//不匹配跳出本次循环
if(isValidat){
continue;
}
//错误提⽰
String message = ssage();
field.setAccessible(true);
//带ConditionalNotEmpty注解的字段的值
Object obj = (param);
boolean isNull = this.isNull(obj);
if (isNull) {
returnSet.add(message);
}
}
}
}
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch(Exception e){
e.printStackTrace();
}
return returnSet;
}
//判空
protected boolean isNull(Object obj){
boolean isNull = false;
//字段是数组类型
if(obj instanceof java.lang.String[]){
String[] array = (String[]) obj;
if(array == null || array.length == 0){
isNull = true;
}
}
/
/字段是集合类型
else if(obj instanceof java.util.Collection){
Collection c = (Collection) obj;
if(c == null || c.size() == 0){
isNull = true;
}
}
//字段是其他对象类型
else {
if(obj == null){
isNull = true;
}else {
isNull = org.springframework.util.StringUtils.isEmpty(obj);
}
}
return isNull;
}
//判断⼀个数组中的元素是否在另⼀个数组中出现
private boolean checkArray(String [] array1,String [] array2){
boolean flag = true;
if((array1 != null && array1.length > 0) && (array2 != null && array2.length > 0)){            for(String s1 : array1){
ains(array2,s1)){
flag = false;
break;
}
}
}
return flag;
}
}
//
import java.lang.annotation.*;
/**
*
* @version 2018-09-29
* @desc 与Validated功能相仿只是把错误结果在aop中直接处理
*/
@Target({ ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface  CustomValidated {
Class<?>[] value() default {};
//业务操作标识 jiaor
String[] operation() default {};
}