需求描述:
在所有的接口中记录客户端发送过来的请求。记录信息包括:
- 请求链接
- 请求类型
- 请求IP
- 请求描述等…
实现效果:
1、自定义注解
package com.nys.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解-API监控
* @author nysheng
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiEyes {
String value() default "";
}
2、AOP实现
package com.nys.aop;
import com.nys.annotation.ApiEyes;
import com.nys.utils.IPUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.lang.reflect.Method;
/**
* AOP实现-切入所有被注解@ApiEyes标记的方法
* @author nysheng
*/
@Aspect
@Component
public class MyAspect {
//日志记录
private Logger logger= LoggerFactory.getLogger(MyAspect.class);
//切入点配置为注解@ApiEyes
@Pointcut("@annotation(com.nys.annotation.ApiEyes)")
public void apiEyes(){}
/**
* 环绕通知
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("apiEyes()")
public Object before(ProceedingJoinPoint joinPoint) throws Throwable {
//1.请求开始
logger.info("=====请求进入======");
long start=System.currentTimeMillis();
//2.获取注解对象
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature=(MethodSignature)signature;
Method method = methodSignature.getMethod();
ApiEyes apiEyes = method.getAnnotation(ApiEyes.class);
//3.获取注解属性
String value = apiEyes.value();
//4.获取request
ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
//5.记录日志
logger.info("请求链接:{}",request.getRequestURL().toString());
logger.info("请求类型:{}",request.getMethod());
logger.info("请求IP:{}",IPUtil.getIpAddress(request));
logger.info("请求描述:{}",value);
//6.执行
Object object=joinPoint.proceed();
//7.请求结束
long end=System.currentTimeMillis();
logger.info("请求用时:{}",(end-start));
logger.info("=====请求结束======");
return object;
}
}
3、获取IP
package com.nys.utils;
import javax.servlet.http.HttpServletRequest;
/**
* IP工具类,获取客户端请求的真实IP地址
* @author nysheng
*/
public class IPUtil {
public static String getIpAddress(HttpServletRequest request) {
String ip = null;
//X-Forwarded-For:Squid 服务代理
String ipAddresses = request.getHeader("X-Forwarded-For");
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//Proxy-Client-IP:apache 服务代理
ipAddresses = request.getHeader("Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//WL-Proxy-Client-IP:weblogic 服务代理
ipAddresses = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//HTTP_CLIENT_IP:有些代理服务器
ipAddresses = request.getHeader("HTTP_CLIENT_IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//X-Real-IP:nginx服务代理
ipAddresses = request.getHeader("X-Real-IP");
}
//有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
if (ipAddresses != null && ipAddresses.length() != 0) {
ip = ipAddresses.split(",")[0];
}
//还是不能获取到,最后再通过request.getRemoteAddr();获取
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ip = request.getRemoteAddr();
}
return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
}
}
4、使用方法
直接在要监听的方法上加上@ApiEyes注解即可
注:SSM环境需要在Spring配置文件中加入
<context:component-scan base-package="com.nys"/>
<!-- 启用 aspectj 方式 AOP-->
<aop:aspectj-autoproxy proxy-target-class="true" />