springBoot管理AOP日志+注解实现

一,自定义注解

package com.liu.annotation;
/**
 * 
 * @author liuerchong
 *根据选项自定义注解参数项
 */
public @interface LogEnable {

    /**
     * 主要是标志日志的描述信息
     * @return
     */
    String desc() default "";
    
    /**
     * 调用方      1:客户端   2:支付宝   3:微信       4:钱宝     5:其他第三方
     * @return
     */
    //int sendFrom() default 1; 
    
    /**
     * 接口url(从二级目录记起)
     * @return
     */
    //String url() default "";
    
    /**
     * 接口类型(0前台,1后台)
     * @return
     */
    //int type() default 0;
    
    /** 功能说明
     * @return
     *  */
    String action() ;

}
二,定义切面类

package com.liu.aspact;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Handler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
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 com.alibaba.fastjson.JSONObject;
import com.liu.annotation.LogEnable;
import com.liu.vo.SysLog;

@Aspect
@Component
public class LogAspect {

    public static final int CODE_SUCCESS = 0;
    
    private Logger logger = LoggerFactory.getLogger(LogAspect.class);
    
   
    
    private static final ThreadLocal<Long> TIME_THREADLOCAL = new ThreadLocal<Long>() {
        @Override
        protected Long initialValue() {
            return System.currentTimeMillis();
        }
    };
    
    
    /**
     * Description: 定义切点名controllerAspect,此方法需要为空,只是标识切点和切面关系
     */
    @Pointcut("@annotation(com.liu.annotation.LogEnable)")
    public void controllerAspect(){}
    
    //声明切面类路径,类型必须为final String类型的,注解里要使用的变量只能是静态常量类型的
   //public static final String POINT = "execution(* com.product.service.*.*(..))";
   //也可以使用注解声明切入点,如下
    @Pointcut("execution(* com.liu.controller.*.*(..))")
    public void point(){}
    
    @Before("point()")
    public void doBefore(){
        TIME_THREADLOCAL.set(System.currentTimeMillis());
    }
    
    
    /**
     * 
     * Description:织入后增强 
    
     */
    @AfterReturning(pointcut = "controllerAspect()", returning = "res")
    public void doAfter(JoinPoint joinPoint, Object res) throws Exception{
        //获取反射参数
        logger.debug("---------------AfterReturning开始--------------");
        if(null == res){
            return;
        }
        Map<String, Object> map = Obj2Map(res);
        logger.info("-------返回值res为-------"+res.toString());
       /* int code = (Integer)map.get("code");
        if(code == CODE_SUCCESS){
            return;
        }*/
        String message = (String)map.get("message");
        //类名
        String targetName = joinPoint.getTarget().getClass().getSimpleName();
        //得到方法名
        String methodName = joinPoint.getSignature().getName();
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        //入参key
        String[] parameterNames = ms.getParameterNames();
        //入参value
        Object[] arguments = joinPoint.getArgs();
        Method method = ms.getMethod();
        //方法的注解对象
        LogEnable logParam = method.getAnnotation(LogEnable.class);  
        //logger.debug("LogEnable注解参数send:" + logParam.send());  
       // logger.debug("LogEnable注解参数url:" + logParam.url()); 
       // logger.debug("LogEnable注解参数type:" + logParam.type()); 
        logger.debug("targetName:" + targetName);
        logger.debug("methodName:" + methodName);
        logger.debug("ms:" + ms);
        logger.debug("arguments:" + JSONObject.toJSONString(arguments));
        logger.debug("parameterNames:" + JSONObject.toJSONString(parameterNames));
        logger.debug("method:" + JSONObject.toJSONString(method));
        
        //拼参数
        SysLog syslog = new SysLog(); 
        //获取用户
        //syslog.setUserId(getMgrUserId());
        syslog.setUserId(getMgrUserId());
       // syslog.setSend(logParam.send());
       //syslog.setUrl(logParam.url());
       // syslog.setType(logParam.type());
        //入参字符串
        StringBuffer jsonParamSb = new StringBuffer();
        for(int i = 0;i < parameterNames.length;i++){
            jsonParamSb.append(parameterNames[i]).append("=").append(JSONObject.toJSONString(arguments[i]));
            if(i != (parameterNames.length - 1)){
                jsonParamSb.append("&");
            }
        }
        //截取返回json
        String jsonParam = null;
        if(jsonParamSb.toString().length() <= 1000){
            jsonParam = jsonParamSb.toString();
        }else{
            jsonParam = jsonParamSb.toString().substring(0, 1000);
        }
        syslog.setJsonParam(jsonParam);
        logger.info("---------------传入参数jsonParam----"+jsonParam);
        //出参
        syslog.setJsonResult(JSONObject.toJSONString(res));
        StringBuffer remarkSb = new StringBuffer();
        remarkSb.append(targetName).append(".").append(methodName).append("报错信息:").append(message);
        //截取remark
        String remark = null;
        if(remarkSb.toString().length() <= 1000){
            remark = remarkSb.toString();
        }else{
            remark = remarkSb.toString().substring(0, 1000);
        }
        syslog.setRemark(remark); 
        syslog.setCreateTime(new Date());
        syslog.setUpdateTime(new Date());
        handleLog(syslog);
        logger.info("---------------报错信息remark----"+remark);
        logger.info("thredlocal计算的耗时"+(System.currentTimeMillis()-TIME_THREADLOCAL.get()));
        logger.debug("---------------AfterReturning结束--------------");
    }
    
    
    
