数据库
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `sys_log`
-- ----------------------------
DROP TABLE IF EXISTS `sys_log`;
CREATE TABLE `sys_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL COMMENT '用户名',
`operation` varchar(255) NOT NULL COMMENT '操作',
`method` varchar(255) NOT NULL COMMENT '方法名',
`params` varchar(255) DEFAULT NULL COMMENT '参数',
`ip` varchar(255) DEFAULT NULL,
`create_date` datetime NOT NULL COMMENT '操作时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of sys_log
-- ----------------------------
INSERT INTO `sys_log` VALUES ('1', 'admin', '登陆成功', 'login', null, '0:0:0:0:0:0:0:1', '2020-03-06 14:47:16');
INSERT INTO `sys_log` VALUES ('2', 'admin', '登陆成功', 'login', null, '0:0:0:0:0:0:0:1', '2020-03-06 14:54:09');
INSERT INTO `sys_log` VALUES ('3', 'admin', '登陆成功', 'login', null, '127.0.0.1', '2020-03-06 14:56:25');
INSERT INTO `sys_log` VALUES ('4', 'admin', '退出系统', 'loginout', null, null, '2020-03-06 14:56:27');
实体类
@Setter
@Getter
public class SysLog implements Serializable {
private Long id;
private String username; //用户名
private String operation; //操作
private String method; //方法名
private String params; //参数
private String ip; //ip地址
private Date createDate; //操作时间
切面
切面中仅记录用户除登陆和退出以外的操作
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
/**
* @ProjectName:
* @Package: 系统日志:切面处理类 切面只记录除登陆和退出的记录 登录退出日志在监听器中记录
* @Author: huat
* @Date: 2020/3/5 22:26
* @Version: 1.0
*/
@Aspect
@Component
public class SysLogAspect {
@Autowired
private SysLogService sysLogService;
//定义切点 @Pointcut
//在注解的位置切入代码
@Pointcut("@annotation( cn.bdqn.utils.MyLog)")
public void logPoinCut() {
}
//切面 配置通知
@AfterReturning("logPoinCut()")
public void saveSysLog(JoinPoint joinPoint) {
//保存日志
SysLog sysLog = new SysLog();
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
//获取操作
MyLog myLog = method.getAnnotation(MyLog.class);
if (null!=myLog) {
String value = myLog.value();
sysLog.setOperation(value);//保存获取的操作
}
//获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
//获取请求的方法名
String methodName = method.getName();
sysLog.setMethod(className + "." + methodName);
sysLog.setCreateDate(new Date());
//获取请求
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
//获取用户名
SysUser sysUser=(SysUser) request.getSession().getAttribute("user");
sysLog.setUsername(sysUser.getUsername());
//获取用户ip地址
sysLog.setIp(IpUtiles.getRealIp(request));
//请求的参数
Object[] args = joinPoint.getArgs();
//将参数所在的数组转换成json
String params = JSON.toJSONString(args);
sysLog.setParams(params);
//调用service保存SysLog实体类到数据库
sysLogService.saveSysLog(sysLog);
}
}
获取ip工具类
如果用户经过多层代理,工具类依然不能获取用户真正ip
import javax.servlet.http.HttpServletRequest;
/**
* @ProjectName:
* @Package:
* @Author: huat
* @Date: 2020/3/5 22:50
* @Version: 1.0
*/
public class IpUtiles {
/**
* 获取真实IP
* @param request 请求体
* @return 真实IP
*/
public static String getRealIp(HttpServletRequest request) {
// 这个一般是Nginx反向代理设置的参数
String ip = request.getHeader("X-Real-IP");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
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();
}
// 处理多IP的情况(只取第一个IP)
if (ip != null && ip.contains(",")) {
String[] ipArray = ip.split(",");
ip = ipArray[0];
}
return ip;
}
}
自定义注解
切面仅在子定义注解的方法上生效,自定义注解为接口名称,这里我的注解为@MyLog
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface MyLog {
String value() default "";
}
用户退出登陆操作
因为用户退出有可能直接关闭浏览器等非正常操作,所以这里直接用session监听器去监听
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.Date;
/**
* @ProjectName:
* @Package:
* @Author: huat
* @Date: 2020/3/6 13:49
* @Version: 1.0
*/
@Component
public class MyHttpSessionListener implements HttpSessionListener {
@Autowired
SysLogService sysLogService;
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
SysUser sysUser=(SysUser) httpSessionEvent.getSession().getAttribute("user");
SysLog sysLog=new SysLog();
sysLog.setUsername(sysUser.getUsername());
sysLog.setMethod("loginout");
sysLog.setCreateDate(new Date());
sysLog.setIp(null);
sysLog.setOperation("退出系统");
sysLog.setParams(null);
sysLogService.saveSysLog(sysLog);
}
}
登陆
因为登陆操作使用的是security的方法,所以在登陆后直接跳转一个我们自定义的方法,在此方法中记录用户操作然后在进入首页
@RequestMapping("jumpIndex")
public String jumpIndex(HttpSession session) {
//记录用户登陆操作
SysLog sysLog=new SysLog();
sysLog.setUsername(SecurityContextHolder.getContext().getAuthentication().getName());
sysLog.setCreateDate(new Date());
HttpServletRequest request=((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
sysLog.setIp(IpUtiles.getRealIp(request));
sysLog.setOperation("登陆成功");
sysLog.setMethod("login");
sysLogService.saveSysLog(sysLog);
return "redirect:"+request.getContextPath()+"sys/user/index";
}