`
xfxlch
  • 浏览: 167089 次
  • 性别: 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事件框架之拦截器使用源代码

    为了更好地控制持久化行为,Hibernate 提供了一个强大的事件处理机制,其中就包括了拦截器(Interceptor)。拦截器允许开发者在对象状态变化时执行自定义逻辑,比如更新时间戳、记录审计日志等。 #### 定义拦截器 ...

    拦截器和控制器的区别

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

    Struts1 拦截器(SAIF)的使用

    Struts1 框架是Java Web开发中的一个经典MVC框架,它的核心组件之一就是拦截器(Interceptor)。拦截器在Struts1中扮演着重要角色,它允许开发者在动作执行前后插入自定义的逻辑,比如日志记录、权限验证、事务管理...

    Struts拦截器案例——登陆

    例如,可以创建一个名为`LoginInterceptor`的拦截器,然后在`&lt;package&gt;`标签内使用`&lt;interceptors&gt;`和`&lt;interceptor&gt;`来声明和配置它。 2. **拦截器实现**:创建一个实现`Interceptor`接口的类,重写`intercept()`...

    登录拦截器

    1. **定义拦截器**:在Struts2中,我们需要创建一个实现了`com.opensymphony.xwork2.interceptor.Interceptor`接口的类。这个类将包含拦截逻辑,例如检查session中是否存在登录信息。 2. **配置拦截器**:在`struts....

    登陆拦截器

    **拦截器(Interceptor)**是Struts2框架的核心特性之一,它允许开发者在Action执行前后插入自定义逻辑。拦截器可以用来实现日志记录、权限检查、事务处理等跨切面的功能。在登录场景中,拦截器通常用于验证用户的...

    拦截器登陆权限验证案例

    在Java Web开发中,拦截器(Interceptor)是一种重要的设计模式,尤其在框架如Spring MVC或Struts2中,用于在请求处理之前或之后执行特定逻辑。在这个“拦截器登陆权限验证案例”中,我们将深入探讨如何在Struts2...

    ssh权限管理和日志拦截器

    在SSH(Struts2、Spring、Hibernate)框架中,权限管理和日志拦截器是两个重要的概念,它们在大型企业级应用开发中起到了关键作用。SSH框架允许开发者通过拦截器(Interceptor)来增强或修改默认的请求处理流程。...

    Hibernate与struts2结合使用的demo

    Struts2的核心组件包括Action(业务逻辑处理)、Result(展示结果)、Interceptor(拦截器)和配置文件(struts.xml)。开发者可以通过定义Action类来实现业务逻辑,然后通过配置Action和Result来定义请求和响应的...

    过滤器与拦截器的区别

    在Java Web开发中,过滤器(Filter)和拦截器(Interceptor)是两种常见的处理请求和响应的机制,它们各自有着不同的特性和应用场景。下面将详细解释这两种技术的区别以及它们在SSH(Spring、Struts和Hibernate)...

    Struts2拦截器的简单登录应用.zip_jsp_lonelyi7a

    在Struts2中,拦截器(Interceptor)扮演着核心角色,它们允许开发者插入自定义的逻辑来扩展或增强Action执行的流程。在这个“Struts2拦截器的简单登录应用”中,我们将深入理解如何利用拦截器实现用户登录验证。 ...

    SSH2及模型驱动,拦截器注入

    在SSH2框架中,拦截器(Interceptor)是非常重要的组件之一,它可以用来增强Action的功能,比如权限检查、日志记录等。为了更好地利用Spring的依赖注入功能,可以通过以下步骤在拦截器中注入Spring管理的对象: 1. ...

    struts拦截器实现等待页面

    在SSH(Struts2、Spring、Hibernate)系统中,拦截器用于增强应用程序的功能,比如权限检查、日志记录、事务管理等。在本场景中,我们关注的是如何利用Struts拦截器来实现一个等待页面,以提升用户体验。 当系统...

    hibernate实现动态表查询的多种解决方案

    2. **拦截器(Interceptor)**:Hibernate提供了一个非常强大的扩展点——拦截器,它可以用来拦截实体的各种生命周期事件。通过实现`org.hibernate.event.spi.Interceptor`接口,可以自定义拦截器逻辑,比如修改SQL...

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

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

    hibernate源码分析

    **三、拦截器(Interceptor)与事件监听器(Listener)** Hibernate提供拦截器和事件监听器来扩展其行为。Interceptor是在特定操作(如保存、更新、删除等)执行前后被调用的接口,允许用户自定义行为。Listener则是...

    struts拦截器防止未登陆访问内部系统

    拦截器(Interceptor)是Struts2框架中的关键组件之一,用于在执行Action之前或之后进行一系列的预处理或后处理任务。例如,它可以用于身份验证、日志记录、数据校验等。拦截器的设计遵循AOP(面向切面编程)思想,...

    燕山大学 spring hibernate struts 三大框架 期末复习资料

    - **拦截器定义**: 拦截器可以是实现了 Interceptor 接口的类,也可以是继承了 AbstractInterceptor 或 MethodFilterInterceptor 抽象类的类。 - **自定义拦截器**: 可以通过实现 Interceptor 接口或继承 ...

    Struts2+Hibernate实现的登录功能

    在实际应用中,Struts2与Hibernate的集成通常通过拦截器(Interceptor)实现。例如,我们可以创建一个自定义的登录拦截器,该拦截器在Action执行之前检查用户的登录状态。如果用户未登录,拦截器会重定向到登录页面...

    struts+hibernate整合jar包

    Struts 2是Struts 1的升级版,它基于MVC设计模式,提供了强大的动作(Action)和结果(Result)管理,以及强大的拦截器(Interceptor)机制。Struts 2的核心组件包括: 1. **Action类**:处理用户请求的业务逻辑。 ...

Global site tag (gtag.js) - Google Analytics