首页 > 其他 > 详细

Controller判断

时间:2021-06-06 16:43:26      阅读:17      评论:0      收藏:0      [点我收藏+]

Controller传入参数判断

起因:需要判断controller层前端传入参数是否为空情况,当时就想到利用SpringAOP来实现,主要有两个思路:

  1. 自定义注解在controller上加上需要判断的参数名
  2. 自定义注解在实体类中需要判断的属性上加上

选的是第一种方案,因为第二个方案需要改动代码,而且不太灵活

目前这个小练习还在开发中,gitee地址 https://gitee.com/sunankang/parameter-check 欢迎一起来开发

创建自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParameterCheckName {
    String name() default "";

    Class[] cls() default{};

    String[] names() default{};
}

如果想判断参数的话

//判断单值
@ParameterCheckName(name = "userName")
public ResultBody get(String userName){}

//判断多值
@ParameterCheckName(names = {"userName","className"})
public ResultBody get(String userName, String className){}

//判断类中某个属性
@ParameterCheckName(cls = Student.class,names={"Student.userName"}){}
public ResultBody get(Student student){}

//混合判断
@ParameterCheckName(clas = Student.class,names={"Student.userName","className"})
public ResultBody get(Student student,String className){}

然后就是利用SpringAop来进行增强

需要将这个类添加到Spring容器当中,否则不生效

@Aspect
@Component
public class AopCheckParameterConfig {
    //切入加上注解ParameterCheckName的方法
    @Before("@annotation(com.jame.parametercheck.annotation.ParameterCheckName)")
    public void test(JoinPoint joinPoint){}
}

首先第一步就是获取切入方法的参数,在网上查询了一下,获取参数的名称的话需要JDK1.8及以上,加入参数javac -parameters

开启此参数可以将编译后的class文件保留原码中的参数名,如果没有开启的话例如get(String name,String className)在运行中可能为

get(String var1,String var2),这样的话就没办法进行参数名称判断了

在idea中添加项目启动参数

技术分享图片

技术分享图片

然后就是一些正常的逻辑处理

/**
 * @author : Jame
 * @date : 2021-06-04 16:54
 **/
@Aspect
@Component
public class AopCheckParameterConfig {

    //存放为空的参数信息
    StringBuilder stringBuilder = new StringBuilder();

