spring boot使用自定义注解+AOP实现对Controller层方法的日志记录
程序员文章站
2022-06-17 13:03:43
...
1.创建一个spring boot项目,导入maven依赖:
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
2.自定义RecordLog注解:
import java.lang.annotation.*;
@Target(ElementType.METHOD) // 此注解适用于方法上
@Retention(RetentionPolicy.RUNTIME) // 此注解不仅被保存到class文件中,jvm加载class文件之后依然存在
@Documented
/**
* 用于标识方法需要记录日志
*/
public @interface RecordLog {
/**
* 方法描述
*
* @return
*/
String desc() default "";
}
3.定义一个IP工具类获取访问的ip地址:
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @ClassName: IPUtil
* @Description:获取ip地址工具类
* @author: jinghx
* @date: 2020/5/26 16:28
*/
public class IPUtil {
private IPUtil() {
}
/**
* 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址;
*
* @param request
* @return
*/
public final static String getIpAddress(HttpServletRequest request) throws UnknownHostException {
// 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} else if (ip.length() > 15) {
String[] ips = ip.split(",");
for (int index = 0; index < ips.length; index++) {
String strIp = (String) ips[index];
if (!("unknown".equalsIgnoreCase(strIp))) {
ip = strIp;
break;
}
}
}
if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
// 根据网卡取本机配置的IP
ip = getLocalIp();
}
return ip;
}
/**
* 获取本机IP
*/
public static String getLocalIp() throws UnknownHostException {
InetAddress inetAddress = InetAddress.getLocalHost();
String ip = inetAddress.getHostAddress().toString();//获得本机Ip
return ip;
}
}
4.编码实现切面类:
/**
* @ClassName: LogAspect
* @Description: 日志切面
* @author: jinghx
* @date: 2020/5/26 15:42
*/
@Aspect // 标识这是一个切面类
@Component // 把切面类加入到IOC容器中
public class LogAspect {
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
/**
* 切入点表达式
*/
public static final String exp = "@annotation(com.learn.annotation.RecordLog)"; // "execution(* com.learn.controller..*(..))";
/**
* 定义切入点
*/
@Pointcut(exp)
public void logAspect() {
}
/**
* 切面方法(环绕通知)
*
* @param joinPoint
* @return
* @throws Exception
*/
@Around("logAspect()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis(); // 开始时间
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
// 获取方法描述
String methodDesc = methodSignature.getMethod().getAnnotation(RecordLog.class).desc();
// 获取Request对象
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
log.info("-----------开始访问方法:" + LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "-------------");
// 方法描述
log.info("方法描述:{}", methodDesc);
// 请求url
log.info("请求url:{}", request.getRequestURL().toString());
// 请求类型
log.info("请求类型:{}", request.getMethod());
// 请求方法
log.info("请求方法:{}.{}", signature.getDeclaringTypeName(), methodSignature.getName());
// 请求IP
log.info("请求IP:{}", IPUtil.getIpAddress(request));
// 请求参数
log.info("请求参数:{}", new Gson().toJson(joinPoint.getArgs()));
Object result = joinPoint.proceed();
// 请求耗时
log.info("请求耗时:{}ms", System.currentTimeMillis() - startTime);
// 请求返回
log.info("请求返回:{}", new Gson().toJson(result));
log.info("------------------请求结束-----------------------");
return result;
}
}
5.编写一个Controller类进行测试:
/**
* @ClassName: UserController
* @Description: 用户Controller
* @author: jinghx
* @date: 2020/5/26 15:38
*/
@RestController
public class UserController {
@GetMapping("/hello")
@RecordLog(desc = "这个一个用于问好的方法")
public String sayHello(String name) {
return "hello," + name + "!";
}
}
最终项目结构:
启动项目,在浏览器中输入:http://localhost:8080/hello?name=德玛西亚
日志输出: