java使用AOP切面获取请求日志并记录

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: java使用AOP切面获取请求日志并记录


3.AOP切面如下

package com.tjair.tjapi.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tjair.common.log.TjapiLogVo;
import com.tjair.common.util.IPUtil;
import com.tjair.tjapi.feign.LogFeignService;
import com.tjair.tjapi.util.HttpHelper;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;
import java.util.Objects;
/**
• @description 拦截所有控制器的返回,记录响应报文
• @author unhejing
• @date 2021-03-17 上午11:52:26
*/
@Aspect
@Configuration
@Slf4j
public class LogAspect {
@Autowired
private LogFeignService logFeignService;
public LogAspect() {
}
@Pointcut(“execution(public * com.tjair.tjapi.controller..(…))”)
public void pointCutMethod() {
}
// 声明环绕通知
@Around(“pointCutMethod()”)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
Long startTime = System.currentTimeMillis();
ApiOperation apiOperation = ((MethodSignature)pjp.getSignature()).getMethod().getAnnotation(ApiOperation.class);
// 获取request对象
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
Object ret = pjp.proceed();
Long endTime = System.currentTimeMillis();
TjapiLogVo tjapiLogVo = getTjapiLogVo(request,Objects.nonNull(apiOperation) ? apiOperation.value() : “”,endTime-startTime,JSON.toJSONString(ret));
// 添加日志
addLog(tjapiLogVo);
log.info(“响应数据耗时{}:响应数据{}”,endTime-startTime,JSON.toJSONString(ret));
return ret;
}
public void addLog(TjapiLogVo tjapiLogVo) {
log.info(“添加日志:{}”,JSON.toJSONString(tjapiLogVo));
Long startTime = System.currentTimeMillis();
logFeignService.addTjapiLog(tjapiLogVo);
Long endtime = System.currentTimeMillis();
log.info(“添加日志耗时:{}”,endtime-startTime);
}
private TjapiLogVo getTjapiLogVo(HttpServletRequest request,String apiName,Long time,String response) throws IOException {
TjapiLogVo tjapiLogVo = new TjapiLogVo();
String jsonBody = HttpHelper.getBodyString(request);
log.info(“请求参数:{}”,jsonBody);
JSONObject reqObj = Objects.nonNull(JSON.parseObject(jsonBody)) ? JSON.parseObject(jsonBody) : new JSONObject();
JSONObject resObj = Objects.nonNull(JSON.parseObject(response)) ? JSON.parseObject(response) : new JSONObject();
//设置请求参数
tjapiLogVo.setParams(jsonBody);
tjapiLogVo.setPartnerid(Objects.nonNull(reqObj.getString(“partnerId”)) ? reqObj.getString(“partnerId”) : “-1”);
// 设置IP地址
tjapiLogVo.setIp(IPUtil.getIpAddr(request));
// 设置位置
tjapiLogVo.setLocation(IPUtil.getCityInfo(tjapiLogVo.getIp()));
//设置请求方法,GET,POST…
tjapiLogVo.setMethod(request.getMethod());
//设置请求路径
tjapiLogVo.setUrl(request.getRequestURI());
// 设置请求方法名称
tjapiLogVo.setApiName(apiName);
// 设置创建时间
tjapiLogVo.setCreateTime(new Date());
// 设置请求状态
Integer code = Objects.nonNull(resObj.getInteger(“code”)) ? resObj.getInteger(“code”) : 1;
tjapiLogVo.setStatus(code);
// 设置接口消耗时间
tjapiLogVo.setTime(time.intValue());
// 设置响应内容
tjapiLogVo.setResponse(response);
return tjapiLogVo;
}
}

4.测试接口

package com.tjair.tjapi.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tjair.common.service.RedisUtils;
import com.tjair.common.util.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
• @author jingyujie
• @create 2021-03-16 下午2:39
**/
@RestController
@RequestMapping(“/test”)
@Api(tags = “测试API控制器”)
public class TestController {
@Autowired
private RedisUtils redisUtils;
@PostMapping(“/apiTest”)
@ApiOperation(“接口测试”)
public Result apiTest(@RequestBody JSONObject obj){
return Result.returnSuccess(“接口已联通,请求入参:”+ JSON.toJSONString(obj));
}
}

