• 关于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/9e135faa3efa


    Jersey实现对方法进行过滤拦截
    https://blog.csdn.net/qq_28334711/article/details/72925495
     
  • 相关阅读:
    PgSQL定时备份
    如何从源码包安装软件?
    PostgreSQL PointInTime Recovery (Incremental Backup)
    Better PostgreSQL backups with WAL archiving
    安装GTK全攻略
    WEB前端开发规范文档
    Linux开机自动启动脚本方法
    安装编译postgresql与pgagent的相关操作
    PostgreSQL: 如何查询表的创建时间?
    什么是编程
  • 原文地址:https://www.cnblogs.com/huxuhong/p/11950029.html
Copyright © 2020-2023  润新知