自定义注解及AOP切面实现针对字段的特殊字符的校验

自定义注解及AOP切面实现针对字段的特殊字符的校验

1、 aspect 切面依赖包导入

<dependency>
    <groupId>org.aspectjgroupId>
    <artifactId>aspectjweaverartifactId>
    <version>1.9.5version>
dependency>

2、自定义注解

2.1 自定义一个方法注解

import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ValidatedMethodAnnotations {
}

2.2 自定义一个参数、字段注解,定义一个默认值,后面使用

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.PARAMETER})
public @interface ValidatedCharAnnotations {
    String value() default "";
}

注:上述的两个注解可以定义一个就行了,将ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER放在一个项即可。

3、切面实现校验业务

import com.ahdhst.commons.webmvc.exception.CommonException;
import com.ahdhst.lzz.lzt25.annotations.ValidatedCharAnnotations;
import com.ahdhst.lzz.lzt25.annotations.ValidatedMethodAnnotations;
import com.ahdhst.lzz.lzt25.enums.core.ResultEnum;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

@Component
@Aspect
@Slf4j
public class ValidatedAspect {

//指定一个或者多个controller,如果多个controller用“||”隔开即可
//within(com.ahdhst.lzz.lzt25.controller.cms.CmsInfoFileController)

/*
指定注解切面处理,希望在下列的方法中添加参数,在argNames指定。字段名与参数名一致。第一个* 表示返回值的类型任意;第二个* 或者.. 表示包名或者类名,.*(..) 表示任何方法名,括号表示参数,两个点表示任何参数类型
*/
    @Around(value = "(execution(* com.ahdhst.lzz.lzt25.controller.*.*.*(..))) && @annotation(megLog)", argNames = "joinPoint,megLog")
    public Object around(ProceedingJoinPoint  joinPoint, ValidatedMethodAnnotations megLog) throws Throwable {
        // System.out.println("aspect is run!!");
        //自定义注解下的方法参数信息获取
        Object[] args = joinPoint.getArgs();
        // 方法签名
        Signature signature1 = joinPoint.getSignature();
        // 获取的是代理类的method对象
        Method method1 = ( (MethodSignature)signature1 ).getMethod();
        // 这个方法才是目标对象上有注解的方法
        Method realMethod = joinPoint.getTarget().getClass().getDeclaredMethod(signature1.getName(), method1.getParameterTypes());

        // 取出对应的注解
        String name = "";
        int num = -1;
        Annotation[][] parameterAnnotations = realMethod.getParameterAnnotations();
        //锚
        A: for (Annotation[] annotations : parameterAnnotations) {
            for (Annotation annotation : annotations) {
                //获取注解名
                name = annotation.annotationType().getSimpleName();
                num = num + 1;
                if (name.equals("ValidatedCharAnnotations")){
                    break A;
                }
            }
        }
        //方法参数中注解为本人自定义的注解,获取该注解下的参数值,参数为一个对象,该对象中的字段,需要校验的,则加上自定义注解
        if(name.equals("ValidatedCharAnnotations")){
        //获取对象信息
            Object object = args[num];
            //获取对象属性
            Field[] fieldArr = object.getClass().getDeclaredFields();
            //校验错误集
            List<String> errorList = new ArrayList<>();
            //遍历属性,获取属性值
            for(Field objectField : fieldArr){
                //获取属性的类型
                String ftype = objectField.getGenericType().toString();
                //字符串输入校验特殊字符
                if(ftype.equals("class java.lang.String")){
                    //校验是否存在自定义注解的机制
                    ValidatedCharAnnotations vca = objectField.getAnnotation(ValidatedCharAnnotations.class);
                    if(null != vca){
                        //获取属性名称
                        String fname = objectField.getName();
                        //首字母大写处理
                        fname = fname.substring(0,1).toUpperCase()+fname.substring(1,fname.length());
                        //利用反射原理,调用getter方法获取属性值
                        Method m = object.getClass().getMethod("get"+fname);
                        String value = (String) m.invoke(object);    
                        //特殊字符开头的正则表达式
                        String regEx = "^[+ * \\[ \\] \\ < > ?]+.*";
                        if(Pattern.compile(regEx).matcher(value).matches()){
                        //vca.value():获取自定义注解的描述
                            errorList.add(vca.value()+":"+value+"存在特殊字符");
                        }
                        log.info("参数值:{},属性值:{}",vca.value(),value);
                    }
                }
            }
            if(CollectionUtils.isNotEmpty(errorList)){
                throw new CommonException(ResultEnum.ERROR_MESSAGE_SPECIAL_CHARACTER_EXIT,errorList.toString());
            }
            //已经通过的继续处理业务
            return joinPoint.proceed(args);
        } else {
            //没有这个注解的不验证,继续处理业务
            return joinPoint.proceed(args);
        }
    }
}

4、注解使用的场景

@ApiOperation(value = "人员信息列表接口", notes = "查询条件:用户名、姓名、所属机构")
    @GetMapping("/userList/{pageNum}/{pageSize}")
    @ValidatedMethodAnnotations //方法注解
    public DHResult<PageSerializable<UserInfoResult>> userList(@PathVariable Integer pageNum, @PathVariable Integer pageSize,@ValidatedCharAnnotations SearchUserParam param) { //参数注解
        return null;
    }
@ApiModel("员工列表查询入参")
@Data
public class SearchUserParam {

    @ApiModelProperty(value = "用户名")
    @ValidatedCharAnnotations("用户名") //字段注解
    private String phone;

    @ApiModelProperty(value = "姓名")
    private String realName;

    @ApiModelProperty(value = "所属机构id")
    private Integer orgId;

    @ApiModelProperty(value = "所属机构名称")
    private String orgName;

    @NotBlank
    @ApiModelProperty(value = "所属站点id", required = true)
    private String appId;

}

5、小结

基于spring boot框架,PostgreSQL数据库,针对特殊开头的条件搜索存在处理报错。由于项目场景比较多,想到了自定义注解、切面处理这类的问题。如有大佬们有好的思路,请指导一下小弟,小弟在此谢过了。

你可能感兴趣的:(JAVA代码片段,java,postgresql)