《web工程aop实现前台操作日志记录》初稿

写日志功能很繁琐,博主废了一些时间写出来分享,用的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 getLogMessageByPage(LogVo logVo){
QueryResult queryResult = new QueryResult();
long total = getLogCount(logVo);
//int a=1/0;
List data = getLogMessage(logVo);
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 getLogMessage(LogVo logVo){
if (logVo == null) {
logVo = new LogVo();
}
List logMessage = (List) dao.getBySql("logSpace.sql.logPage", logVo);
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 queryResult = logService.getLogMessageByPage(logVo);
    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,可以了

你可能感兴趣的:(《web工程aop实现前台操作日志记录》初稿)