目的
为了实现用户做的每一步操作都被后台记录下来。
思路
1,创建自定义注解。
2,在要记录的方法中加上自定义注解。
3,拦截浏览器发送的请求。
4,加载访问的类
5,获取这个方法的方法名,然后根据AOP拦截的请求进行判断是否是同一个。
6,判断这个拦截的方法有没有自定义的注解。
7,获取注解的值,然后写入数据库。
实现
创建数据库
DROP TABLE IF EXISTS `sys_log`;
CREATE TABLE `sys_log` (
`id` int(64) NOT NULL AUTO_INCREMENT,
`user_name` varchar(64) DEFAULT NULL,
`optIp` varchar(255) DEFAULT NULL COMMENT '操作IP',
`operation` varchar(255) DEFAULT NULL COMMENT '操作',
`content` varchar(255) DEFAULT NULL COMMENT '内容',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx` (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 COMMENT='日志管理';
自定义注解类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OperationLogger {
String modelName() default "";
String option();
}
面向切面编程,aop拦截类
@Aspect
public class LogAspect {
@Autowired
private LogService logService;
/**
* 用户创建订单
*/
@Pointcut("@annotation(com.zxzc.aspect.OperationLogger)")
public void controllerAspect(){
System.out.println("切入点》》》》");
}
@AfterReturning("controllerAspect()")
public void doAfterReturn(JoinPoint joinPoint){
System.out.println("==========后置通知=========");
handleLog(joinPoint);
}
private void handleLog(JoinPoint joinPoint){
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
UserInfo user = (UserInfo) request.getSession().getAttribute("userInfo");
//获取横切的方法名
String methodName = joinPoint.getSignature().getName();
// String methodName = signature.substring(
// signature.lastIndexOf(".")+1,signature.indexOf("("));
//获取拦截的class
String classType = joinPoint.getTarget().getClass().getName();
//加载这个类
Class<?> clazz = Class.forName(classType);
//获取这个类上的方法名
Method[] methods = clazz.getDeclaredMethods();
System.out.println("methodName:"+methodName);
/**
* 循环判断,对所有方法进行循环遍历
*/
for (Method method:methods){
// 如果这个方法上面的注解是否含有自定义的注解
// 并且方法名等于切点访问的方法名
if (method.isAnnotationPresent(OperationLogger.class)
&&method.getName().equals(methodName)){
//获取method的注解
OperationLogger operationLogger = method.getAnnotation(OperationLogger.class);
//也可以用这种方式获取
/*Annotation[] annotations = method.getAnnotations();
for (Annotation annotation:annotations){
if (annotation instanceof OperationLogger){
OperationLogger operationLogger = (OperationLogger) annotation;
}
}*/
SysLog sysLog = new SysLog();
if (user!=null){
sysLog.setUserName(user.getUserName());
sysLog.setOptip(RequestIpUtil.getRemoteHost(request));
}else{
sysLog.setUserName("未登录用户");
sysLog.setOptip(RequestIpUtil.getRemoteHost(request));
}
sysLog.setCreateTime(new Date());
sysLog.setOperation(operationLogger.option());
sysLog.setContent(operationLogger.modelName());
logService.insertLog(sysLog);
}
}
} catch (Exception e){
e.printStackTrace();
}
}
}
LogService接口
public interface LogService {
void insertLog(SysLog sysLog);
}
LogServiceImpl类
@Service("logService")
public class LogServiceImpl implements LogService {
@Autowired
private SysLogMapper sysLogMapper;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void insertLog(SysLog sysLog) {
sysLogMapper.insertSelective(sysLog);
}
}
SysLogMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.zxzc.dao.SysLogMapper" >
<resultMap id="BaseResultMap" type="com.zxzc.pojo.SysLog" >
<constructor >
<idArg column="id" jdbcType="INTEGER" javaType="java.lang.Integer" />
<arg column="user_name" jdbcType="VARCHAR" javaType="java.lang.String" />
<arg column="optIp" jdbcType="VARCHAR" javaType="java.lang.String" />
<arg column="operation" jdbcType="VARCHAR" javaType="java.lang.String" />
<arg column="content" jdbcType="VARCHAR" javaType="java.lang.String" />
<arg column="create_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
</constructor>
</resultMap>
<sql id="Base_Column_List" >
id, user_name, optIp, operation, content, create_time
</sql>
<insert id="insertSelective" parameterType="com.zxzc.pojo.SysLog" >
insert into sys_log
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="id != null" >
id,
</if>
<if test="userName != null" >
user_name,
</if>
<if test="optip != null" >
optIp,
</if>
<if test="operation != null" >
operation,
</if>
<if test="content != null" >
content,
</if>
<if test="createTime != null" >
create_time,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="id != null" >
#{id,jdbcType=INTEGER},
</if>
<if test="userName != null" >
#{userName,jdbcType=VARCHAR},
</if>
<if test="optip != null" >
#{optip,jdbcType=VARCHAR},
</if>
<if test="operation != null" >
#{operation,jdbcType=VARCHAR},
</if>
<if test="content != null" >
#{content,jdbcType=VARCHAR},
</if>
<if test="createTime != null" >
#{createTime,jdbcType=TIMESTAMP},
</if>
</trim>
</insert>
</mapper>
springmvc.xml配置文件中加入
<aop:config proxy-target-class="true"></aop:config>
<aop:aspectj-autoproxy />
<bean id="logAspect" class="com.zxzc.aspect.LogAspect" />
记录获取Ip地址的Util类
public class RequestIpUtil {
public static String getRemoteHost(javax.servlet.http.HttpServletRequest request){
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
ip = request.getRemoteAddr();
}
return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
}
}
然后在要拦截的方法上加上
@OperationLogger(modelName = "操作名称",option = "操作接口")
运行结果: