该篇以记录接口调用的传入参数日志为场景,来介绍下使用自定义注解作为切点,AOP切面方式去记录每个接口的传入参数以及可扩展的业务处理。
项目目录:
先是创建自定义注解, LogTrack:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author : JCccc
* @CreateTime : 2020/4/13
* @Description :
**/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogTrack {
String value() default "logTracking";
}
上面的自定义注解,我只用了一个默认参,所以不用命名,写value就可以。
然后写切点对应的代码,LogTrackAspect:
用到了fastjson,导入依赖:
com.alibaba
fastjson
1.2.58
/**
* @Author : JCccc
* @CreateTime : 2020/4/13
* @Description :
**/
@Component
@Aspect
public class LogTrackAspect {
private static final Logger log = LoggerFactory.getLogger(LogTrackAspect.class);
//这里需要注意了,这个是将自己自定义注解作为切点的根据,路径一定要写正确了
@Pointcut(value = "@annotation(com.jc.mytest.aop.logRecord.LogTrack)")
public void access() {
}
//进来切点世界,先经过的第一个站
@Before("access()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
System.out.println("-aop 日志记录启动-" + new Date());
}
//环绕增强,是在before前就会触发
@Around("@annotation(logTrack)")
public Object around(ProceedingJoinPoint pjp, LogTrack logTrack) throws Throwable {
System.out.println("-aop 日志环绕阶段-" + new Date());
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// GET 请求其实可以从request里获取出参数
// Map map=request.getParameterMap();
// System.out.println("获取参数:"+map.get("username")[0])
String url = request.getRequestURL().toString();
String ip = IpUtil.getIpAddr(request);
String logTrackValue = logTrack.value();
Object[] pipArrary = pjp.getArgs();
if (pipArrary.length>1){ //多参,不是Map/JsonObject方式
List
ps:return pjp.proceed(); 这个是从切点的环绕增强里面脱离出来,接下来会进入before阶段 ,然后回到接口,再回来after阶段。
所以扩展业务逻辑处理的话,可以放在return pjp.proceed();这行代码之前,例如判断用户密码是否正确;判断用户权限等等。
接下来是在Controller编写接口,并用上自定义注解,MyTestController:
/**
* @Author : JCccc
* @CreateTime : 2020/3/27
* @Description :
**/
@Controller
@RequestMapping("/test")
public class MyTestController {
@ResponseBody
@GetMapping("/testGet1")
@LogTrack("testGet1 接口")
public void testGet1(@RequestParam("userId") String userId, @RequestParam("toUserId") String toUserId) {
System.out.println("已经进入GET测试接口,参数userId:" + userId+ "参数toUserId:"+toUserId);
}
@ResponseBody
@GetMapping("/testGet2")
@LogTrack("testGet2 接口")
public void testGet2(@RequestParam Map map) {
System.out.println("已经进入GET测试接口,参数:" + map.get("userId"));
}
@ResponseBody
@PostMapping("/testPost1")
@LogTrack("testPost1 接口")
public void testPost1(@RequestBody Map map) {
System.out.println("已经进入POST测试接口,参数:" + map.toString());
}
@ResponseBody
@PostMapping("/testPost2")
@LogTrack("testPost2 接口")
public void testPost2(@RequestBody JSONObject jsonObject) {
System.out.println("已经进入POST测试接口,参数:" + jsonObject.toString());
}
}
然后我们来运行一下,看看控制台,就知道整个切点以及环绕的流程了:
首先是测试GET方式的接口,通过@RequestParam单个参数获取的情况:
调用接口:
运行结果:
接下来还是GET方式 ,通过Map去接收多参:
调用接口:
运行结果:
然后是调用Post请求:
ps: 如果发现按照上面配置了,但是aop切点的方法好像没触发,
那么可以试试
1.检查jar包是否有导入正确
org.aspectj
aspectjweaver
1.9.4
org.aspectj
aspectjrt
1.8.9
2.在启动类上加上注解@EnableAspectJAutoProxy 这个其实springboot是默认帮我们已经开启为true状态的。
本篇使用到的一些工具类:
IpUtil:
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @Author : JCccc
* @CreateTime : 2018-11-23
* @Description :
* @Point: Keep a good mood
**/
public class IpUtil {
public static String getIpAddr(HttpServletRequest request) {
String ipAddress = null;
try {
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1")) {
// 根据网卡取本机配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
ipAddress = inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
// = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
} catch (Exception e) {
ipAddress="";
}
// ipAddress = this.getRequest().getRemoteAddr();
return ipAddress;
}
}