1、springboot maven引入aop,如果使用的Springmvc没有使用maven则下载对应的jar包到lib下。
<!-- aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、springboot配置文件中加入aop配置,我这边是.properties文件。.yml对应改一下即可。
#spring aop配置
spring.aop.proxy-target-class=true
spring.aop.auto=true
如果使用的Springmvc,spring-mvc.xml中加入以下配置
<!-- 基于注解的实现AOP -->
<aop:aspectj-autoproxy proxy-target-class="true">
</aop:aspectj-autoproxy>
3、自定义操作日志注解
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented
public @interface OperLog {
String operModul() default ""; // 操作模块
String operType() default ""; // 操作类型
String operDesc() default ""; // 操作说明
}
4、切面处理类,操作日志异常日志记录处理,因为操作日志很大并且不是很重要的信息,主要用来快速定位问题,所以我这里使用的是直接把信息写到日志文件,如果是安全日志建议存在数据库。
@Aspect
@Component
public class OperLogAspect {
public static final String path = "/home/data/logs/";
public static final String runLogName = "runLog";
public static final String exceptionLogName = "exceptionLog";
public static final String fileType = ".log";
public static File runLog = new File(path+runLogName+fileType);
public static File exceptionLog = new File(path+exceptionLogName+fileType);
public static BufferedWriter runLogWriter = null;
public static BufferedWriter exceptionLogWriter = null;
/**
* 操作版本号
* <p>
* 项目启动时从命令行传入,例如:java -jar xxx.war --version=201902
* </p>
*/
/* @Value("${version}")
private String operVer;*/
/**
* 设置操作日志切入点 记录操作日志 在注解的位置切入代码
*/
@Pointcut("@annotation(com.xxx.log.OperLog)")
public void operLogPoinCut() {
}
/**
* 设置操作异常切入点记录异常日志 扫描所有controller包下操作
*/
@Pointcut("execution(* com.xxx.controller..*.*(..))")
public void operExceptionLogPoinCut() {
}
/**
* 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
*
* @param joinPoint 切入点
* @param keys 返回结果
*/
@AfterReturning(value = "operLogPoinCut()", returning = "keys")
public void saveOperLog(JoinPoint joinPoint, Object keys){
// 获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes
.resolveReference(RequestAttributes.REFERENCE_REQUEST);
try {
File newf = new File(path);
if(!newf.exists()){
newf.mkdirs();
}
if(!runLog.exists() || runLog.length()>536870912){
//如果日志文件不存在或者大于512M则新建另外一个日志文件
runLog = new File(path+runLogName+ TimeUtils.converStringDate(new Date(),"yyyy-MM-dd HH-mm-ss")+fileType);
}
runLogWriter = new BufferedWriter(new FileWriter(runLog,true));
// operlog.setOperId(MD5Utils.getMd5Value(new Date().toString())); // 主键ID
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// 获取操作
OperLog opLog = method.getAnnotation(OperLog.class);
if (opLog != null) {
//String operDesc = opLog.operDesc();
runLogWriter.newLine();
runLogWriter.write("=================================Start Request============================================");
runLogWriter.newLine();
runLogWriter.write("Start Request Time:"+ TimeUtils.converStringDate(new Date(),"yyyy-MM-dd HH:mm:ss"));
runLogWriter.newLine();
//operlog.setOperModul(operModul); // 操作模块
//operlog.setOperType(operType); // 操作类型
//operlog.setOperDesc(operDesc); // 操作描述
}
// 获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
// 获取请求的方法名
String methodName = method.getName();
methodName = className + "." + methodName;
runLogWriter.write("Request Method = "+methodName);
runLogWriter.newLine();//换行
//operlog.setOperMethod(methodName); // 请求方法
// 请求的参数
Map<String, String> rtnMap = converMap(request.getParameterMap());
// 将参数所在的数组转换成json
String params = rtnMap.get("key");
String model = request.getHeader("model");//获取请求头部中的参数
runLogWriter.write("Request Params = "+deparams);
runLogWriter.newLine();//换行
runLogWriter.write("Return Result = "+ JSON.toJSONString(keys));
runLogWriter.newLine();//换行
runLogWriter.write("Request IP = "+ HttpRequestUtils.getIpAddr(request));
runLogWriter.newLine();//换行
runLogWriter.write("Request URI = "+request.getRequestURI());
runLogWriter.newLine();//换行
runLogWriter.write("End Request Time = "+ TimeUtils.converStringDate(new Date(),"yyyy-MM-dd HH:mm:ss"));
runLogWriter.newLine();//换行
runLogWriter.write("========================================================================================");
runLogWriter.newLine();
//operlog.setOperRequParam(params); // 参数
//operlog.setOperRespParam(JSON.toJSONString(keys)); // 返回结果
//operlog.setOperIp(HttpRequestUtils.getIpAddr(request)); // 请求IP
//operlog.setOperUri(request.getRequestURI()); // 请求URI
//operlog.setOperCreateTime(new Date()); // 创建时间
//operationLogMapper.insert(operlog);
} catch (Exception e) {
logException(runLogWriter,e);
e.printStackTrace();
}finally {
closeWriter(runLogWriter);
}
}
/**
* 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
*
* @param joinPoint 切入点
* @param e 异常信息
*/
@AfterThrowing(pointcut = "operExceptionLogPoinCut()", throwing = "e")
public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
// 获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes
.resolveReference(RequestAttributes.REFERENCE_REQUEST);
//ExceptionLog excepLog = new ExceptionLog();
try {
File newf = new File(path);
if(!newf.exists()){
newf.mkdirs();
}
if(!exceptionLog.exists() || exceptionLog.length()>536870912){
//如果日志文件不存在或者大于512M则新建另外一个日志文件
exceptionLog = new File(path+exceptionLogName+ TimeUtils.converStringDate(new Date(),"yyyy-MM-dd HH-mm-ss")+fileType);
}
exceptionLogWriter = new BufferedWriter(new FileWriter(exceptionLog,true));
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// excepLog.setExcId(UuidUtil.get32UUID());
// 获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
// 获取请求的方法名
String methodName = method.getName();
methodName = className + "." + methodName;
// 请求的参数
Map<String, String> rtnMap = converMap(request.getParameterMap());
// 将参数所在的数组转换成json
String params = rtnMap.get("key");
// 将参数所在的数组转换成json
exceptionLogWriter.newLine();
exceptionLogWriter.write("=================================An Exception Occurred Here============================================");
exceptionLogWriter.newLine();
exceptionLogWriter.write("Request Params = "+params );
exceptionLogWriter.newLine();
exceptionLogWriter.write("Request Method = "+methodName);
exceptionLogWriter.newLine();
exceptionLogWriter.write("ExceptionName = "+e.getClass().getName());
exceptionLogWriter.newLine();
exceptionLogWriter.write("ExceptionInfo = "+stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));
exceptionLogWriter.newLine();
exceptionLogWriter.write("Operation URI = "+request.getRequestURI());
exceptionLogWriter.newLine();
exceptionLogWriter.write("Operation Device IP = "+ HttpRequestUtils.getIpAddr(request));
exceptionLogWriter.newLine();
exceptionLogWriter.write("End ExceptionInfo Print Time = "+ TimeUtils.converStringDate(new Date(),"yyyy-MM-dd HH:mm:ss"));
exceptionLogWriter.newLine();
exceptionLogWriter.write("========================================================================================");
exceptionLogWriter.newLine();
/* excepLog.setExcRequParam(params); // 请求参数
excepLog.setOperMethod(methodName); // 请求方法名
excepLog.setExcName(e.getClass().getName()); // 异常名称
excepLog.setExcMessage(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace())); // 异常信息
excepLog.setOperUserId(UserShiroUtil.getCurrentUserLoginName()); // 操作员ID
excepLog.setOperUserName(UserShiroUtil.getCurrentUserName()); // 操作员名称
excepLog.setOperUri(request.getRequestURI()); // 操作URI
excepLog.setOperIp(IPUtil.getRemortIP(request)); // 操作员IP
excepLog.setOperCreateTime(new Date()); // 发生异常时间
exceptionLogService.insert(excepLog);*/
} catch (Exception e2) {
logException(exceptionLogWriter,e2);
e.printStackTrace();
}finally {
closeWriter(exceptionLogWriter);
}
}
/**
* 转换request 请求参数
*
* @param paramMap request获取的参数数组
*/
public Map<String, String> converMap(Map<String, String[]> paramMap) {
Map<String, String> rtnMap = new HashMap<String, String>();
for (String key : paramMap.keySet()) {
rtnMap.put(key, paramMap.get(key)[0]);
}
return rtnMap;
}
/**
* 转换异常信息为字符串
*
* @param exceptionName 异常名称
* @param exceptionMessage 异常信息
* @param elements 堆栈信息
*/
public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
StringBuffer strbuff = new StringBuffer();
for (StackTraceElement stet : elements) {
strbuff.append(stet + "\n");
}
String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
return message;
}
/**
* 功能描述:日志记录异常
* @param [writer, e]
* @return void
*/
public void logException(BufferedWriter writer,Exception e){
try {
writer.newLine();
writer.write("===============================LoggingException================================");
writer.newLine();
writer.write("Exception Time:"+ TimeUtils.converStringDate(new Date(),"yyyy-MM-dd HH:mm:ss"));
writer.newLine();
writer.write("ExceptionInfo:"+e);
writer.newLine();
writer.write("==========================================================================");
writer.newLine();
} catch (IOException ie) {
ie.printStackTrace();
}
}
/**
* 功能描述:关闭输出通道
* @param [writer]
* @return void
*/
public void closeWriter(BufferedWriter writer){
try {
writer.flush();
writer.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
}
5、在需要记录操作日志的方法上加上@OperLog(operDesc="操作描述")注解即可。
@OperLog(operModul="操作模块",operType="操作类型",operDesc="操作描述")
public String xxx(){
}