先看效果,其他程序员使用的时候,如下,findAllCountry被调用时,调用时间、调用人、方法名、方法描述、testValue、testValue2的值都将被存入数据库中。
public class TestAction extends ActionSupport { private String testValue = "hellow"; private String testValue2 = "hellow2"; @IDBLog(desc="分页查询数据", params="testValue;testValue2;") public void findAllCountry(){ System.out.println("in CountryAction :findAllCountry"); //TODO: } //注解中要记录该参数的值,必须提供get方法 public String getTestValue() { return testValue; } public String getTestValue2() { return testValue2; } }
1:先写一个DB日志实体:
/** * * 数据库日志记录实体 <p> * @author zhuoyueping @date 2012-5-8 <br> * @version <br> */ public class DBLog extends Core { /** 操作的用户 **/ protected String remote_user; /** 操作的时间 **/ protected Date operate_date; /** 操作的action **/ protected String operation; /** 操作的action的描述 **/ protected String oper_desc; /** 操作的action的成员变量 **/ protected String oper_params; //getter 、 setter }
2:注解IDBLog,指定了该注解的action方法:
/** * 定义注入Action的log远程业务接口<p> * @author zhuoyueping @date 2012-05-7<br> * @version 1.0<br> */ @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface IDBLog { /** * 指定action方法的描述名称 如:查询用户 * @return */ public abstract String desc(); /** * 指定action方法的成员参数名称,指定的参数应该覆盖toString方法,多个成员参数用;分隔 * @return */ public abstract String params() default ""; }
3:structs2的拦截器代码,CommonBaseInterceptor是公司内部对拦截器的简单封装类
/** * 以拦截器的方式动态注入action方法,记录用户、时间、操作的action * @author zhuoyueping @date 2012-04-08<br> * @version 1.0<br> */ public class DBLogInteceptor extends CommonBaseInterceptor { /** * 系统默认生成版本号 */ private static final long serialVersionUID = 1L; private IDBLogService dbLogService; /** * 实现拦截功能<p> */ public String intercept(ActionInvocation actionInvocation) throws Exception { Object action = actionInvocation.getAction(); java.lang.reflect.Method[] methods = action.getClass().getDeclaredMethods(); for (Method method : methods) { boolean hasAnnotation = method.isAnnotationPresent(IDBLog.class); if (hasAnnotation) { IDBLog avicLog = method.getAnnotation(IDBLog.class); //上下文 ActionContext actionContext = actionInvocation.getInvocationContext(); HttpServletRequest request= (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST); //登陆用户 String uid =request.getRemoteUser(); //操作时间 Date currentDate = new Date(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); String date = sdf.format(currentDate); //操作方法: String operation = action.getClass().getName()+"."+method.getName(); //操作的方法描述 String desc = avicLog.desc(); //参数 String params = avicLog.params(); List<String> fieldNames = splitParams(params); StringBuffer sb = new StringBuffer(); if(fieldNames!=null){ for(String fieldName:fieldNames){ //调用getXX方法 String methodName = convertMethodName(fieldName); Method getMethod=action.getClass().getMethod(methodName, new Class[]{}); Object fieldValue=getMethod.invoke(action, new Object[]{}); String value = formatFidlParam(fieldName,fieldValue.toString()); sb.append(value); } } DBLog log = new DBLog(); log.setRemote_user(uid); log.setOperate_date(currentDate); log.setOperation(operation); log.setOper_desc(desc); log.setOper_params(sb.toString()); System.out.println("************************in AvicDBLogInteceptor\n "+log ); //取得spring中管理的bean,取得service执行save保存数据 ServletContext sc=request.getSession().getServletContext(); ApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(sc); dbLogService = (IDBLogService) ac.getBean("com.system.common.dbLogService"); //写数据库日志 dbLogService.save(log); System.out.println("******************************************写日志完成"); } } return actionInvocation.invoke(); } //根据传入的参数名称, private List<String> splitParams(String params){ System.out.println("input:"+params); List<String> lst = null; if(params==null||params.trim().equals("")){ return null; } lst = new ArrayList<String>(); StringTokenizer st = new StringTokenizer(params,";"); while(st.hasMoreTokens()){ String paramName = st.nextToken().trim(); lst.add(paramName); } return lst; } //根据成员变量名,改第一个字母大写后,再增加get前缀,转为getXxxx方法名。 private String convertMethodName(String fieldName){ String fisrLetter = fieldName.substring(0, 1).toUpperCase(); String methodName = "get"+fisrLetter+fieldName.substring(1); System.out.println(methodName); return methodName; } //格式化参数名和参数值输出格式 private String formatFidlParam(String fieldName,String fiedldValue){ String rtnValue = null; rtnValue = "["+fieldName+" = {"+fiedldValue+"}]"; return rtnValue; } }
3:配置拦截器:
<package name="common" extends="struts-default"> <interceptors> <interceptor name="dbLogInteceptor" class="com.framework.web.struts2.interceptor.DBLogInteceptor"/> <interceptor-stack name="commonsStack"> <interceptor-ref name="exception"/> <interceptor-ref name="prepare"/> <interceptor-ref name="params"/> <interceptor-ref name="validation"/> <interceptor-ref name="workflow"/> </interceptor-stack> <interceptor-stack name="uploadStack"> <interceptor-ref name="fileUpload"> <param name="allowedTypes">image/bmp,image/png,image/gif,image/jpeg,image/jpg</param> <param name="maximumSize">50485760</param> </interceptor-ref> <interceptor-ref name="commonsStack"/> </interceptor-stack> <interceptor-stack name="annotation"> <interceptor-ref name="uploadStack"/> <interceptor-ref name="dbLogInteceptor"/> </interceptor-stack> </interceptors> <!-- *******************默认拦截器************** --> <default-interceptor-ref name="annotation"/> </package>
4:最后一步,在配置action时,这个action所在的xml文件的package应该继承上面的包,这些action才能被拦截。
structs2的配置文件的包继承是多继承的,extends可以多个,如下,继承了json-default和common。
common中定义的拦截器,该配置中的userList这个action中就可以通过注解使用拦截器了。
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="avic-system-json" extends="json-default,common"> <!-- ************************************************配置自定义ACTION类************************************************* --> <action name="userList" class="com.system.example.page.UserListAction" method="getPageList"> <result name="success" type="json"></result> </action> </package> </struts>