    private void handleLog(SysLog syslog) {
        logger.info("保存日志信息");
        
    }

    /**
     * 
     * Description: 对象转map
     *
     * @param obj
     * @return
     * @throws Exception
     * @author suoww
     * @date 2017-2-8
     */
    public Map<String,Object> Obj2Map(Object obj) throws Exception{
        Map<String,Object> map=new HashMap<String, Object>();
        Field[] fields = obj.getClass().getDeclaredFields();
        for(Field field:fields){
            field.setAccessible(true);
            map.put(field.getName(), field.get(obj));
        }
        return map;
    }
    
    /**
     * 
     * Description: 获取APP用户ID
     *
     * @return
     * @author suoww
     * @date 2017-2-8
     */
    protected String  getAppUserId() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session = request.getSession();
        if (null == session) {
            return null;
        }
        //PartnerUser user = (PartnerUser) session.getAttribute("userInfo");
       /* if (null == user) {
            return null;
        }
        return user.getId();*/
        return "app";
    }
    
    /**
     * 
     * @return
     */
    protected String getMgrUserId(){
       // ShiroUser user = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
       // return user.getId();
        return "";
    }
    
    
    private static final long HALF_MINUTE= 60*1000;
 // service层的统计耗时切面,类型必须为final String类型的,注解里要使用的变量只能是静态常量类型的
    public static final String POINT = "execution (* com.liu.service.impl.*.*(..))";
    
    /**
     * 统计方法执行耗时Around环绕通知
     * @param joinPoint
     * @return
     */
    @Around(POINT)
    public Object timeAround(ProceedingJoinPoint joinPoint) {
     // 定义返回对象、得到方法需要的参数
     Object obj = null;
     Object[] args = joinPoint.getArgs();
     long startTime = System.currentTimeMillis();
    
     try {
      obj = joinPoint.proceed(args);
     } catch (Throwable e) {
      logger.error("统计某方法执行耗时环绕通知出错", e);
     }
    
     // 获取执行的方法名
     long endTime = System.currentTimeMillis();
     MethodSignature signature = (MethodSignature) joinPoint.getSignature();
     String methodName = signature.getDeclaringTypeName() + "." + signature.getName();
    
     // 打印耗时的信息
     this.printExecTime(methodName, startTime, endTime);
    
     return obj;
    }
    
    /**
     * 打印方法执行耗时的信息,如果超过了一定的时间,才打印
     * @param methodName
     * @param startTime
     * @param endTime
     */
    private void printExecTime(String methodName, long startTime, long endTime) {
     long diffTime = endTime - startTime;
     if (diffTime > HALF_MINUTE) {
      logger.warn("-----" + methodName + " 方法执行耗时:" + diffTime + " ms");
      Handler(methodName,diffTime);
     }
    }

    private void Handler(String methodName, long diffTime) {
        logger.warn("-----" + methodName + " 长耗时处理,方法执行耗时:" + diffTime + " ms");
        
    }
    
   
    
    

}
 

