一,自定义注解
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.ponent;
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 -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 -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.ponentScan;
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