版权声明:本文由施勇原创,转载请注明作者和出处! https://blog.csdn.net/shiyong1949/article/details/82936377
1,开发环境
操作系统:Windows 7
JDK:1.8.0_161
Eclipse:Mars.2 Release (4.5.2)
2,自定义注解类UserLog
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserLog {
/** 要执行的操作内容比如:用户:XXX登录成功 **/
public String operationContent() default "";
}
3,日志处理切面UserLogAspect
这里使用的是后通知,当业务代码执行完成后,再执行日志保存。
@Aspect
@Component
public class UserLogAspect {
@Autowired
private ILogSysUserService logSysUserService;
//Controller层切点
@Pointcut("@annotation(com.riskraider.common.annotation.UserLog)")
public void controllerAspect() {
}
/**
* 前置通知 用于拦截Controller层记录用户的操作
*
* @param joinPoint 切点
*/
@SuppressWarnings("rawtypes")
@After("controllerAspect()")
public void doAfter(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpSession session = request.getSession();
//读取session中的用户
SysAccount account = (SysAccount) session.getAttribute("account");
if(null != account){
//获取请求ip
String ip = request.getRemoteAddr();
try{
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 operationUrl = request.getServletPath();
String operationContent = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
//凡是加了UserLog注解的方法都记录日志
if(null != method.getAnnotation(UserLog.class)){
operationContent = method.getAnnotation(UserLog.class).operationContent();
//获取用户请求方法的参数并序列化为JSON格式字符串
Map<String,Object> nameAndArgs = null;
if(null != joinPoint.getArgs() && joinPoint.getArgs().length > 0) {
//获取参数名称和值
nameAndArgs = getParameMap(joinPoint);
}
SysUserLogDTO log = new SysUserLogDTO();
log.setUserId(account.getAccountId());
log.setUserName(account.getName());
log.setUserIp(ip);
log.setOperationUrl(operationUrl);
log.setOperationContent(operationContent);
log.setParameMap(nameAndArgs);
logSysUserService.saveSysUserLog(log);
break;
}
}
}
}
}catch(Exception e) {
LoggerUtils.error("记录用户操作日志失败!", e);
}
}
}
/**
* @Title: getParameMap
* @Description: 获取参数的名称和值
* @author: 施勇
* @date: 2018年10月3日 下午3:12:26
* @param: @param joinPoint
* @param: @return
* @return: Map<String,Object>
* @throws
*/
public Map<String,Object> getParameMap(JoinPoint joinPoint){
Map<String, Object> map = new HashMap<String, Object>();
Object[] args = joinPoint.getArgs(); // 参数值
String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames(); // 参数名
for(int i=0;i<argNames.length;i++){
if("response".equals(argNames[i]) || "request".equals(argNames[i]) || "pwd".equals(argNames[i])){
continue;
}else{
map.put(argNames[i], args[i]);
}
}
return map;
}
}
getParameMap()这个方法是用于获取用户请求中的参数,只需要保存业务相关的参数就可以了,所以将request和response过滤掉了,同时也不保存用户登录时的密码。对这个参数Map在保存到数据库中的时候可以转换成JSONString,这样方便查看。
4,使用注解
在需要记录日志的地方加上注解
@RequestMapping("/doLogin")
@ResponseBody
@UserLog(operationContent="登录系统")
public ResultBean doLogin(String loginName, String pwd, HttpServletRequest request,HttpServletResponse response){
}
这里重点是AOP切面保存用户操作日志,其他AOP相关配置就不重复说了。