    //切入加上注解ParameterCheckName的方法
    @Before("@annotation(com.jame.parametercheck.annotation.ParameterCheckName)")
    public void test(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        //获取方法传入的参数
        Object[] args = joinPoint.getArgs();
        //获取方法传入参数的Class
        Class classes[] = new Class[args.length];

        for (int i = 0; i < classes.length; i++) {
            classes[i] = args[i].getClass();
        }

        //获取拦截的方法
        Method method = signature.getDeclaringType().getDeclaredMethod(signature.getName(), classes);

        //获取拦截方法上的注释
        ParameterCheckName annotationN = method.getAnnotation(ParameterCheckName.class);

  
        //使用ParameterCheckName进行判断
        if (annotationN != null) {
            //只传入一个参数名称判断
            if (!annotationN.name().equals("")) {
                //获取传入参数数组
                Parameter[] parameters = method.getParameters();
                for (int i = 0; i < parameters.length; i++) {
                    if (parameters[i].getName().equals(annotationN.name())) {
                        if (args[i] == null || args[i].equals(""))
                            stringBuilder.append(parameters[i].getName() + "-");
                    }
                }
                //类判断
            } else if (annotationN.cls().length != 0) {
                String[] names = annotationN.names();
                //存放类和类中属性名对应关系
                HashMap<String, ArrayList<String>> namesMap = new HashMap<>();

                for (int k = 0; k < names.length; k++) {
                    //需要判断类中属性
                    if (names[k].contains(".")) {
                        String[] split = names[k].split("\\.");
                        if (namesMap.get(split[0]) == null) {
                            ArrayList<String> strings = new ArrayList<>();
                            strings.add(split[1]);
                            namesMap.put(split[0], strings);
                        } else {
                            ArrayList<String> strings = namesMap.get(split[0]);
                            strings.add(split[1]);
                            namesMap.put(names[0], strings);
                        }
                    } else {
                        parametersCheck(method, args, names[k]);
                    }
                }
                //遍历多个类
                for (Class c : annotationN.cls()) {
                    //遍历参数
                    for (int i = 0; i < args.length; i++) {
                        if (args[i].getClass() == c) {
                            //获取具体类的所有属性
                            Field[] declaredFields = c.getDeclaredFields();
                            for (Field declaredField : declaredFields) {
                                ArrayList<String> strings = namesMap.get(c.getSimpleName());
                                for (String string : strings) {
                                    if (string.equals(declaredField.getName())) {
                                        Method methodAfter = c.getMethod("get" + captureName(declaredField.getName()), null);
                                        //String类型
                                        if (declaredField.getGenericType().toString().equals("class java.lang.String")) {
                                            String s = (String) methodAfter.invoke(args[i]);
                                            if (s == null || s.equals(""))
                                                stringBuilder.append(c.getSimpleName() + "." + declaredField.getName() + "-");
                                        } else if (declaredField.getGenericType().toString().equals("class java.lang.Integer")) {
                                            Integer s = (Integer) methodAfter.invoke(args[i]);
                                            if (s == null)
                                                stringBuilder.append(c.getSimpleName() + "." + declaredField.getName() + "-");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }


            }
            //多个参数名判断
            if (annotationN.cls().length == 0 && annotationN.names().length != 0) {
                String[] names = annotationN.names();
                for (String name : names) {
                    parametersCheck(method, args, name);
                }
            }
        }
        //抛出异常
        if (stringBuilder.length() != 0) {
            String s = stringBuilder.toString();
            //清空字符串
            stringBuilder.delete(0, stringBuilder.length());

            System.out.println(stringBuilder.toString());
            throw new ParameterException(666, "参数:" + s + "为空");
        }

    }

    public void parametersCheck(Method method, Object[] args, String name) {
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            if (parameters[i].getName().equals(name)) {
                if (args[i] == null || args[i].equals("")) {
                    stringBuilder.append(parameters[i].getName() + "-");
                }
            }
        }
    }

    private String captureName(String str) {
        // 进行字母的ascii编码前移,效率要高于截取字符串进行转换的操作
        char[] cs = str.toCharArray();
        cs[0] -= 32;
        return String.valueOf(cs);
    }
}

整体逻辑如下

技术分享图片

最后使用有SpringBoot全局异常处理来接收抛出的自定义异常

@ControllerAdvice
public class MyExceptionHandler{
    
    @ResponseBody
    @ExceptionHandler(value = ParameterException.class)
    public ResultBody exceptionHandler(ParameterException e){
        ResultBody resultBody = new ResultBody();
        resultBody.setMessage(e.getMessage());
        resultBody.setCode(e.getCode());
        return resultBody;
    }
}

但是呢,目前这个项目还有很多问题:

1.现在还不能判断基本数据类型

2.如果传入Integer的参数为空,就直接报400,试过在Mapping添加required=false,JoinPoint获取不到这个参数(主要解决)

Controller层

@GetMapping("/get")
@ParameterCheckName(names = {"id","name"})
public String get(@RequestParam(value = "id" ) Integer id,
                  @RequestParam(value = "name" ) String name) {
    return "完成,返回结果";
}

切入类

public void test(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        //
        Object[] args = joinPoint.getArgs();
}

String类型没有传入可以检测到

技术分享图片

技术分享图片

而Integer不传入则报错400,在Mapping添加required=false

技术分享图片

获取不到Integer的参数,就很难受,大家有什么解决方案可以来一起开发

https://gitee.com/sunankang/parameter-check

Controller判断

原文:https://www.cnblogs.com/sunankang/p/14855403.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!