[沫沫金]JavaWeb企业信息系统,增加操作记录、数据库记录
背景
系统出现数据莫名丢失,业务人员的反馈无法复现问题。纠结了很久,最终老板发话要记录操作,通过日志进行分析重现
环境
SSH框架
目标
1、记录访问了那个方法,使用的参数及返回的内容
2、记录新增、修改、删除的数据持久化记录
关键
监听器(Interceptor)
实现
1、访问记录,使用Struts的MethodFilterInterceptor监听器
import org.apache.log4j.Logger; import org.apache.struts2.ServletActionContext; import org.codehaus.jackson.map.ObjectMapper; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; /** * Action方法监听 * @author ZhangLi * @date 2018年8月28日 下午4:42:57 */ public class MethodInterceptor extends MethodFilterInterceptor { private static final long serialVersionUID = 1L; @SuppressWarnings("rawtypes") @Override protected String doIntercept(ActionInvocation AI) throws Exception { String result = null; Logger logger = null; try{ result = AI.invoke(); String methodName = AI.getProxy().getMethod(); if (methodName.length() > 0) { Object action = AI.getAction(); Class clazz = action.getClass(); logger = Logger.getLogger(clazz); ObjectMapper mapper = new ObjectMapper(); StringBuilder sbInfo = new StringBuilder(); sbInfo.append("[ Log ] 操作记录 (Start)"); sbInfo.append("\n"); sbInfo.append(String.format("访问后台:%s访问[%s]类[%s]方法",ServletActionContext.getRequest().getRemoteAddr(),clazz.getName(),methodName)); sbInfo.append("\n"); sbInfo.append(String.format("访问URL:%s",ServletActionContext.getRequest().getRequestURI())); sbInfo.append("\n"); sbInfo.append(String.format("访问参数:%s",mapper.writeValueAsString(ServletActionContext.getRequest().getParameterMap()))); sbInfo.append("\n"); sbInfo.append(String.format("返回结果:%s",result)); sbInfo.append("\n"); sbInfo.append("[ Log ] 操作记录 (End)"); logger.warn(sbInfo); } }catch(Exception e){ logger.error("Log - 访问错误", e); } return result; } }
struts.xml配置
<package name="default" extends="json-default" namespace="/"> <!-- 配置拦截器和拦截器栈 --> <interceptors> <interceptor name="methodInterceptor" class="com.ytforever.interceptor.MethodInterceptor"> </interceptor> <interceptor-stack name="methodStack"> <interceptor-ref name="methodInterceptor"></interceptor-ref> </interceptor-stack> </interceptors> <!-- 默认拦截器 --> <default-interceptor-ref name="methodStack"></default-interceptor-ref> </package>
<!-- 假如多个package,每个首行拷贝默认拦截器,不然,方法不被监听,无法记录 -->
<!-- 默认拦截器 -->
<default-interceptor-ref name="methodStack"></default-interceptor-ref>
2、数据库持久化记录,使用hibernate的EventListener事件监听
import org.apache.log4j.Logger; import org.codehaus.jackson.map.ObjectMapper; import org.hibernate.event.PostDeleteEvent; import org.hibernate.event.PostDeleteEventListener; import org.hibernate.event.PostInsertEvent; import org.hibernate.event.PostInsertEventListener; import org.hibernate.event.PostUpdateEvent; import org.hibernate.event.PostUpdateEventListener; /** * HIBERNATE删除、修改监听 * @author ZhangLi * @date 2018年8月28日 下午4:44:26 */ public class UpdateDeleteListener implements PostInsertEventListener,PostUpdateEventListener, PostDeleteEventListener { private static final long serialVersionUID = 1L; Logger logger = null; ObjectMapper mapper = new ObjectMapper(); @Override public void onPostDelete(PostDeleteEvent PD) { try { logger = Logger.getLogger(PD.getEntity().getClass()); StringBuffer sbInfo = new StringBuffer(); sbInfo.append("[ Data ] 删除数据 (Start)"); sbInfo.append("\n"); sbInfo.append(String.format("实体名:%s", PD.getEntity().getClass().getName())); sbInfo.append("\n"); sbInfo.append(String.format("主键值:%s", PD.getId())); sbInfo.append("\n"); sbInfo.append(String.format("表字段:%s", mapper.writeValueAsString(PD.getPersister().getPropertyNames()))); sbInfo.append("\n"); sbInfo.append(String.format("删数据:%s",mapper.writeValueAsString(PD.getDeletedState()))); sbInfo.append("\n"); sbInfo.append("[ Data ] 删除数据 (End)"); logger.warn(sbInfo); } catch (Exception e) { logger.error("[ Data ] 删除数据失败", e); } } @Override public void onPostUpdate(PostUpdateEvent PU) { try { logger = Logger.getLogger(PU.getEntity().getClass()); StringBuffer sbInfo = new StringBuffer(); sbInfo.append("[ Data ] 修改数据 (Start)"); sbInfo.append("\n"); sbInfo.append(String.format("实体名:%s", PU.getEntity().getClass().getName())); sbInfo.append("\n"); sbInfo.append(String.format("修改前:%s",mapper.writeValueAsString(PU.getOldState()))); sbInfo.append("\n"); sbInfo.append(String.format("修改后:%s",mapper.writeValueAsString(PU.getEntity()))); sbInfo.append("\n"); sbInfo.append("[ Data ] 修改数据 (End)"); logger.warn(sbInfo); } catch (Exception e) { logger.error("[ Data ] 数据修改失败", e); } } @Override public void onPostInsert(PostInsertEvent PI) { try { logger = Logger.getLogger(PI.getEntity().getClass()); StringBuffer sbInfo = new StringBuffer(); sbInfo.append("[ Data ] 新增数据 (Start)"); sbInfo.append("\n"); sbInfo.append(String.format("实体名:%s", PI.getEntity().getClass().getName())); sbInfo.append("\n"); sbInfo.append(String.format("表字段:%s", mapper.writeValueAsString(PI.getPersister().getPropertyNames()))); sbInfo.append("\n"); sbInfo.append(String.format("新增的数据:%s",mapper.writeValueAsString(PI.getState()))); sbInfo.append("\n"); sbInfo.append("[ Data ] 新增数据 (End)"); logger.warn(sbInfo); } catch (Exception e) { logger.error("[ Data ] 新增数据失败", e); } } }
applicationContext.xml文件配置
<bean id="auditlogEvent" class="com.ytforever.interceptor.UpdateDeleteListener"></bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <!-- 注入数据源 --> <property name="dataSource" ref="dataSource" /> <!-- 设置Spring取那个包中查找相应的实体类 --> <property name="packagesToScan"> <value>com.ytforever.bean,com.ytforever.workflow.bean</value> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> <!-- 开发环境下需要,部署环境删除 --> <prop key="hibernate.show_sql">false</prop> <prop key="hibernate.format_sql">true</prop> <prop key="javax.persistence.validation.mode">none</prop> <prop key="hibernate.jdbc.fetch_size">100</prop> <prop key="hibernate.jdbc.batch_size">50</prop> </props> </property> <property name="eventListeners"> <map> <entry> <key> <value>post-insert</value> </key> <ref bean="auditlogEvent" /> </entry> <entry> <key> <value>post-update</value> </key> <ref bean="auditlogEvent" /> </entry> <entry> <key> <value>post-delete</value> </key> <ref bean="auditlogEvent" /> </entry> </map> </property> </bean>
效果
小结
想完成系统访问记录、数据操作记录,重现操作过程。选用框架监听,完成记录,非常好使。
祝所有项目人员战斗满满、收获满满、人气满满。