J2EE项目中出于安全的角度考虑,用户行为审计日志功能必不可少,通过本demo可以实现如下功能:
1.项目中记录审计日志的方法.
2.struts拦截器的基本配置和使用方法.
3.struts拦截器中获得用户访问的类和访问的方法.
4.注解的基本用法,以及在struts拦截器中使用注解.
5.struts拦截器中获得用户访问的IP地址,可扩展对IP进行鉴权功能(允许或限制某些IP).
系统运行一段时间后,通过这些审计日志还可以挖掘的内容:
1.用户行为审计,发现最异常情况及时调整和处理.
2.统计哪些模块访问的频度最高,调整界面把用户访问最高的模块放到显著位置.
3.统计各个功能模块方法的访问时长,有助于我们进行程序性能的优化.
4.用户关联行为分析,优化访问流程,提高用户体验.
项目结构:
功能代码:
AuditLogInterceptor.java(知识点见注释):
package com.tgb.lk.auditlog; import java.lang.reflect.Method; import java.util.Date; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; import com.tgb.lk.model.AuditLog; public class AuditLogInterceptor extends MethodFilterInterceptor { @Override protected String doIntercept(ActionInvocation actioninvocation) throws Exception { AuditLog auditLog = new AuditLog(); auditLog.setStartTime(new Date());// 设置开始时间 String result = actioninvocation.invoke();// 递归调用拦截器 auditLog.setEndTime(new Date());// 设置结束时间 String userId = (String) ServletActionContext.getRequest().getSession() .getAttribute("userId"); auditLog.setUserId(userId);// 设置登录用户的Id,在用户登录时把id保存到session中,这里可扩展判断用户是否登录的验证和权限验证 /*String name = actioninvocation.getInvocationContext().getName(); String methodName = ""; // struts.xml中配置: // <package name="user" namespace="/user" extends="default"> // <action name="user_*" class="com.tgb.lk.action.UserAction" method="{1}"> // // 访问地址: http://127.0.0.1:8080/AuditLogDemo/user/user_add // http://127.0.0.1:8080/AuditLogDemo/user/user_del if (name != null && name.contains("_")) { methodName = name.substring(name.indexOf("_") + 1, name.length()); }*/ String methodName = actioninvocation.getProxy().getMethod(); if (methodName.length() > 0) { Object action = actioninvocation.getAction(); Class clazz = action.getClass(); // 如果设置了注解则读取注解的内容,如果没有设置注解则记录登录的class名 if (clazz.isAnnotationPresent(AuditLogger.class)) { AuditLogger talClazz = (AuditLogger) clazz .getAnnotation(AuditLogger.class); auditLog.setClazz(talClazz.log()); } else { auditLog.setClazz(clazz.getSimpleName()); } Method method = action.getClass().getMethod(methodName, null); // 如果设置了注解则读取注解的内容,如果没有设置注解则记录登录的method名 if (method.isAnnotationPresent(AuditLogger.class)) { AuditLogger alm = (AuditLogger) method .getAnnotation(AuditLogger.class); auditLog.setMethod(alm.log()); } else { auditLog.setMethod(methodName); } String ip = ServletActionContext.getRequest().getRemoteAddr(); auditLog.setIp(ip);// 记录登录的IP,这里还可以对IP进行鉴权功能(允许或限制某些IP) auditLog.setResult(result);// 记录登录时返回的结果. System.out.println(auditLog); // auditLogService.save(auditLog); //保存入库 } return result; // 跳转 } }
struts.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/" extends="struts-default"> <interceptors> <!-- 日志审计拦截器 --> <interceptor name="auditlog" class="com.tgb.lk.auditlog.AuditLogInterceptor" /> <interceptor-stack name="myStack"> <interceptor-ref name="auditlog"> <!-- 配置到excludeMethods中的方法将不记录日志 --> <param name="excludeMethods">testExclude</param> </interceptor-ref> <!-- struts默认的拦截器 --> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors> <default-interceptor-ref name="myStack" /> </package> <!-- 注意extends="default" --> <package name="user" namespace="/user" extends="default"> <action name="user_*" class="com.tgb.lk.action.UserAction" method="{1}"> <result name="add">/index.jsp</result> <result name="del">/index.jsp</result> <result name="modify">/index.jsp</result> <result name="view">/index.jsp</result> </action> </package> </struts>
注解类AuditLogger.java:
package com.tgb.lk.auditlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target( { java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE }) public @interface AuditLogger { public abstract String log(); }
Struts的Action中使用配置:
package com.tgb.lk.action; import com.tgb.lk.auditlog.AuditLogger; @AuditLogger(log = "用户管理") public class UserAction { @AuditLogger(log = "添加用户") public String add() { return "add"; } @AuditLogger(log = "删除用户") public String del() { return "del"; } @AuditLogger(log = "修改用户") public String modify() { return "modify"; } @AuditLogger(log = "浏览用户信息") public String view() { return "view"; } }
实体类AuditLog.java
package com.tgb.lk.model; import java.util.Date; public class AuditLog { private int id; private String userId; private Date startTime; private Date endTime; private String ip; private String clazz; private String method; private String result; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public Date getStartTime() { return startTime; } public void setStartTime(Date startTime) { this.startTime = startTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public String getResult() { return result; } public void setResult(String result) { this.result = result; } @Override public String toString() { return "AuditLog [id=" + id + ", userId=" + userId + ", ip=" + ip + ", startTime=" + startTime + ", endTime=" + endTime + ", clazz=" + clazz + ", method=" + method + ", result=" + result + "]"; } }
代码下载地址: http://download.csdn.net/detail/lk_blog/6003581
限于本人水平有限,很多地方写的并不完美,望大家不吝赐教,希望在和大家的交流中得到提高.