`
xfxlch
  • 浏览: 162515 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Hibernate Interceptor(拦截器)

    博客分类:
  • Java
 
阅读更多
需求:
对所有操作数据库的事件,添加audit log, 此log持久化到一张单独的audit_log表,以供操作人员可以查阅跟踪。

方案:
Hibernate Interceptor 提供了一个拦截器,使用切面的方法,拦截所有对DB的操作,like:persist, merge, remove event。

实现:
首先是创建一个AuditlogInterceptor,来实现对数据库操作的拦截。 这个Interceptor要继承Hibernate的EmptyInterceptor, 然后我们同时重写onsave,ondelete,onFlushDirty, postFlush等方法来实现我们自己的需求:
public class AuditLogInterceptor extends EmptyInterceptor {
    
    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = -4829761117655964386L;
    
    private static final  Logger logger =
        LoggerFactory.getLogger(AuditLogInterceptor.class);
    
    private static final String EMPTY_STRING = "";
    private static final String DELETE = "postFlush - delete";
    private static final String INSERT = "postFlush - insert";
    private static final String UPDATE = "postFlush - update";
    private static EntityManager entityManager = null;
    static {
        entityManager = Persistence.createEntityManagerFactory("auditLog").createEntityManager();
    }
    //FIXME thread local
    private Set<IAuditable> inserts = new HashSet<IAuditable>();
    
    private Set<IAuditable> updates = new HashSet<IAuditable>();
    
    private Set<IAuditable> deletes = new HashSet<IAuditable>();
    
    @Override
    public synchronized boolean onSave(Object entity, Serializable id, Object[] state,
        String[] propertyNames, Type[] types)
        throws CallbackException {
        
        logger.info("onSave");
        
        if (entity instanceof IAuditable) {
            inserts.add((IAuditable)entity);
        }
        return false;
    }
    
    @Override
    public synchronized boolean onFlushDirty(Object entity, Serializable id,
        Object[] currentState, Object[] previousState, String[] propertyNames,
        Type[] types)
        throws CallbackException {
        
        logger.info("onFlushDirty");
        
        if (entity instanceof IAuditable) {
            updates.add((IAuditable)entity);
        }
        return false;
    }
    
    @Override
    public synchronized void onDelete(Object entity, Serializable id, Object[] state,
        String[] propertyNames, Type[] types) {
        logger.info("onDelete");
        if (entity instanceof IAuditable) {
            deletes.add((IAuditable)entity);
        }
    }
    
    /**
     * called before commit into database
     */
    @SuppressWarnings("rawtypes")
    @Override
    public void preFlush(Iterator iterator) {
        logger.info("preFlush");
    }
    
    /**
     * called after committed into database
     */
    @SuppressWarnings("rawtypes")
    @Override
    public synchronized void postFlush(Iterator iterator) {
        
        logger.info("postFlush");
        String username =
            SecurityContextHolder.getContext().getAuthentication().getName();
        
        Collection collection =
            SecurityContextHolder.getContext()
                .getAuthentication()
                .getAuthorities();
        String role = collection.toString();
        
        if (inserts.isEmpty() && updates.isEmpty() && deletes.isEmpty()) {
            return;
        }
        
        try {
            if (!entityManager.getTransaction().isActive()) {
                entityManager.getTransaction().begin();
            }
            
            for (IAuditable entity : inserts) {
                persistenceEntity(entity,
                    entityManager,
                    username,
                    role,
                    INSERT,
                    null);
            }
            
            for (IAuditable entity : updates) {
                IAuditable preStateEntity = null;
                preStateEntity = entityManager.find(entity.getClass(), entity.getId());
                
                List<String> valueList = getNewOldValues(entity, preStateEntity);
                String oldValues = valueList.get(0);
                String changeValues = valueList.get(1);
                
                if (!oldValues.equals(changeValues)) {
                    persistenceEntity(entity,
                        entityManager,
                        username,
                        role,
                        UPDATE,
                        valueList);
                }
            }
            for (IAuditable entity : deletes) {
                persistenceEntity(entity,
                    entityManager,
                    username,
                    role,
                    DELETE,
                    null);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            updates.clear();
            inserts.clear();
            deletes.clear();
            if (entityManager.isOpen()
                && entityManager.getTransaction().isActive()) {
                logger.info("finally cause");
                entityManager.getTransaction().commit();
            }
        }
    }
    
    private void persistenceEntity(IAuditable entity, EntityManager em,
        String username, String role, String comments, List<String> changeValueslist) {
        logger.info(comments);
        AuditLogEntity logEntity = new AuditLogEntity();
        logEntity.setComments(comments);
        logEntity.setOperator(StringUtils.isEmpty(username) ? "default" : username);
        
        logEntity.setRole(StringUtils.isEmpty(role) ? "default" : role);
        logEntity.setCreatedOn(new Date()); //sql date?  
        logEntity.setUpdatedOn(new Date());
        if (changeValueslist == null && DELETE.equals(comments)) {
            logEntity.setNewvalue(EMPTY_STRING);
            logEntity.setOldvalue(entity.getLogDeatil());
        } else if (changeValueslist == null && INSERT.equals(comments)) {
            logEntity.setNewvalue(entity.getLogDeatil());
            logEntity.setOldvalue(EMPTY_STRING);
        } else if (UPDATE.equals(comments)) {
            String newvalue = changeValueslist.get(1);
            String oldvalue = changeValueslist.get(0);
            logEntity.setNewvalue(newvalue);
            logEntity.setOldvalue(oldvalue);
        }
        
        logEntity.setEntity(entity.getClass().getName());
        em.persist(logEntity);
    }
    
}


其次把这个拦截器配置到我们的事务里去。
配置文件:比如数据源配置文件:datasource-context.xml:
添加:
<bean id="entityManagerFactory"
		class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="auditLog" />
		<property name="dataSource" ref="dataSource" />
		<property name="packagesToScan" value="com.statestreet.fcm.cfd" />
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
		</property>
		<!-- new added 
		<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
        -->
		<property name="jpaProperties">
			<props>
 				<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
 				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.cache.use_second_level_cache">false</prop>
				<prop key="hibernate.cache.use_query_cache">false</prop>
				<prop key="hibernate.use_sql_comments">false</prop>
				<prop key="hibernate.format_sql">true</prop>
				<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
				<!-- by clu -->
				<prop key="hibernate.ejb.interceptor">com.statestreet.fcm.cfd.interceptor.AuditLogInterceptor</prop>
				
			</props>
		</property>
	</bean>


由于这里是我自己去创建了一个PersistenceUnit,所以Hibernate会要求有一个persistence.xml文件,在META-INFO 文件夹下面,我们只要创建这个文件,并不需要指定,Hibernate会自动到该目录下去查找这个文件,文件名不能写错:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"   
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> 
    <persistence-unit name="auditLog" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <properties>
            
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.connection.driver_class" value="oracle.jdbc.OracleDriver"/>
            <property name="hibernate.connection.url" value="jdbc:oracle:thin:@"/>
            <property name="hibernate.connection.password" value="123"/>
            <property name="hibernate.connection.username" value="123"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
            <property name="hibernate.c3p0.min_size" value="5"/>
            <property name="hibernate.c3p0.max_size" value="20"/>
            <property name="hibernate.c3p0.timeout" value="300"/>
            <property name="hibernate.c3p0.max_statements" value="50"/>
            <property name="hibernate.c3p0.idle_test_period" value="3000"/>
           
        </properties>
    </persistence-unit>
</persistence>


最后就是要去创建Entity来保持audit log, 比如AuditEntity.java
@Entity
@Table(name = "AUDIT_LOG_DETAIL")
public class AuditLogEntity implements Serializable {

	/**
	 * serialVersionUID
	 */
	private static final long serialVersionUID = -1275702854046959229L;

	@Id
	@GeneratedValue
	private Long id;
	
	@Column(nullable = false )
	private String operator;
	
	@Column(nullable = false )
	private String role;
	
	@Column
	private String entity;
	
	@Column
	private String oldvalue;
	
	@Column
	private String newvalue;
	
	@Column
	private String comments;
	
	@Column(nullable = false)
	private Date createdOn;
	
	@Column(nullable = false)
	private Date updatedOn; 
}


--EOF--

分享到:
评论

相关推荐

    Hibernate事件框架之拦截器使用源代码

    使用拦截器时按如下步骤进行: (1)定义实现Interceptor接口的拦截器类 (2)通过Session启用拦截器,或者通过Configuration启用全局拦截器请看示例代码

    拦截器和控制器的区别

    拦截器 interceptor 过滤器 filter web.xml implements filter filterchain arg2.doFilter(req,resp); 监听器 servlet application /session /request 6/8 个 1、拦截器 定义拦截器的包 定义拦截器的...

    jpaprojections:示例项目演示了如何使用Hibernate Interceptor and Envers,DTO Projection,Observer和Command设计模式

    使用Hibernate拦截器检测Persistence Context中的实体更改 使用Hibernate拦截器对数据库中的实体更改做出React 使用观察者设计模式来监视实体持久性更改并对其做出React 使用命令设计模式提供一种通用方法,可将...

    拦截器登陆权限验证案例

    支持Struts2 不支持Hibernate

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     9.2 利用拦截器(Interceptor)生成审计日志  9.3 Hibernate的事件处理机制  9.4 批量处理数据  9.4.1 通过Session来进行批量操作  9.4.2 通过StatelessSession来进行批量操作  9.4.3 通过HQL来进行批量操作 ...

    Spring + Hibernate + Struts 事务配置小例子(带提示框等小技巧)

    -- 下面定义BeanNameAutoProxyCreator所需的事务拦截器--&gt; &lt;value&gt;transactionInterceptor &lt;!-- 此处可增加其他新的Interceptor --&gt; &lt;!--定义DAO Bean ,由于BeanNameAutoProxyCreator自动...

    spring2.5 struts2.0 hibernate3.2.5 搭建的企业级开发基础模块

    还有登录拦截器:com.light.framework.interceptor 字符集过滤器:com.light.framework.filter 项目字符集请用UTF-8 com.light.framework包中还有些小东西 自己看看吧 我是用MyEclipse6.0开发的(MyEclipse...

    Struts2 in action中文版

    4.4.1 声明独立的拦截器和拦截器栈 74 4.4.2 将拦截器映射到动作组件 76 4.4.3 设置、覆盖拦截器参数 77 4.5 构建自定义拦截器 78 4.5.1 实现Interceptor接口 78 4.5.2 构建AuthenticationInterceptor拦截器 79 4.6 ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part4

     9.2 利用拦截器(Interceptor)生成审计日志  9.3 Hibernate的事件处理机制  9.4 批量处理数据  9.4.1 通过Session来进行批量操作  9.4.2 通过StatelessSession来进行批量操作  9.4.3 通过HQL来进行批量操作 ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part3

     9.2 利用拦截器(Interceptor)生成审计日志  9.3 Hibernate的事件处理机制  9.4 批量处理数据  9.4.1 通过Session来进行批量操作  9.4.2 通过StatelessSession来进行批量操作  9.4.3 通过HQL来进行批量操作 ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part1.rar

     9.2 利用拦截器(Interceptor)生成审计日志  9.3 Hibernate的事件处理机制  9.4 批量处理数据  9.4.1 通过Session来进行批量操作  9.4.2 通过StatelessSession来进行批量操作  9.4.3 通过HQL来进行批量操作 ...

    深入浅出Struts2(附源码)

    18.3 使用DataSourceInjectorInterceptor拦截器 269 18.4 小结 273 第19章定制结果类型 274 19.1 概述 274 19.2 编写一个自定义的结果类型 274 19.3 使用新的结果类型 277 19.4 小结 279 第20章 Velocity 280...

    java后台框架源码

    filter:Log4jFormatFilter(格式化log4j日志输出的),SessionCheckFilter(登陆拦截器) interceptor:权限拦截包 listener:目前只有session的监听器,用于监听session的 service:具体的业务处理包 util:项目工具包 ...

    Myeclipse6.0中SSH框架搭建

    -- 定义拦截器 --&gt; class="org.springframework.transaction.interceptor.TransactionInterceptor"&gt; &lt;property name="transactionManager" ref="transactionManager"&gt;&lt;/property&gt; ...

    spring4学习完整demo

    开发工具IntelliJ IDEA15,maven构建工程,使用spring4.1.1,demo集成jackson传输json,hibernate-validator校验数据,mybatis数据库持久框架,拦截器interceptor,aop构建事务等,让你快速入门spring

    J2EE应用开发详解

    118 8.3.5 Struts2配置文件 119 8.4 Action的配置方式 121 8.4.1 动态方法调用 121 8.4.2 设置action元素的method属性 122 8.4.3 使用通配符配置action 122 8.4.4 默认action 123 8.5 拦截器Interceptor 123 8.5.1 ...

    深入浅出Struts 2 .pdf(原书扫描版) part 1

    18.3 使用DataSourceInjectorInterceptor拦截器 269 18.4 小结 273 第19章 定制结果类型 274 19.1 概述 274 19.2 编写一个自定义的结果类型 274 19.3 使用新的结果类型 277 19.4 小结 279 第20章 Velocity 280 ...

Global site tag (gtag.js) - Google Analytics