定义注解 DictRetun
代码语言:javascript复制import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 此注解将会给方法加上标记,以触发读取方法参数是否有AppendFileldDesc注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER}) // 仅仅作用在入参上
public @interface DictRetun {
}
定义注解 DictFild
代码语言:javascript复制import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DictFild {
}
定义织入
代码语言:javascript复制import com.zanglikun.springdataredisdemo.aop.dictAop.annotation.DictFild;
import com.zanglikun.springdataredisdemo.aop.dictAop.annotation.DictRetun;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
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 javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
@Aspect // 声明切面类
@Component // 注册为Spring组件,不然切面类不生效,这里我是先关闭了,你使用请务必开启
@Slf4j
public class DictAdvice {
/**
* Pointcut 定义切入点,一般为方法级别。通过切点表达式体现。
* A原表达式:execution(public * com.zanglikun.springdataredisdemo.controller..*.*(..))
* A表达式是切入 com.zanglikun.springdataredisdemo.controller 下面所有的Public方法
* <p>
* 一般还有匹配注解的如:@annotation(com.zanglikun.springdataredisdemo.aop.fileLimitAop.FileLimit)
* 就是切入被FileLimit的注解
*/
@Pointcut("@annotation(com.zanglikun.springdataredisdemo.aop.dictAop.annotation.DictRetun)")
public void dictPointcut() {
}
// 定一个变量,以便于全局获得模拟的DB返回的字典信息
HashMap<String, HashMap<String, Object>> returnMap = new HashMap<>();
// 自己主动去缓存Cache Code=Name oldValue NewValue
HashMap<String, HashMap<String, Object>> getDictionary() {
HashMap<String, Object> dbReturn = new HashMap<>();
dbReturn.put("1", "张三");
dbReturn.put("2", "李四");
dbReturn.put("3", "刘能");
returnMap.put("name", dbReturn);
return returnMap;
}
/**
* 环绕通知
* 理解点1:joinPoint.proceed()作用是:执行被拦截的方法。
* 为什么叫环绕通知呢?我们一般在joinPoint.proceed()。上下位置放置我们要执行的代码,可以实现在方法前、后执行代码
*
* @param joinPoint 切点 注意Around的joinPoint 可以与其他的实现JoinPoint不一样
* @return 返回的内容未来要返回给前端使用哦
* @throws Throwable
* @Around("onePointCut()") 这种定义切入点方式和直接在@Around里面声明具体得切入点表达式一样
*/
@Around("dictPointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Object proceed = joinPoint.proceed();//调用被切入方法,并获取其返回值
Object joinPointInfo = getJoinPointInfo(joinPoint, proceed);
return joinPointInfo;
}
/**
* 替换字典的操作
* @param joinPoint 切点信息
* @param returnRes 方法返回的内容
* @return 处理returnRes后再返回
*/
public Object getJoinPointInfo(JoinPoint joinPoint, Object returnRes) {
// 这串代码的含义是获取HttpServletRequest、HttpServletResponse获取的是本线程的哦
{
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
}
Object[] args = joinPoint.getArgs(); // 获取方法的所有入参值,但是无法准确获取入参类型,但是要去修改属性值,必须得获取对象
for (Object arg : args) {
System.out.println(arg);
}
// 获取AOP签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod(); // 获取被调用的方法
Class<?> returnType = method.getReturnType(); // 获取返回值的类型
Parameter[] parameters = method.getParameters(); // 获取方法的入参
for (Parameter parameter : parameters) {
parameter.getName(); // 获取参数名称例如:User user 获取的是user
Annotation[] classAnnotations = parameter.getAnnotations(); // 获取该入参的所有注解
Class<?> type = parameter.getType(); // 获取入参的字节码文件以便于快速获得变量的属性
if (parameter.isAnnotationPresent(DictRetun.class)) { // 如果该变量被DictRetun修饰了,才会执行
Field[] declaredFields = type.getDeclaredFields(); // 获取该变量的所有属性列表
for (Field declaredField : declaredFields) {
if (declaredField.isAnnotationPresent(DictFild.class)) { // 如果变量被DictFild修饰后,才执行
// 开始替换为字典值
try {
declaredField.setAccessible(true);
Object o = declaredField.get(returnRes);
if (o instanceof String) {
getDictionary(); // 初始化数据
HashMap<String, Object> stringObjectHashMap = returnMap.get(declaredField.getName());
declaredField.set(returnRes, stringObjectHashMap.get(o));
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} finally {
declaredField.setAccessible(false);
}
}
}
}
}
return returnRes;
}
}
定义实体 User
代码语言:javascript复制@Data
@AllArgsConstructor
@NoArgsConstructor
public class User{
@DictFild
private String name;
}
测试代码
代码语言:javascript复制 @PostMapping("/testArgsAnno")
@ResponseBody
public User testArgsAnno(@DictRetun @RequestBody User user) {
return user;
}
测试结果
结果1
代码语言:javascript复制【入参】:
{
"name": "1"
}
【出参】:
{
"name": "张三"
}
结果2
代码语言:javascript复制【入参】:
{
"name": "2"
}
【出参】:
{
"name": "李四"
}