5.请求结果如下

备注说明:

1.LogFeignService是添加日志的service

2.IPUtil是获取IP和地址信息相关的工具类

3.HttpHelper是解析request中的请求参数的工具类

4.ApiOperation是获取接口的注解上面的接口描述

5.partnerId是我请求参数里面必传的用户编码

6.code是响应参数里面的状态码,用于判断接口是否请求成功

末尾附上工具类:

IPUtil.java

类中的/ip2region.db这个是一个地址库,可直接百度下载即可。

package com.tjair.common.util;
import org.apache.commons.io.FileUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.lang.reflect.Method;
/**
• ip操作相关工具类
• @author jingyujie
• @create 2020-06-24 下午2:11
**/
public class IPUtil {
public static String getCityInfo(String ip){
try {
//db
String dbPath = IPUtil.class.getResource(“/ip2region.db”).getPath();
System.out.println(“路径:”+dbPath);
File file = new File(dbPath);
if (file.exists() == false) {
System.out.println(“Error: Invalid ip2region.db file”);
String tmpDir = System.getProperties().getProperty(“java.io.tmpdir”);
dbPath = tmpDir + “ip.db”;
System.out.println(dbPath);
file = new File(dbPath);
FileUtils.copyInputStreamToFile(IPUtil.class.getClassLoader().getResourceAsStream(“classpath:ip2region.db”), file);
}
//查询算法
int algorithm = DbSearcher.BTREE_ALGORITHM; //B-tree
//DbSearcher.BINARY_ALGORITHM //Binary
//DbSearcher.MEMORY_ALGORITYM //Memory
DbSearcher searcher = null;
try {
DbConfig config = new DbConfig();
searcher = new DbSearcher(config, dbPath);


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
21天前
|
JSON API 数据格式
【Azure APIM】如何把APIM中处理的请求的所有请求头保存在日志中?
Azure API Management 默认诊断日志不记录请求的 Header 和 Body 信息。为实现记录,可通过配置 Trace 策略解决。例如,使用 `context.Request.Headers` 和 `context.Request.Body` 获取相关信息,并以 JSON 或字符串格式保存。示例代码展示了如何将 Headers 转换为 JSON 或逗号分隔字符串形式记录。相关参考资料包括 Set Body Policy 和 Trace Policy 官方文档,帮助进一步了解与扩展功能。
83 36
|
2月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
84 0
|
2月前
|
Java 开发者 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——什么是AOP
本文介绍了Spring Boot中的切面AOP处理。AOP(Aspect Oriented Programming)即面向切面编程,其核心思想是分离关注点。通过AOP,程序可以将与业务逻辑无关的代码(如日志记录、事务管理等)从主要逻辑中抽离,交由专门的“仆人”处理,从而让开发者专注于核心任务。这种机制实现了模块间的灵活组合,使程序结构更加可配置、可扩展。文中以生活化比喻生动阐释了AOP的工作原理及其优势。
60 0
|
2月前
|
运维 Cloud Native Java
postman发起post请求遇到报错:java.io.FileNotFoundException (文件名、目录名或卷标语法不正确。)
遇到bug报错,多猜可能的原因,控制变量反复测试,直至找到问题的关键,然后再思考如何解决或者回避。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来
|
3月前
|
Java 编译器 Spring
JAVA中切面的使用
AOP(面向切面编程)通过切面、通知、切入点和连接点实现模块化关注点分离。Spring AOP基于代理模式,使用JDK动态代理或CGLIB代理;AspectJ采用字节码增强,在编译或类加载时织入切面逻辑,性能更高。示例代码展示了如何在方法调用前后插入日志记录等操作。
|
5月前
|
JSON Java 数据格式
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
154 25
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
|
4月前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
194 8
|
5月前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
87 6
|
6月前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
116 1
|
7月前
|
JSON Java 数据格式
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
java操作http请求针对不同提交方式(application/json和application/x-www-form-urlencoded)
200 1