写日志功能很繁琐,博主废了一些时间写出来分享,用的ssm框架,后期会设置优先级,避免所有方法都会被记录到日志。开始:
1、首先定义一个自定义注解@controllerLog和@serviceLog
package com.hhwy.business.annotation;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ControllerLog {
String description() default "";
}
package com.hhwy.business.annotation;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ServiceLog {
String description() default "";
}
2、在webapp下找到 plugin-config.xml或者applicationContext.xml(公司项目中用的plugin-config.xml,以此为例)
3、完了之后可以手写Aspect类
package com.hhwy.business.service.impl;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSON;
import com.hhwy.business.annotation.ControllerLog;
import com.hhwy.business.annotation.ServiceLog;
import com.hhwy.business.core.modelutil.ExecutionResult;
import com.hhwy.business.domain.LogException;
import com.hhwy.business.domain.LogMeg;
import com.hhwy.business.service.LogService;
import com.hhwy.framework.util.PlatformTools;
import com.hhwy.sso.client.filter.SessionUtil;
@Aspect
@Component
@Scope("prototype")
public class LogAspect {
//注入Service用于把日志保存数据库
@Resource
private LogService logService;
//本地异常日志记录对象
private static final Logger logger = LoggerFactory.getLogger(LogAspect. class);
//Service层切点
@Pointcut("@annotation(com.hhwy.business.annotation.ServiceLog)")
public void serviceAspect() {
}
//Controller层切点
@Pointcut("@annotation(com.hhwy.business.annotation.ControllerLog)")
public void controllerAspect() {
}
//定义id接受数据库中存放位置的id
String id;
/**
* 前置通知 用于拦截Controller层记录用户的操作
*
* @param joinPoint 切点
*/
@Around("controllerAspect()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
//读取session中的用户
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//请求的IP
String ip = request.getRemoteAddr();
LogMeg log = new LogMeg();
Object proceed = null;
try {
//获取执行的方法名
log.setOperateMethod((pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName() + "()"));
//获取调用方法的用户ip
log.setOperateIp(ip);//ip放入logMeg实体
//获取执行的模块(注解中的内容)
log.setOperateModule(JSON.toJSONString(getControllerMethodDescription(pjp)));
//获取访问者的唯一标识
log.setVisitorId(SessionUtil.getLoginUserId());
//获取用户名
log.setOperator(SessionUtil.getLoginName());
//获取用户访问的uri
log.setURI(request.getRequestURI());
//获取方法执行前时间
Date date=new Date();
DateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String startTime=format.format(date);
log.setStartTime(startTime);
this.id = PlatformTools.getID();
//aop环绕环绕通知执行的原方法
proceed = pjp.proceed();
//提取controller中ExecutionResult的属性
ExecutionResult result = (ExecutionResult) proceed;
log.setOperateResult(result.getCode());
log.setDetail(result.getMsg());
//获取方法调用结束时间
Date date2=new Date();
DateFormat format2=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String endTime =format2.format(date2);
log.setEndTime(endTime);
log.setId(this.id);
System.out.println("保存前:^^^^^^^^^^^^^^^^^^^^^"+id);
logService.saveLog(log);
System.out.println("保存后^^^^^^^^^^^^^^^^^^^^^"+id);
System.out.println(this);
return proceed;
} catch (Exception e) {
e.printStackTrace();
//记录本地异常日志
logger.error("==环绕通知异常==");
logger.error("异常信息:{}", e.getMessage());
return null;
}
}
/**
* 异常通知 用于拦截service层记录异常日志
*
* @param joinPoint
* @param e
*/
@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//读取session中的用户
SessionUtil.getLoginUserName();
//获取请求ip
String ip = request.getRemoteAddr();
LogException logException = new LogException();
try {
/*==========数据库日志=========*/
logException.setExceptionCode(e.getClass().getName());
logException.setExceptionMessage(e.getMessage());
logException.setExceptionMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
System.out.println("保存前:#################################"+this.id);
System.out.println(this);
logException.setLogOperateId(this.id);
System.out.println(logException.getLogOperateId()+"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
logException.setMethodDescription(getServiceMthodDescription(joinPoint));
//保存数据库
logService.saveLogException(logException);
System.out.println("保存后:#################################"+this.id);
} catch (Exception exception) {
//记录本地异常日志
exception.printStackTrace();
logger.error("==serivce通知异常==");
logger.error("异常信息:{}", e.getMessage());
}
/*==========记录本地异常日志==========*/
logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage());
}
/**
* 获取注解中对方法的描述信息 用于service层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public static String getServiceMthodDescription(JoinPoint joinPoint)
throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(ServiceLog. class).description();
break;
}
}
}
return description;
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public static String getControllerMethodDescription(ProceedingJoinPoint pjp) throws Exception {
String targetName = pjp.getTarget().getClass().getName();
String methodName = pjp.getSignature().getName();
Object[] arguments = pjp.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
description = method.getAnnotation(ControllerLog. class).description();
break;
}
}
}
return description;
}
}
4、接下来写一个service接口及实现类,用来存储获取到的检测信息
package com.hhwy.business.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.hhwy.business.annotation.ServiceLog;
import com.hhwy.business.domain.LogException;
import com.hhwy.business.domain.LogMeg;
import com.hhwy.business.domain.LogMessageDetail;
import com.hhwy.business.domain.LogVo;
import com.hhwy.business.service.LogService;
import com.hhwy.framework.persistent.DAO;
import com.hhwy.framework.persistent.QueryResult;
@Component
public class LogServiceImpl implements LogService{
@Autowired
DAO> dao;
/**
* 保存日志信息
*/
public void saveLog(LogMeg lmg){
dao.save(lmg);
}
public void saveLogException(LogException logException){
dao.save(logException);
}
/**
* 分页查询log信息表
*/
@ServiceLog(description = "查询日志service")
public QueryResult
QueryResult
long total = getLogCount(logVo);
//int a=1/0;
List
queryResult.setTotal(total);
queryResult.setData(data);
return queryResult;
}
public Integer getLogCount(LogVo logVo){
Object result = dao.getOneBySQL("logSpace.sql.projectsSize",logVo);
int total = result == null ? 0 : Integer.valueOf(result.toString());
return total;
}
@SuppressWarnings("unchecked")
public List
if (logVo == null) {
logVo = new LogVo();
}
List
return logMessage;
}
/**
* 通过ID查询所有日志记录详情
*/
public LogMessageDetail getLogMessage(String id){
LogMessageDetail logMessageDetail = new LogMessageDetail();
logMessageDetail.setLogMeg(getLogById(id));//a4e55ef84bda4d09a809a2561e51770d
LogException logException = new LogException();
logException.setLogOperateId(id);//a4e55ef84bda4d09a809a2561e51770d
logMessageDetail.setLogException(getLogExceptionById(logException.getLogOperateId()));
return logMessageDetail;
}
/**
* 通过id获取log详细信息
*/
public LogMeg getLogById(String id){
LogMeg logMeg = dao.findById(id, LogMeg.class);
return logMeg;
}
/**
* 通过id获取logException详细信息
*/
public LogException getLogExceptionById(String id) {
LogException logException = (LogException) dao.getOneBySQL("logSpace.sql.logExceptionPageById", id);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"+logException+id);
return logException;
}
}
这过程中用写了2个实体类(logException记录异常信息,logMeg记录执行正常信息)1个vo (需要传递参数的实体类)1个detail(需要显示到前台的类)
package com.hhwy.business.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
import com.hhwy.framework.persistent.entity.Domain;
@Entity(name="LogException")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name="log_exception")
public class LogException extends Domain{
/**
* serialVersionUID
* @return the serialVersionUID
* @since 1.0.0
*/
private static final long serialVersionUID = 1L;
//表log_operate的id外键
@Column(name="log_operate_id", length=32)
private String logOperateId;
//异常代码
@Column(name="exception_code", length=512)
private String exceptionCode;
//异常信息
@Column(name="exception_message", length=512)
private String exceptionMessage;
//异常方法
@Column(name="exception_method", length=100)
private String exceptionMethod;
//异常方法描述
@Column(name="method_description", length=100)
private String methodDescription;
public String getMethodDescription() {
return methodDescription;
}
public void setMethodDescription(String methodDescription) {
this.methodDescription = methodDescription;
}
public String getLogOperateId() {
return logOperateId;
}
public void setLogOperateId(String logOperateId) {
this.logOperateId = logOperateId;
}
public String getExceptionCode() {
return exceptionCode;
}
public void setExceptionCode(String exceptionCode) {
this.exceptionCode = exceptionCode;
}
public String getExceptionMessage() {
return exceptionMessage;
}
public void setExceptionMessage(String exceptionMessage) {
this.exceptionMessage = exceptionMessage;
}
public String getExceptionMethod() {
return exceptionMethod;
}
public void setExceptionMethod(String exceptionMethod) {
this.exceptionMethod = exceptionMethod;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》
package com.hhwy.business.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.hhwy.framework.persistent.entity.Domain;
@Entity(name="LogMeg")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name="log_operate")
public class LogMeg extends Domain {
/**
* serialVersionUID
* @return the serialVersionUID
* @since 1.0.0
*/
private static final long serialVersionUID = 1L;
//记录操作人ID
@Column(name="visitor_id", length=32)
private String visitorId;
//记录操作人的ip
@Column(name="operate_ip", length=32)
private String operateIp;
//记录操作人的用户名
@Column(name="operator", length=32)
private String operator;
//记录操作模块
@Column(name="operate_module", length=32)
private String operateModule;
//记录操作开始时间
@Column(name="start_time", length=32)
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private String startTime;
//记录模块操作的方法
@Column(name="operate_method", length=256)
private String operateMethod;
//记录操作结果
@Column(name="operate_result", length=32)
private String operateResult;
//记录操作结束时间
@Column(name="end_time", length=100)
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private String endTime;
//记录操作详情
@Column(name="detail", length=100)
private String detail;
//执行的uri
@Column(name="uri", length=100)
private String URI;
public String getURI() {
return URI;
}
public void setURI(String uRI) {
URI = uRI;
}
public String getOperateIp() {
return operateIp;
}
public void setOperateIp(String operateIp) {
this.operateIp = operateIp;
}
public String getOperator() {
return operator;
}
public void setOperator(String operator) {
this.operator = operator;
}
public String getOperateModule() {
return operateModule;
}
public void setOperateModule(String operateModule) {
this.operateModule = operateModule;
}
public String getOperateMethod() {
return operateMethod;
}
public void setOperateMethod(String parammaps) {
this.operateMethod = parammaps;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
public String getVisitorId() {
return visitorId;
}
public void setVisitorId(String visitorId) {
this.visitorId = visitorId;
}
public String getOperateResult() {
return operateResult;
}
public void setOperateResult(String operateResult) {
this.operateResult = operateResult;
}
}
《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》
package com.hhwy.business.domain;
import com.hhwy.business.core.modelutil.PagingProperty;
public class LogVo extends PagingProperty{
//记录操作模块
private String operateModule;
//记录模块操作的方法
private String operateMethod;
//记录操作结果
private String operateResult;
//记录产生详情
private String detail;
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getOperateModule() {
return operateModule;
}
public void setOperateModule(String operateModule) {
this.operateModule = operateModule;
}
public String getOperateMethod() {
return operateMethod;
}
public void setOperateMethod(String operateMethod) {
this.operateMethod = operateMethod;
}
public String getOperateResult() {
return operateResult;
}
public void setOperateResult(String operateResult) {
this.operateResult = operateResult;
}
}
《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》《》
package com.hhwy.business.domain;
public class LogMessageDetail{
//封装了两个实体类作为参数
private LogMeg logMeg;
private LogException logException;
public LogMeg getLogMeg() {
return logMeg;
}
public void setLogMeg(LogMeg logMeg) {
this.logMeg = logMeg;
}
public LogException getLogException() {
return logException;
}
public void setLogException(LogException logException) {
this.logException = logException;
}
}
5、数据库同样我建立了两张表、分别存储logMeg和logException
log_exception表
log_operate表:
6、那么接下来的工作都结束了,可以检测我们的成果
1、页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
详情页detail
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
用到的controller类
package com.hhwy.business.controller;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.hhwy.business.annotation.ControllerLog;
import com.hhwy.business.core.modelutil.ExecutionResult;
import com.hhwy.business.core.modelutil.ReturnCode;
import com.hhwy.business.domain.LogMeg;
import com.hhwy.business.domain.LogMessageDetail;
import com.hhwy.business.domain.LogVo;
//import com.hhwy.business.logUtil.StaticLogUtil;
import com.hhwy.business.service.LogService;
import com.hhwy.framework.persistent.QueryResult;
@RestController
@RequestMapping("/LogController")
public class LogController {
@Autowired
LogService logService;
public static final Logger log = LoggerFactory.getLogger(LogMeg.class);
/**
* 通过传入实体lmg,增加日志信息
* saveLogMessage(描述这个方法的作用)
* @param lmg
* @return
* Object
* @exception
* @since 1.0.0
*/
@RequestMapping(value = "saveLogMessage", method = RequestMethod.GET)
public Object saveLogMessage(@PathVariable LogMeg lmg){
ExecutionResult result = new ExecutionResult();
try {
logService.saveLog(lmg);
result.setCode(ReturnCode.RES_SUCCESS); //设置返回结果编码:成功
result.setFlag(true); //设置是否成功标识
result.setMsg("保存成功!"); //设置返回消息,根据实际情况修改
} catch (Exception e) {
log.error("保存失败!",e); //记录异常日志,根据实际情况修改
result.setCode(ReturnCode.RES_FAILED); //设置返回结果编码:失败
result.setFlag(false); //设置是否成功标识
result.setData(null); //设置返回结果为空
result.setMsg("保存失败!"); //设置返回消息,根据实际情况修改
return result;
}
return result;
}
/**
* 获取日志列表,分页显示
* getLogByPage(描述这个方法的作用)
* @param logMeg
* @return
* @throws Exception
* Object
* @exception
* @since 1.0.0
*/
@ControllerLog(description = "日志添加操作")
@RequestMapping(value = "/LogPage", method = RequestMethod.POST)
public Object getLogByPage(HttpServletRequest req, @RequestBody(required=false) LogVo logVo){
ExecutionResult result = new ExecutionResult();
System.out.println("controller的地址:"+ this);
try {
QueryResult
result.setTotal(queryResult.getTotal()); //设置数据总条数
result.setRows(queryResult.getRows() == null ? queryResult.getData() : queryResult.getRows()); //设置数据列表
result.setCode(ReturnCode.RES_SUCCESS); //设置返回结果编码:成功
result.setFlag(true); //设置是否成功标识
result.setMsg("查询成功!"); //设置返回消息,根据实际情况修改
} catch (Exception e) {
log.error("查询失败!",e); //记录异常日志,根据实际情况修改
result.setCode(ReturnCode.RES_FAILED); //设置返回结果编码:失败
result.setFlag(false); //设置是否成功标识
result.setData(null); //设置返回结果为空
result.setMsg("查询失败!"); //设置返回消息,根据实际情况修改
}
return result;
}
@RequestMapping(value = "/getLogMessage/{id}", method = RequestMethod.GET)
public Object getLogMessage(@PathVariable String id) {
ExecutionResult result = new ExecutionResult();
try {
LogMessageDetail logMessageDetaileg = logService.getLogMessage(id);
result.setCode(ReturnCode.RES_SUCCESS); //设置返回结果编码:成功
result.setFlag(true); //设置是否成功标识
result.setData(logMessageDetaileg); //设置实体
result.setMsg("查询成功!"); //设置返回消息,根据实际情况修改
} catch (Exception e) {
log.error("查询失败!",e); //记录异常日志,根据实际情况修改
result.setCode(ReturnCode.RES_FAILED); //设置返回结果编码:失败
result.setFlag(false); //设置是否成功标识
result.setData(null); //设置返回结果为空
result.setMsg("查询失败!"); //设置返回消息,根据实际情况修改
return result;
}
return result;
}
}
6、大功告成
使用过程中只需要在这两个地方加上注解就可以了
controller层
service层加
ok,可以了