开发者

springboot如何通过自定义注解对方法参数进行拦截验证

目录
  • springboot通过自定义注解对方法参数进行拦截验证
    • 元注解参数说明
    • @Target类型和说明
  • 具体实现:简单版
    • 具体实现:封装版
      • 总结

        sprhttp://www.devze.comingboot通过自定义注解对方法参数进行拦截验证

        元注解参数说明

        • @Target 定义注解的作用目标,也就是可以定义注解具体作用在类上,方法上,还是变量上
        • @Retention 定义注解的保留策略
        RetentionPolicy.SOURCE注解仅存在于源码中在class字节码文件中不包含
        RetentionPolicy.CLASS默认的保留策略注解会在class字节码文件中存在但运行时无法获得;
        RetentionPolicy.RUNTIME注解会在class字节码文件中存在,在运行时可以通过反射获取到。
        • @Document 说明该注解将被包含在Javadoc中
        • @Inherited 说明子类可以继承父类中的该注解

        @Target类型和说明

        类型说明
        ElementType.TYPE接口、类、枚举、注解
        ElementType.FIELD字段、枚举的常量
        ElementType.METHOD方法
        ElementType.PARAMETER方法参数
        ElementType.CONSTRUCTOR构造函数
        ElementType.LOCAL_VARIABLE局部变量
        ElementType.ANNOTATION_TYPE注解
        ElementType.PACKAGE

        具体实现:简单版

        1、引入坐标

        <!-- 引入aop切面支持 -->
        <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        2、创建自定义注解

        package com.hk.annotation;
         
        import java.lang.annotation.*;
         
        @Target({ElementType.METHOD})
        @Retention(RetentionPolicy.RUNTIME)
        @Inherited
        public @interface ParamsIntercept {
          
        }
        • @Target注解指定ElementType
        • @Inherited 说明子类可以继承父类中的该注解
        • @Retention注解指定RetentionPolicy

        注意:

        注解支持的元素类型除了上面的String之外还有以下:

        • 基本类型(int、char、byte、double、float、long、boolean)
        • 字符串String
        • 类Class
        • 枚举enum
        • 注解Annotation
        • 上述类型的数组类型

        当使用其他类型修饰注解元素时,编译期会报错

        Invalid type 'Integer' for annotation member

        基本类型的包装类型也是不允许在注解中修饰注解元素的;上述代码中 subjectId 不能 定义为 Integer

        3、创建切面进行判断

        import com.alibaba.fastjson.JSONObject;
        import com.bxm.adsmanager.model.dao.user.User;
        import org.apache.commons.lang.ArrayUtils;
        import org.apache.commons.lang3.StringUtils;
        import org.apache.log4j.Logger;
        import org.ASPectj.lang.JoinPoint;
        import org.aspectj.lang.annotation.Aspect;
        import org.aspectj.lang.annotation.Before;
        import org.aspectj.lang.reflect.MethodSignature;
        import org.springframework.stereotype.Component;
          
        import javax.servlet.http.HttpServletRequest;
        import java.lang.reflect.Method;
          
        @Aspect
        @Component
        public class ParamsBeforeAspect {
          
            private static final Logger logger = Logger.getLogger(ParamsBeforeAspect .class);
          
            @Before("@annotation(com.hk.annotation.ParamsIntercept)")
            public void doBefore(JoinPoint point){
                try {
                    long startTime = System.currentTimeMillis();//开始时间
                    Method method = getMethod(point);
                    if(null == method){
                        if(logger.isWarnEnabled()){
                            logger.warn("method is null");
                        }
                        return;
                    }            
         
                    Object[] args = point.getArgs();//获取请求参数
                    
                    if (ArrayUtils.isNotEmpty(args)) {
                        for (Object arg : args) {
                           // 对参数进行判断
                        }
                    }
          
                    long endTime = System.currentTimeMillis();//结束时间
                    float excTime=(float)(endTime-startTime)/1000;
                    logger.info("总耗时:" + excTime+"s");
                }catch (Exception e){
                    logger.error("记录日志异常",e);
                }
            } 
         
            private Method getMethod(JoinPoint point) {
                MethodSignature methodSignature = (MethodSignature) point.getSignature();
                Class<?> targetClass = point.getTarget().getClass();
                try {
                    return targetClass.getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
                } catch (NoSuchMethodException e) {
                    return null;
                }
            }

        4nhZNKtjHm、controller使用

        @Controller
        @RequestMapping(value = "/")
        public class UserManagerController {
            //1.传入的是一个具体的值
        	@ParamsIntercept
            @RequestMapping(value = "/getUser/{subjectId}")
            public R<String> getUserDetail(@PathVariable Integer subjectId) {
                try {
                    //处理自己的业务
         编程客栈       } catch (Exception e) {
                    e.printStackTrace();
                    return R.error(e.getMessage());
                }
                return R.error("操作失败");
            }
           
        }         

        具体实现:封装版

        1、引入坐标

        <!-- 引入aop切面支持 -->
        <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        2、创建自定义注解

        package com.hk.annotation;
         
        import java.lang.annotation.*;
         
        @Target({ElementType.METHOD})
        @Retention(RetentionPolicy.RUNTIME)
        @Inherited
        public @interface ParamsIntercept {
          String subjectId();
        }

        3、创建切面

        package com.hk.aspect;
         
        import com.warmer.base.enums.ReturnStatus;
        import com.warmer.base.util.R;
        import com.warmer.base.util.SpringUtils;
        import com.warmer.base.util.StringUtil;
        import com.warmer.web.annotation.AnnotationResolver;
        import com.warmer.web.annotation.DomainOwner;
        import com.warmer.web.entity.KgDomain;
        import com.warmer.web.security.TokenService;
        import com.warmer.web.service.KnowledgeGraphService;
        import org.aspectj.lang.ProceedingJoinPoint;
        import org.aspectj.lang.annotation.Around;
        import org.aspectj.lang.annotation.Aspect;
        import org.aspectj.lang.annotation.Pointcut;
        import org.aspectj.lang.reflect.MethodSignature;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.sprinphpgframework.stereotype.Component;
        import org.springframework.web.context.request.RequestContextHolder;
        import org.springframework.web.context.request.ServletRequestAttributes;
         
        import javax.servlet.http.HttpServletRequest;
        import java.util.List;
         
        @Aspect
        @Component
        public class DomainValidAspect {
         
            @Pointcut("@annotation(com.hk.annotation.ParamsIntercept)")
            public void annotationPointCut() {
         
            }
         
            @Before("annotationPointCut()")
            public void doBefore(JoinPoint joinPoint) {
                MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                // 获取方法注解
                ParamsIntercept paramsIntercept = signature.getMethod().getAnnotation(ParamsIntercept.class);
                // 获取参数
                String subjectIdCode = paramsIntercept.subjectId();
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = servletRequestAttributes.getRequest();
                Integer memberId = (Integer) request.getAttribute("memberId");
                AnnotationResolver annotationResolver = AnnotationResolver.newInstance();
                Integer resolver = (Integer) annotationResolver.resolver(joinPoint, subjectIdCode);
                log.info("获取请求参数:subjectId:{}, memberId:{}", resolver, memberId);
                // 具体业务代码
                .......
            }
        }
         

        4、封装获取参数工具

        package com.hk.aspect;
        
        import org.aspectj.lang.JoinPoint;
        import org.aspectj.lang.reflect.MethodSignature;
        
        import java.lang.reflect.Method;
        import java.util.Map;
        
        /**
         * @description:
         * @author: HK
         * @since: 2024/9/25 15:16
         */
        public class AnnotationResolver {
            private static AnnotationResolver resolver ;
            public static AnnotationResolver newInstance(){
                if (resolver == null) {
                    return resolver = new AnnotationResolver();
                }else{
                    return resolver;
                }
            }
            
            public Object resolver(JoinPoint joinPoint, String str) {
        
                if (str == null) return null ;
        
                Object value = null;
                if (str.matches("#\\{\\D*\\}")) {
                    String newStr = str.replaceAll("#\\{", "").replaceAll("\\}", "");
                    if (newStr.contains(".")) { // 复杂类型
                        try {
                            value = complexResolver(joinPoint, newStr);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } else {
                        value = simpleResolver(joinPoint, newStr);
                    }
                } else { //非变量
                    value = str;
                }
                return value;
            }
        
        
            private Object complexResolver(JoinPoint joinPoint, String str) throws Exception {
                MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
                String[] names = methodSignature.getParameterNames();
                Object[] args = joinPoint.getArgs();
                String[] strs = str.split("\\.");
        
                for (int i = 0; i < names.length; i++) {
                    if (strs[0].equals(names[i])) {
                        Object obj = args[i];
                        //这里处理出入参数为Map的逻辑
                        if(obj instanceof Map){
                            Map item=(Map) obj;
                            return item.get(strs[1]);
                        }
                        Method dmethod = obj.getClass().getDeclaredMethod(getMethodName(strs[1]), null);
                        Object value = dmethod.invoke(args[i]);
                        return getValue(value, 1, strs);
                    }
                }
                return null;
            }
        
            private Object getValue(Object obj, int index, String[] strs) {
                try {
                    if (obj != null && index < strs.length - 1) {
                        Method method = obj.getClass().getDeclaredMethod(getMethodName(strs[index + 1]), null);
                        obj = method.invoke(obj);
                        getValue(obj, index + 1, strs);
                    }
                    return obj;
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        
            private String getMethodName(String name) {
                return "get" + name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toUpperCase()python);
            }
            private Object simpleResolver(JoinPoint joinPoint, String str) {
                MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
                String[] names = methodSignature.getParameterNames();
                Object[] args = joinPoint.getArgs();
        
                for (int i = 0; i < names.length; i++) {
                    if (str.equals(names[i])) {
                        return args[i];
                    }
                }
                return null;
            }
        
        }

        5、controller使用

        @Controller
        @RequestMapping(value = "/")
        public class UserManagerController {
            //1.传入的是一个具体的值
        	@ParamsIntercept(subjectId= "#{userCode}")
            @RequestMapping(value = "/getUser/{subjectId}")
            public R<String> getUserDetail(@PathVariable Integer subjectId) {
                try {
                    //处理自己的业务
                } catch (Exception e) {
                    e.printStackTrace();
                    return R.error(e.getMessage());
                }
                return R.error("操作失败");
            }
            //2.传入的是一个对象
            @ParamsIntercept(subjectId= "#{userItem.subjectId}")
            
        	//3.传入的可能是一个map
         	@ParamsIntercept(subjectId= "#{params.subjectId}")
           
        }         

        总结

        以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

        0

        上一篇:

        下一篇:

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        最新开发

        开发排行榜