关于Jersey框架下的Aop日志 和Spring 框架下的Aop日志
摘要
最近新接手的项目经常要查问题,但是,前面一拨人,日志打的非常乱,好多就根本没有打日志,所以弄一个AOP统一打印一下 请求数据和响应数据
框架
spring+springmvc+jersey
正文
这个项目有点老啦,竟然还有前端页面用jsp写的,哎,说起来都是泪。下面说说我做这个项目踩得坑吧
统一打印请求的请求数据和响应数据(接口是restful 风格,用jersey框架实现的),肯定第一反应想到老罗的Spring aop,一开始木有仔细研究框架,以为会一招spring就可以吃遍天下啦。o(╥﹏╥)o,所以花了半个小时,写了一个spring aop,调试了1天,就是没看见spring 给目标类生成代理。其中我怀疑过,打的切点不对,spring配置文件不对,等等,反正就木有考虑过spring 本身的问题。后来我才发现要做代理的目标package 根本就木有交给spring 托管,他是由jersey直接托管(以前也木有玩过jersey框架,看了web.xml配置以后才茅塞顿开)
下面的代码是spring+jersey框架下日志aop (注:没法用spring aop ,因为restful风格的package 根本就木有交给spring托管)
import com.alibaba.fastjson.JSON;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;
import java.io.*;
import java.net.URI;
import java.util.List;
/**
* Created by huxuhong on 2019/11/27.
*/
@Provider
public class OperationLogFilter implements ContainerRequestFilter,ContainerResponseFilter{
Logger logger = LoggerFactory.getLogger(OperationLogFilter.class);
@Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
if(containerRequestContext!=null){
URI uri = null;
String path = null;
UriInfo uriInfo = containerRequestContext.getUriInfo();
if(uriInfo != null){
uri = uriInfo.getAbsolutePath();
}
if(uri != null){
path = uri.getPath();
}
String method = containerRequestContext.getMethod();
String params = inputStreamToString(containerRequestContext);
printReqInfo(path,method,params);
}else{
logger.info("请求request不存在");
}
}
@Override
public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
if(containerResponseContext ==null){
logger.info("响应response不存在");
}else{
String response = outputStreamToString(containerResponseContext);
printResInfo(response);
}
}
private String inputStreamToString(ContainerRequestContext containerRequestContext ) {
StringBuffer stringBuffer = new StringBuffer();
ByteArrayOutputStream baos = null;
InputStream repeatStreamRead = null;
InputStream repeatStreamWrite = null;
try{
InputStream in = containerRequestContext.getEntityStream();
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) > -1 ) {
baos.write(buffer, 0, len);
}
baos.flush();
repeatStreamRead = new ByteArrayInputStream(baos.toByteArray());
List<String> paramsList = IOUtils.readLines(repeatStreamRead,"UTF-8");
if(paramsList!=null && !paramsList.isEmpty()){
for(String str : paramsList){
stringBuffer.append(str);
}
}
repeatStreamWrite = new ByteArrayInputStream(baos.toByteArray());
containerRequestContext.setEntityStream(repeatStreamWrite);
}catch (Throwable e){
logger.warn("解析输入流失败{}",e);
}finally {
try {
if(baos != null){
baos.close();
}
if(repeatStreamRead != null){
repeatStreamRead.close();
}
if(repeatStreamWrite != null){
repeatStreamWrite.close();
}
} catch (Throwable e) {
logger.warn("关闭流失败{}",e);
}
}
return stringBuffer.toString();
}
private String outputStreamToString(ContainerResponseContext containerResponseContext ) throws IOException {
String responseStr = null;
try{
Object obj = containerResponseContext.getEntity();
if(obj != null){
responseStr = JSON.toJSON(obj).toString();
}
}catch (Throwable e){
logger.warn("解析响应数据异常{}",e);
}
return responseStr;
}
public void printReqInfo(String url,String method,String params){
logger.info("请求地址:{},请求方式:{},请求参数:{}",url,method,params);
}
public void printResInfo(String response){
logger.info("响应数据:{}",response);
}
}
下面是采用spring 的aop日志 实现方式
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
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 org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.container.ContainerRequestContext;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
/**
* Created by huxuhong on 2019/11/26.
*/
@Component
@Aspect
public class OperationLogAspect {
Logger logger = LoggerFactory.getLogger(OperationLogAspect.class);
ThreadLocal<Long> startTime = new ThreadLocal<Long>();
/**
* 定义拦截规则:拦截com.ppdai.wechat.spring.controller包下面的所有类
* execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
*/
@Pointcut(value = "execution(* com.ppdai.wechat.spring.controller..*(..))")
public void serviceMethodPointcut() {
}
@Before(value = "serviceMethodPointcut()")
public void doBefore(JoinPoint joinPoint){
String url = null;
String method = null;
String param = null;
String reqConcreteClass = null;
try {
startTime.set(System.currentTimeMillis());
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if(attributes == null){
return;
}
HttpServletRequest request = attributes.getRequest();
url = request.getRequestURL().toString();
method = request.getMethod();
if(method.toUpperCase().equals("GET")){
param = request.getQueryString();
}else{
for(Object obj :joinPoint.getArgs()){
if(obj instanceof MultipartFile
|| obj instanceof HttpServletRequest
|| obj instanceof HttpServletResponse){
continue;
}
param = JSON.toJSON(obj).toString();
}
}
reqConcreteClass = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
}catch (Throwable e){
logger.warn("解析请求信息异常",e);
}
printReqInfo(url,method,reqConcreteClass,param);
}
@AfterReturning(returning = "ret", pointcut = "serviceMethodPointcut()")
public void doAfterReturning(Object ret) throws Throwable {
String responseStr = null;
try {
if(ret != null){
responseStr = JSON.toJSON(ret).toString();
}
Long times = System.currentTimeMillis() - startTime.get();
printResponseInfo(responseStr,times);
}catch (Throwable e){
logger.warn("解析响应内容异常",e);
}
}
private void printResponseInfo(String response,long times){
logger.info("响应内容: {},响应耗时:{} " , response,times );
}
private void printReqInfo(String url,String method,String concreteClass,String param){
logger.info("请求URL: {},类路径:{}, 请求方式: {}, 请求参数: {}", url,concreteClass, method, param);
}
}
望后来的人不要跟我犯同样的错误,都是先入为主的观念害人
参考资料
ssm (spring springmvc mybatis) maven 项目集成 Jersey2 入门指南
https://blog.csdn.net/gianttj/article/details/86144582
https://www.jianshu.com/p/9e135faa3efaJersey实现对方法进行过滤拦截
https://blog.csdn.net/qq_28334711/article/details/72925495
关于Jersey框架下的Aop日志 和Spring 框架下的Aop日志的更多相关文章
- Java框架之spring框架的优点,为什么要学习spring框架
为什么要学习Spring的框架a: 方便解耦,简化开发 Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理 b:AOP编程的支持 Spring提供面向切 ...
- 「框架」菜鸟简单模仿一下spring的ioc和aop思想,欢迎大家进来阅读指教
*博客搬家:初版发布于 2015/12/04 16:41 原博客地址:https://my.oschina.net/sunqinwen/blog/539397 spring最核心的部分莫过于io ...
- Spring Boot中使用AOP统一处理Web请求日志
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是Spring框架中的一个重要内容,它通 ...
- Spring框架之IoC和AOP
Spring框架简介: 2003年2月,Spring框架正式成为一个开源项目,并发布于SourceForge中.致力于Java EE应用的各种解决方案,而并不是仅仅专注于某一层的方案,是企业应用开发的 ...
- Spring 系列: Spring 框架简介 -7个部分
Spring 系列: Spring 框架简介 Spring AOP 和 IOC 容器入门 在这由三部分组成的介绍 Spring 框架的系列文章的第一期中,将开始学习如何用 Spring 技术构建轻量级 ...
- Spring 系列: Spring 框架简介(转载)
Spring 系列: Spring 框架简介 http://www.ibm.com/developerworks/cn/java/wa-spring1/ Spring AOP 和 IOC 容器入门 在 ...
- Spring框架入门
技术分析之什么是Spring框架 1. Spring框架的概述 * Spring是一个开源框架 * Spring是于2003 年兴起的一个轻量级的Java开发 ...
- spring框架篇(一)-------spring简介与配置文件使用控制反转事例
spring简介 Spring 是一个开源框架,中文意思就是春天,也许是作者想让自己的这个框架给Java开发人员带来春天吧.其官方网站是 https://spring.io/ ,可以在官方网站下载到完 ...
- Spring框架的第四天(整合ssh框架)
## Spring框架的第四天 ## ---------- **课程回顾:Spring框架第三天** 1. AOP注解方式 * 编写切面类(包含通知和切入点) * 开启自动代理 2. JDBC模板技术 ...
随机推荐
- spring的xml文件的作用与实现原理
1.Spring读取xml配置文件的原理与实现 https://www.cnblogs.com/wyq178/p/6843502.html 2.首先使用xml配置文件的好处是参数配置项与代码分离,便于 ...
- 【6】TensorFlow光速入门-python模型转换为tfjs模型并使用
本文地址:https://www.cnblogs.com/tujia/p/13862365.html 系列文章: [0]TensorFlow光速入门-序 [1]TensorFlow光速入门-tenso ...
- Luogu P4271 [USACO18FEB]New Barns P
题意 给一个一开始没有点的图,有 \(q\) 次操作,每次为加点连边或者查询一个点到连通块内所有点的距离最大值. \(\texttt{Data Range}:1\leq q\leq 10^5\) 题解 ...
- GPRS DTU的工作原理和应用场景有哪些
GPRS DTU是属于物联网无线数据终端设备的中一种,它主要是利用公用运营商的GPRS网络(又称G网)来为用户提供无线长距离数据传输的功能.一般都是采用的高性能工业级8/16/32位通信处理器和工业级 ...
- Flask简介与启动服务器
Flask 一.简介 官方文档:http://flask.pocoo.org/ http://www.pythondoc.com/flask/index.html(中文) 1.概述 flask是一个非 ...
- [Luogu P1066] 2^k进制数 (组合数或DP)
题面 传送门:https://www.luogu.org/problemnew/show/P1066 Solution 这是一道神奇的题目,我们有两种方法来处理这个问题,一种是DP,一种是组合数. 这 ...
- .net 实现之短信验证码
接口类型:互亿无线触发短信接口,支持发送验证码短信.订单通知短信等. 账户注册:请通过该地址开通账户http://sms.ihuyi.com/register.html 只能测试用: 实现注册页面 & ...
- [.Net Core 3.0+/.Net 5] System.Text.Json中时间格式化
简介 .Net Core 3.0开始全新推出了一个名为System.Text.Json的Json解析库,用于序列化和反序列化Json,此库的设计是为了取代Json.Net(Newtonsoft.Jso ...
- 【Java】线程的 6 种状态
一.线程状态的枚举 Java的线程从创建到销毁总共有6种状态.这些状态被定义在Thread类种的内部枚举 State 中,分别如下: 1.NEW:初始状态. 线程实例已创建,但未启动. // 实例创建 ...
- Oracle数据库操作相关
1. 导出dmp 文件 (1)导出数据库所有的用户数据: exp system/manage@ORCL file=D:\oracle_dmp\data1.dmp full=y (2)导出指定的用户数据 ...