三,编写测试类

controller

package com.liu.controller;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.liu.annotation.LogEnable;
import com.liu.service.HellowordService;

//标识该接口全部返回json格式。
@RestController

public class HelloWorldController {
    
    Logger logger = LoggerFactory.getLogger(HelloWorldController.class);
    
    @Autowired
    HellowordService hellowordService;
    
    
    @RequestMapping("/index")
    @LogEnable(action="index")
    public String index() {
        logger.debug("Hello debug");
        logger.info("Hello info");
        logger.warn("Hello warn");
        logger.error("Hello error");
        hellowordService.testCost();
        return "success";
    }

    @RequestMapping("/getMap")
    @LogEnable(action="getMap")
    public Map<String, Object> getMap() {
        Map<String, Object> result = new HashMap<String, Object>();
        hellowordService.testCost();
        result.put("errorCode", "200");
        result.put("errorMsg", "成功");
        return result;
    }


}


service接口及实现类

package com.liu.service;

public interface HellowordService {

    public void testCost();
}
 

package com.liu.service.impl;

import org.springframework.stereotype.Service;

import com.liu.service.HellowordService;

@Service
public class HelloworldServiceImpl implements HellowordService{

    @Override
    public void testCost() {
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

}
 

package com.liu.vo;

import java.util.Date;

public class SysLog {

    private String action;
    private String userId;
    private String note;
    private String url;
    

    private Integer type;
    private String jsonParam;
    private String jsonResult;
    private String remark;
    private Integer send;


    private Date createTime;
    private Date updateTime;

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    public String getJsonResult() {
        return jsonResult;
    }

    public void setJsonResult(String jsonResult) {
        this.jsonResult = jsonResult;
    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }


    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }


    public String getJsonParam() {
        return jsonParam;
    }

    public void setJsonParam(String jsonParam) {
        this.jsonParam = jsonParam;
    }
    
    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public Integer getType() {
        return type;
    }

    public Integer getSend() {
        return send;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public void setSend(Integer send) {
        this.send = send;
    }
}
 

四,入口类

package com.liu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@ComponentScan(basePackages = { "com.liu" })
@SpringBootApplication
@EnableAspectJAutoProxy //表示启用AOP
public class App {

    public static void main(String[] args) {
        // 主函数运行springboot项目
        SpringApplication.run(App.class, args);
        
    }

}
 

运行结果:

[11:17:59.695] WARN  com.liu.aspact.LogAspect 255 printExecTime - -----com.liu.service.HellowordService.testCost 方法执行耗时:60001 ms
[11:17:59.700] WARN  com.liu.aspact.LogAspect 261 Handler - -----com.liu.service.HellowordService.testCost 长耗时处理,方法执行耗时:60001 ms
[11:17:59.707] INFO  com.liu.aspact.LogAspect 80 doAfter - -------返回值res为-------success
[11:17:59.995] INFO  com.liu.aspact.LogAspect 132 doAfter - ---------------传入参数jsonParam----
[11:17:59.996] INFO  com.liu.aspact.LogAspect 156 handleLog - 保存日志信息
[11:17:59.997] INFO  com.liu.aspact.LogAspect 148 doAfter - ---------------报错信息remark----HelloWorldController.index报错信息:null
[11:17:59.998] INFO  com.liu.aspact.LogAspect 149 doAfter - thredlocal计算的耗时60374

发布了23 篇原创文章 · 获赞 0 · 访问量 201

猜你喜欢

转载自blog.csdn.net/liuerchong/article/details/105136587