[沫沫金]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>

效果

 

 

 

小结

想完成系统访问记录、数据操作记录,重现操作过程。选用框架监听,完成记录,非常好使。

 

posted @ 2018-08-31 14:27  章力  阅读(251)  评论(0编辑  收藏  举报