实现的大致思路是:
1.前期准备,设计日志表和日志类,编写日志Dao和Service以及实现
2.自定义注解,注解中加入几个属性,属性可以标识操作的类型(方法是做什么的)
3.编写切面,切点表达式使用上面的注解直接定位到使用注解的方法,
4.编写通知,通过定位到方法,获取上面的注解以及注解的属性,然后从session中直接获取或者从数据库获取当前登录用户的信息,最后根据业务处理一些日志信息之后调用日志Service存储日志。
下面是具体实现:
1.日志数据库:
CREATE TABLE `logtable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`operateor` varchar(5) DEFAULT NULL,
`operateType` varchar(20) DEFAULT NULL,
`operateDate` datetime DEFAULT NULL,
`operateResult` varchar(4) DEFAULT NULL,
`remark` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
2.日志实体类:
Logtable.java
package cn.xm.exam.bean.log;
import java.util.Date;
public class Logtable {
private Integer id;
private String operateor;
private String operatetype;
private Date operatedate;
private String operateresult;
private String remark;
}
3.日志的Dao层使用的是Mybatis的逆向工程导出的mapper
4.日志的Service层和实现类
5.自定义注解:
package cn.xm.exam.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 日志注解
*
*
*/
@Target(ElementType.METHOD) // 方法注解
@Retention(RetentionPolicy.RUNTIME) // 运行时可见
public @interface LogAnno {
String operateType();// 记录日志的操作类型
}
6.在需要日志记录的方法中使用注解:(此处将注解写在DictionaryServiceImpl方法上)
package cn.xm.exam.service.impl.common;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import cn.xm.exam.annotation.LogAnno;
import cn.xm.exam.bean.common.Dictionary;
import cn.xm.exam.bean.common.DictionaryExample;
import cn.xm.exam.mapper.common.DictionaryMapper;
import cn.xm.exam.mapper.common.custom.DictionaryCustomMapper;
import cn.xm.exam.service.common.DictionaryService;
/**
* 字典表的实现类
*
* @author
*
*/
@Service
public class DictionaryServiceImpl implements DictionaryService {
@Resource
private DictionaryMapper dictionaryMapper;/**
* 1、添加字典信息
*/
@LogAnno(operateType = "添加了一个字典项")
@Override
public boolean addDictionary(Dictionary dictionary) throws SQLException {
int result = dictionaryMapper.insert(dictionary);
if (result > 0) {
return true;
} else {
return false;
}
}
}
7.编写通知,切入到切点形成切面(注解AOP实现,环绕通知记录日志。)
注意:此处是注解AOP,因此在spring配置文件中开启注解AOP
<!-- 1.开启注解AOP -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
LogAopAspect.java
package cn.xm.exam.aop;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Date;
import org.apache.struts2.ServletActionContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import cn.xm.exam.annotation.LogAnno;
import cn.xm.exam.bean.log.Logtable;
import cn.xm.exam.bean.system.User;
import cn.xm.exam.service.log.LogtableService;
/**
* AOP实现日志
*
*
*/
@Component
@Aspect
public class LogAopAspect {
@Autowired
private LogtableService logtableService;// 日志Service
/**
* 环绕通知记录日志通过注解匹配到需要增加日志功能的方法
*
* @param pjp
* @return
* @throws Throwable
*/
@Around("@annotation(cn.xm.exam.annotation.LogAnno)")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
// 1.方法执行前的处理,相当于前置通知
// 获取方法签名
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
// 获取方法
Method method = methodSignature.getMethod();
// 获取方法上面的注解
LogAnno logAnno = method.getAnnotation(LogAnno.class);
// 获取操作描述的属性值
String operateType = logAnno.operateType();
// 创建一个日志对象(准备记录日志)
Logtable logtable = new Logtable();
logtable.setOperatetype(operateType);// 操作说明
// 整合了Struts,所有用这种方式获取session中属性(亲测有效)
User user = (User) ServletActionContext.getRequest().getSession().getAttribute("userinfo");//获取session中的user对象进而获取操作人名字
logtable.setOperateor(user.getUsername());// 设置操作人
Object result = null;
try {
//让代理方法执行
result = pjp.proceed();
// 2.相当于后置通知(方法成功执行之后走这里)
logtable.setOperateresult("正常");// 设置操作结果
} catch (SQLException e) {
// 3.相当于异常通知部分
logtable.setOperateresult("失败");// 设置操作结果
} finally {
// 4.相当于最终通知
logtable.setOperatedate(new Date());// 设置操作日期
logtableService.addLog(logtable);// 添加日志记录
}
return result;
}
}