1、前言
最近开发了一个项目,由于项目在整个开发过程中处于赶时间状态(每个项目都差不多如此)所以项目在收尾阶段发现缺少记录系统日志功能,以前系统都是直接写在每个模块的代码中,然后存入表单,在页面可以查看部分日志。这个系统并没有此要求,因此便想到了做一个系统通用的日志记录,主要记录数据有:操作的用户名、操作的远程IP地址、操作时间、操作对象、操作方法、操作的一些参数以及操作结果。由于系统框架是基于ssh框架的,所以最终考虑使用struts2的自带拦截器Interceptor来实现。
2、什么拦截器?
拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。谈到拦截器,还有一个词大家应该知道——拦截器链(Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
拦截器的原理和大致流程
1.ActionInvocation初始化时,根据配置,加载Action相关的所有Interc eptor。
2. 通过ActionInvocation.invoke方法调用Action实现时,执行Interceptor。
Interceptor将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为具有很好的重用性。XWork、WebWork的许多功能都是有Interceptor实现,可以在配置文件中组装Action用到的Interceptor,它会按照你指定的顺序,在Action执行前后运行。
3、实现代码
package com.teraee.tasystem.interceptor;
import java.net.InetAddress;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.teraee.tasystem.service.base.SysConfigManager;
import com.teraee.tasystem.service.base.SysOperationLogManager;
import com.teraee.tasystem.support.SpringUtil;
import com.teraee.tasystem.util.Log;
import com.teraee.tasystem.util.StringUtil;
import com.teraee.tasystem.util.SysOpConstant;
/**
* 所有Action调用之前执行的拦截器
*@author LH
*@data 2018年3月7日
*/
@SuppressWarnings("serial")
public class OperationInterceptor extends AbstractInterceptor {
private static Log log = Log.getLoger(new Object() {
public Class getClassName() {
return this.getClass();
}
}.getClassName());
//无须记录Action调用日志的方法
private static String[] unRecordLogResources={"validateTeaSnapNum",//校验教师创建的快照数量是否超过场景限制
"validateServSnapNum",//校验应用服务创建的快照数量是否超过场景限制
"getRoleList",//获取角色列表
"initTaeCfg",//初始化登录配置
"getIdvEnable",//IDV功能是否开启
"getSysOpLogListByPage",//查询系统操作日志
"getSysOpType",//得到系统操作方法
"getStaticSwitch",//获取统计页面的开关状态
"init",//登录初始化,
"initEnv",//初始化登录环境
"getInitUrl",//初始化登录环境
"getAllUrl",//获取线上请求地址url
"initCfgInfo",//正常登录
"getURLfromConf",//获取配置文件信息
"loginStatus",//检测用户登录状态
"localAccountValidate",//本地账号验证模式
"verifyLocal",//本地登录账号校验
"verifyRemoteByQQ",//第三方登录远程同步并返回用户角色
"verifyRemote",//用户登录同步到本地
"buildTerLoginRelation"//添加终端登录关系
};
public String intercept(ActionInvocation invocation) throws Exception {
// log.loger.info("operation intercept begin!");
HttpServletRequest req = ServletActionContext.getRequest();
String ipaddr = getRemoteIpAddr(req);//获取系统操作远程ip
String userName = (String) req.getSession().getAttribute("usrName");//登录用户
log.loger.info("ipaddr="+ipaddr+"userName="+userName);
String actionClass = invocation.getProxy().getAction().getClass().getName();
if(actionClass.indexOf("$") != -1){
actionClass = actionClass.substring(0, actionClass.indexOf("$"));
}
if(actionClass.indexOf(".") != -1){
actionClass = actionClass.substring(actionClass.lastIndexOf(".")+1);
}
String actionName = invocation.getProxy().getActionName();
String url="";
if(StringUtil.isNotBlank(req.getQueryString())){
url = req.getRequestURI()+"?"+URLDecoder.decode(req.getQueryString(),"UTF-8");
}else{
url = req.getRequestURI();
}
log.loger.info("actionClass="+actionClass+" actionName="+actionName+" url="+url);
Date startTime = new Date();
try{
//实际方法执行阶段
invocation.invoke();
}catch(Exception exception){
}finally{
// log.loger.info("operation intercept end!");
if(!isNoRecordResource(actionName)){
// log.loger.info("save action log start!");
Date endTime = new Date();
long costTime = endTime.getTime() - startTime.getTime();
//生成一条用户操作记录
SysOperationLogManager sysOperationLogManager = (SysOperationLogManager) SpringUtil.getObject("sysOperationLogManager");
sysOperationLogManager.saveSysOperationLog(userName,actionClass,actionName,url,ipaddr,startTime,endTime,costTime,SysOpConstant.SYS_LOG_ACTION);
}
}
return null;
}
//是否是无需记录的Action日志类型
private boolean isNoRecordResource(String actionName){
String methodName = actionName.split("_")[1];
for(int i=0;i<unRecordLogResources.length;i++){
if(StringUtils.equals(methodName, unRecordLogResources[i])) {
return true;
}
}
return false;
}
protected String getRemoteIpAddr(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.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip= request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
try {
ip= InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return ip.split(",")[0];
}
}
<!-- 用户拦截器定义在该元素下 -->
<interceptors>
<interceptor name="operationInterceptor" class="com.teraee.tasystem.interceptor.OperationInterceptor" />
<interceptor-stack name="defualtSecurityStackWithAuthentication">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="operationInterceptor" />
</interceptor-stack>
</interceptors>
4、效果截图
点击系统查询用户列表生成系统操作日志
进入拦截器获取到执行的方法名以及Action等