java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > springboot通过自定义注解对方法参数进行拦截验证

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

作者:蓝眸少年CY

这篇文章主要介绍了springboot如何通过自定义注解对方法参数进行拦截验证问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

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

元注解参数说明

RetentionPolicy.SOURCE注解仅存在于源码中在class字节码文件中不包含
RetentionPolicy.CLASS默认的保留策略注解会在class字节码文件中存在但运行时无法获得;
RetentionPolicy.RUNTIME注解会在class字节码文件中存在,在运行时可以通过反射获取到。

@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 {
  
}

注意:

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

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

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;
        }
    }

4、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.springframework.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());
    }
    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}")
   
}         

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文