springboot如何通過自定義注解對(duì)方法參數(shù)進(jìn)行攔截驗(yàn)證
springboot通過自定義注解對(duì)方法參數(shù)進(jìn)行攔截驗(yàn)證
元注解參數(shù)說明
@Target
定義注解的作用目標(biāo),也就是可以定義注解具體作用在類上,方法上,還是變量上@Retention
定義注解的保留策略
RetentionPolicy.SOURCE | 注解僅存在于源碼中在class字節(jié)碼文件中不包含 |
RetentionPolicy.CLASS | 默認(rèn)的保留策略注解會(huì)在class字節(jié)碼文件中存在但運(yùn)行時(shí)無法獲得; |
RetentionPolicy.RUNTIME | 注解會(huì)在class字節(jié)碼文件中存在,在運(yùn)行時(shí)可以通過反射獲取到。 |
@Document
說明該注解將被包含在javadoc中@Inherited
說明子類可以繼承父類中的該注解
@Target類型和說明
類型 | 說明 |
ElementType.TYPE | 接口、類、枚舉、注解 |
ElementType.FIELD | 字段、枚舉的常量 |
ElementType.METHOD | 方法 |
ElementType.PARAMETER | 方法參數(shù) |
ElementType.CONSTRUCTOR | 構(gòu)造函數(shù) |
ElementType.LOCAL_VARIABLE | 局部變量 |
ElementType.ANNOTATION_TYPE | 注解 |
ElementType.PACKAGE | 包 |
具體實(shí)現(xiàn):簡(jiǎn)單版
1、引入坐標(biāo)
<!-- 引入aop切面支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2、創(chuàng)建自定義注解
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
- 上述類型的數(shù)組類型
當(dāng)使用其他類型修飾注解元素時(shí),編譯期會(huì)報(bào)錯(cuò)
Invalid type 'Integer' for annotation member
基本類型的包裝類型也是不允許在注解中修飾注解元素的;上述代碼中 subjectId 不能 定義為 Integer
3、創(chuàng)建切面進(jìn)行判斷
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();//開始時(shí)間 Method method = getMethod(point); if(null == method){ if(logger.isWarnEnabled()){ logger.warn("method is null"); } return; } Object[] args = point.getArgs();//獲取請(qǐng)求參數(shù) if (ArrayUtils.isNotEmpty(args)) { for (Object arg : args) { // 對(duì)參數(shù)進(jìn)行判斷 } } long endTime = System.currentTimeMillis();//結(jié)束時(shí)間 float excTime=(float)(endTime-startTime)/1000; logger.info("總耗時(shí):" + 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.傳入的是一個(gè)具體的值 @ParamsIntercept @RequestMapping(value = "/getUser/{subjectId}") public R<String> getUserDetail(@PathVariable Integer subjectId) { try { //處理自己的業(yè)務(wù) } catch (Exception e) { e.printStackTrace(); return R.error(e.getMessage()); } return R.error("操作失敗"); } }
具體實(shí)現(xiàn):封裝版
1、引入坐標(biāo)
<!-- 引入aop切面支持 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2、創(chuàng)建自定義注解
package com.hk.annotation; import java.lang.annotation.*; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ParamsIntercept { String subjectId(); }
3、創(chuàng)建切面
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); // 獲取參數(shù) 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("獲取請(qǐng)求參數(shù):subjectId:{}, memberId:{}", resolver, memberId); // 具體業(yè)務(wù)代碼 ....... } }
4、封裝獲取參數(shù)工具
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(".")) { // 復(fù)雜類型 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]; //這里處理出入?yún)?shù)為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.傳入的是一個(gè)具體的值 @ParamsIntercept(subjectId= "#{userCode}") @RequestMapping(value = "/getUser/{subjectId}") public R<String> getUserDetail(@PathVariable Integer subjectId) { try { //處理自己的業(yè)務(wù) } catch (Exception e) { e.printStackTrace(); return R.error(e.getMessage()); } return R.error("操作失敗"); } //2.傳入的是一個(gè)對(duì)象 @ParamsIntercept(subjectId= "#{userItem.subjectId}") //3.傳入的可能是一個(gè)map @ParamsIntercept(subjectId= "#{params.subjectId}") }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Intellij IDEA 配置Subversion插件實(shí)現(xiàn)步驟詳解
這篇文章主要介紹了Intellij IDEA 配置Subversion插件實(shí)現(xiàn)步驟詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05springboot~nexus項(xiàng)目打包要注意的地方示例代碼詳解
這篇文章主要介紹了springboot~nexus項(xiàng)目打包要注意的地方,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07eclipse maven maven-archetype-webapp 創(chuàng)建失敗問題解決
這篇文章主要介紹了eclipse maven maven-archetype-webapp 創(chuàng)建失敗問題解決的相關(guān)資料,需要的朋友可以參考下2016-12-12關(guān)于springboot的跨域配置問題的解決方案
這篇文章主要介紹了關(guān)于springboot的跨域配置問題,處理filter,spring?security等過濾器跨域問題,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07Java服務(wù)剛啟動(dòng)時(shí)接口超時(shí)排查全過程
這篇文章主要為大家介紹了Java服務(wù)剛啟動(dòng)時(shí),一小波接口超時(shí)排查全過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07