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)。
精彩评论