您的位置:首页 > 游戏 > 手游 > 郓城网页设计_上海网站建设公司兴田德润可以不_建网站多少钱_深圳谷歌seo推广

郓城网页设计_上海网站建设公司兴田德润可以不_建网站多少钱_深圳谷歌seo推广

2024/12/23 15:01:42 来源:https://blog.csdn.net/qq_42108331/article/details/142657102  浏览:    关键词:郓城网页设计_上海网站建设公司兴田德润可以不_建网站多少钱_深圳谷歌seo推广
郓城网页设计_上海网站建设公司兴田德润可以不_建网站多少钱_深圳谷歌seo推广

说明:在一些时候,我们需要在接口介绍到参数前处理参数,像参数校验、参数转换等,本文介绍如何使用AOP来实现此需求。

场景

需求:有一批开放给第三方调用的接口,之前传递的都是用户表的ID,现在需要换成用户表的用户名。如下:

@RestController
@RequestMapping("user")
public class UserController {@Autowiredprivate UserMapper userMapper;@GetMapping("{id}")public User getUser(@PathVariable String id) {return userMapper.selectUserById(id);}
}

在这里插入图片描述

一般思维,我们可以在响应的接口前,调用一个方法,根据传递的用户名去查询用户表,返回用户ID。这样,所有需要修改的地方,都需要加上这个方法,代码侵入大,不易维护,不优雅。

使用AOP

使用AOP,我们可以考虑在相应的接口上,打上一个自定义注解,表示改接口需要进行处理,然后在对应的参数上,再打上一个注解,表示需要对该参数进行处理,

首先,创建三个注解,如下:

(接口注解,打在接口上,表示需要处理的接口)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InterfaceAnnotation {
}

(参数注解,打在参数上,表示需要处理的参数)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamAnnotation {
}

(字段注解,如果参数是对象,打在对象的属性上,表示取出该对象的这个属性处理)

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

重点是切面,切面要做的是取出对应的参数值,进行转换,然后再赋值回去,需要考虑参数是单个字段、对象这两种情况,如下:

import com.hezy.annotation.FieldAnnotation;
import com.hezy.annotation.ParamAnnotation;
import com.hezy.mapper.UserMapper;
import com.hezy.pojo.UserDTO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;@Aspect
@Component
public class UsernameToIdAspect {@Autowiredprivate UserMapper userMapper;@Around("@annotation(com.hezy.annotation.InterfaceAnnotation)")public Object resolveUsernameToId(ProceedingJoinPoint joinPoint) throws Throwable {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();// 获取方法参数列表Object[] args = joinPoint.getArgs();// 获取方法参数的注解,这里是二位数组,是因为一个参数可以有多个注解Annotation[][] parameterAnnotations = method.getParameterAnnotations();// 遍历每个注解for (int i = 0; i < parameterAnnotations.length; i++) {// 遍历注解,判断是否有ParamAnnotation注解for (Annotation annotation : parameterAnnotations[i]) {// 如果有ParamAnnotation注解if (annotation instanceof ParamAnnotation) {// 获取该对象的属性值String username = (String) args[i];// 将根据username查询后的accountId赋值给这个参数args[i] = getUserIdByUsername(username);}}// 参数如果是对象if (args[i] instanceof UserDTO) {// 获取对象的所有属性,并遍历Field[] declaredFields = args[i].getClass().getDeclaredFields();for (Field field : declaredFields) {// 如果有 FieldAnnotation 注解if (field.getAnnotation(FieldAnnotation.class) != null) {// 设置属性为可访问的field.setAccessible(true);// 获取该对象的属性值String username = (String) field.get(args[i]);// 将根据username查询后的accountId赋值给该对象的id字段Field accountId = args[i].getClass().getDeclaredField("id");accountId.setAccessible(true);accountId.set(args[i], getUserIdByUsername(username));}}}}return joinPoint.proceed(args);}/*** 根据username去查userId*/private String getUserIdByUsername(String username) {String userId = userMapper.selectIdByUsername(username);if (userId == null) {throw new RuntimeException("操作失败,该账户不存在");}return userId;}
}

测试

根据username查id

    @Select("select id from i_users where username = #{username}")String selectIdByUsername(@Param("username") String username);

启动项目,传username,可以看到,也能查出数据,说明转换成功了。完全不用去修改原来的代码。

在这里插入图片描述

再试下传入一个对象,将对象里面的username字段取出来,然后查出id,赋值给原对象。这样就不影响原来逻辑了。

    @InterfaceAnnotation@DeleteMappingpublic void deleteUserByUsername(@RequestBody UserDTO userDTO) {userMapper.deleteUserByUsername(userDTO);}

别忘了要在对象属性上打注解

import com.hezy.annotation.FieldAnnotation;
import lombok.Data;import java.io.Serializable;@Data
public class UserDTO implements Serializable {private String id;@FieldAnnotationprivate String username;private String password;
}

只传个username

在这里插入图片描述

断点打在获取参数后,可以看到id已经补上了,说明切面起作用了。

在这里插入图片描述

总结

本文介绍了AOP的一个使用场景,另外使用AOP还可以解决很多问题,像记录接口访问日志、接口鉴权、补全用户信息(类似上面的)。

完整源码:https://github.com/HeZhongYing/aop_use_demo

AOP技术介绍,参考下面这边博客:

  • AOP技术

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com