- 浏览: 257099 次
- 性别:
- 来自: 苏州
文章分类
最新评论
-
a542550187:
很受用,最近正好学习软件工程方面的知识
如何建立领域模型(转) -
liiyee:
谢谢!中文版有些地方的翻译实在是挺对付的。
hibernate in action 2 英文版 -
HFLdragon:
下来学习一下
ajax upload file -
wendellup_account1:
thanks....
Spring 3 mvc Validation的错误 -
zhangjq5:
中文名乱码……
ajax upload file
History Interceptor
原文: https://www.hibernate.org/195.html
I've made some enhancements to the AuditInterceptor so that not only the creation- and modification times were recorded.
The following Interceptor can be used to record all modifcations on an Object in a seperate table. The main pitfall is the problem, that you cannot modify the set of history entries of an object within onFlushDirty since you will get an TransientObjectException. The workaround is to record the old history entries in preFlush() in a new set and using this one in onFlushDirty.
package de.micromata.hibernate; import java.io.Serializable; import java.sql.Timestamp; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import net.sf.hibernate.CallbackException; import net.sf.hibernate.Interceptor; import net.sf.hibernate.type.Type; import org.apache.log4j.Priority; /** * Implementation of an Interceptor recording all changes on an Object in a * seperate table. * * @author Wolfgang Jung (w.jung@micromata.de) * */ public class HistoryInterceptor implements Interceptor { /** New history entries, found in onFlushDirty */ private final Map histories = new HashMap(); /** Our Logger */ private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(HistoryInterceptor.class); /** The user who changes the objects */ private final String userName; /** * Object formatter, should use something like * org.apache.log4j.spi.RendererSupport */ private String format(Object obj) { if (obj == null) { return null; } return obj.toString(); } /** Create a new Interceptor, recording the changes under the given userName */ public HistoryInterceptor(final String userName) { this.userName = userName; } /** the username */ private String getUser() { return userName; } /** * @see Interceptor#onLoad(java.lang.Object, java.io.Serializable, * java.lang.Object[], java.lang.String[], net.sf.hibernate.type.Type[]) */ public boolean onLoad(Object obj, Serializable id, Object[] values, String[] properties, Type[] types) throws CallbackException { return false; } /** * Record the changes in the HashMap. Unfortunately, these changes can't be * done immediately (TransientObjectException), so they are recorded in a * seperate Set. * * @see Interceptor#onFlushDirty(java.lang.Object, java.io.Serializable, * java.lang.Object[], java.lang.Object[], java.lang.String[], * net.sf.hibernate.type.Type[]) */ public boolean onFlushDirty(Object obj, Serializable id, Object[] newValues, Object[] oldValues, String[] properties, Type[] types) throws CallbackException { if (log.isEnabledFor(Priority.INFO)) { log.info("Updating " + obj + " with id " + id + " new=" + Arrays.asList(newValues) + " old=" + Arrays.asList(oldValues) + " props=" + Arrays.asList(properties)); } if (!(obj instanceof Historizable)) { return false; } Historizable h = (Historizable) obj; // Won't work: // net.sf.hibernate.TransientObjectException: object references an unsaved // transient instance - save the transient instance before flushing: // de.micromata.hibernate.HistoryEntry // Set entries = h.getHistoryEntries(); // // get the copy from the map Set entries = (Set) histories.get(obj); for (int i = 0; i < properties.length; i++) { // Skip the historyEntries if (properties[i].equals("historyEntries") == true) { continue; } Object oldOne = oldValues[i]; Object newOne = newValues[i]; // Check for changes if (oldOne == null && newOne == null) { continue; } if (newOne instanceof PersistentCollection) { // Collections must be compared against the snapshot PersistentCollection collection = (PersistentCollection) newValues[i]; if (collection.isDirectlyAccessible() == false) { continue; } // retrieve Snapshot oldOne = collection.getCollectionSnapshot().getSnapshot(); if (oldOne instanceof Map && newOne instanceof Set) { // a Set is internally stored as Map oldOne = ((Map) oldOne).values(); } } if (oldOne != null && oldOne.equals(newOne) == true) { continue; } // Generate a new entry HistoryEntry entry = new HistoryEntry(); entry.setWho(getUser()); entry.setTimestamp(new Timestamp(new Date().getTime())); entry.setWhat("update"); entry.setProperty(properties[i]); entry.setOldValue(format(oldOne)); entry.setNewValue(format(newOne)); if (log.isDebugEnabled()) { log.debug("Changed " + properties[i] + " from " + oldOne + " to " + newOne); } // and store it. entries.add(entry); } // h.setHistoryEntries(entries); return false; } /** * Record the creation of the object. * * @see net.sf.hibernate.Interceptor#onSave(java.lang.Object, * java.io.Serializable, java.lang.Object[], java.lang.String[], * net.sf.hibernate.type.Type[]) * */ public boolean onSave(Object obj, Serializable id, Object[] newValues, String[] properties, Type[] types) throws CallbackException { if (!(obj instanceof Historizable)) { return false; } Historizable h = (Historizable) obj; if (log.isDebugEnabled()) { log.debug("Inserting " + obj + " with id " + id + " new=" + Arrays.asList(newValues) + " props=" + Arrays.asList(properties)); } // Ensure that the set is not null Set entries = h.getHistoryEntries(); if (entries == null) { entries = new HashSet(); h.setHistoryEntries(entries); } HistoryEntry entry = new HistoryEntry(); entry.setWho(getUser()); entry.setTimestamp(new Timestamp(new Date().getTime())); entry.setWhat("created"); entries.add(entry); return false; } public void onDelete(Object obj, Serializable id, Object[] newValues, String[] properties, Type[] types) throws CallbackException { } public void preFlush(Iterator it) throws CallbackException { log.debug("Pre-Flush"); while (it.hasNext()) { Object obj = it.next(); if (!(obj instanceof Historizable)) { continue; } Historizable h = (Historizable) obj; Set s = new HashSet(); // Record all existing entries Set old = h.getHistoryEntries(); if (old == null) { old = new HashSet(); h.setHistoryEntries(old); } // s.addAll(h.getHistoryEntries()); Set newEntries = (Set) histories.put(h, s); } } public void postFlush(Iterator it) throws CallbackException { log.debug("Post-Flush"); while (it.hasNext()) { Object obj = it.next(); if (!(obj instanceof Historizable)) { continue; } Historizable h = (Historizable) obj; Set newEntries = (Set) histories.get(h); if (newEntries == null) { continue; } h.getHistoryEntries().addAll(newEntries); } histories.clear(); } public Boolean isUnsaved(Object arg0) { return null; } public int[] findDirty(Object obj, Serializable id, Object[] newValues, Object[] oldValues, String[] properties, Type[] types) { return null; } public Object instantiate(Class arg0, Serializable arg1) throws CallbackException { return null; } }
The interface <pre>Historizable</pre> is used for accessing the history entries:
package de.micromata.hibernate; import java.util.Set; public interface Historizable { public Set getHistoryEntries(); public void setHistoryEntries(Set set); }
The implementation of HistoryEntry is straight forward:
package de.micromata.hibernate; public class HistoryEntry { private Integer id; private String who; private String what; private String property; private String oldValue; private String newValue; private Timestamp timestamp; // getter and setter methods omitted. }
Mapping for the HistoryEntry object:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="de.micromata.hibernate.HistoryEntry" table="HISTORY_ENTRIES"> <id name="id" type="int"> <column name="HISTORY_ID" /> <generator class="native"/> </id> <property name="who"/> <property name="what"/> <property name="property"/> <property name="timestamp"/> <property name="oldValue"/> <property name="newValue"/> </class> </hibernate-mapping>
Sample usage
Sample object for the test:
package de.micromata.hibernate; import java.util.Set; public class Order implements Historizable { private Set historyEntries; private Integer id; private String item; private int quantity; // getter and setter methods omitted. }
Mapping file for the Order object:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="de.micromata.hibernate.Order" table="ORDERS"> <id name="id" type="int"> <column name="ORDER_ID" /> <generator class="native"/> </id> <property name="item"/> <property name="quantity"/> <set name="historyEntries" table="T_ORDER_HISTORY" lazy="true" inverse="false" cascade="all"> <key column="ORDER_ID" /> <many-to-many class="de.micromata.hibernate.HistoryEntry" column="HISTORY_ID" outer-join="auto" /> </set> </class> </hibernate-mapping>
Testcase
A simple test-case shows the usage:
package de.micromata.hibernate; import java.util.Set; import junit.framework.TestCase; import net.sf.hibernate.Session; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Transaction; import net.sf.hibernate.cfg.Configuration; import net.sf.hibernate.tool.hbm2ddl.SchemaExport; /** * @author Wolfgang Jung (w.jung@micromata.de) */ public class HibernateTest extends TestCase { /** Our Logger */ private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(HibernateTest.class); public void testHistory() throws Exception { // create clean database Configuration cfg = new Configuration(); cfg.configure(); SchemaExport export = new SchemaExport(cfg); export.drop(true, true); export.create(true, true); SessionFactory sf = cfg.buildSessionFactory(); // Open the session with the Interceptor Session s = sf.openSession(new HistoryInterceptor("Admin")); Transaction tx = s.beginTransaction(); Order o = new Order(); o.setItem("Hurzel"); o.setQuantity(27); // o.setHistoryEntries(new HashSet()); Integer id = (Integer) s.save(o); s.flush(); assertEquals(1, o.getHistoryEntries().size()); tx.commit(); tx = s.beginTransaction(); o = (Order) s.load(Order.class, id); Set hist = o.getHistoryEntries(); // Contains the creation assertEquals(1, hist.size()); o.setQuantity(23); s.update(o); s.flush(); assertEquals(2, o.getHistoryEntries().size()); // Contains the creation and the modification tx.commit(); tx = s.beginTransaction(); o = (Order) s.load(Order.class, id); hist = o.getHistoryEntries(); log.debug("hist=" + hist); // Contains the creation and the modification assertEquals(2, hist.size()); s.delete(o); s.flush(); tx.commit(); s.close(); sf.close(); } }
发表评论
-
Hibernate的优化抓取和高速缓存(未完)
2011-06-02 15:47 826优化抓取和高速缓存 1. 对象获取方法: ... -
理解Hibernate中PO的代理类
2011-05-27 12:23 1224理解一下Hibernate中动态类与load()和get()方 ... -
Hibernate在oracle中ID增长的两种方式(转)
2010-10-20 13:49 1085根据hibernate的文档,有两种方式实现实体对象的主键自动 ... -
HQL常用查询语句(转)
2010-10-20 10:20 7261. 查询整个映射对象所有字段 //直接from查询出来 ... -
Hibernate中一级缓存和二级缓存区别(转)
2010-10-18 15:37 647缓存是介于应 ... -
Hiberante中LAZY的疑惑
2010-10-08 09:28 854用户User与Role,Resource关联都是lazy,而使 ... -
HQL中使用to_number()中的错误
2010-09-19 16:33 2062项目中要取得某个表中最大的数字(字段类型定义是字段串),使用s ... -
(转)Hibernate 缓存 及 对象的状态
2010-01-08 16:21 706对于session这个接口的学 ... -
Hibernate 与 Spring 多数据源的配置
2009-09-15 14:41 677Spring2.0.1以后的版本已经支持配置多数据源,并且可以 ... -
hibernate in action 2 英文版
2009-06-11 23:08 1870hibernate in action 2 英文版与大家分享, ... -
java.sql.BatchUpdateException: ORA-00942: 表或视图不存在
2009-06-10 16:04 3625java.sql.BatchUpdateException: ... -
Hibernate中使用CreateSQLQuery查询mysql的问题
2009-05-07 23:11 3063Hibernate中有三种SQL的查询方式: 1. HQL( ...
相关推荐
Postman Interceptor是一款谷歌浏览器的插件。 它可以实现自动抓取在谷歌浏览器请求的接口及各种参数同步发到postman客户端的history tab下,以便使用者直接使用,而省去了复制粘贴的繁琐过程。
- Interceptor:Postman的浏览器插件可以捕获浏览器发送的网络请求,方便调试。 - Mock Servers:模拟服务器响应,测试客户端应用与API的交互。 - Monitor:定期检查接口的可用性和性能,提供实时监控。 总之,...
1. 使用Postman Interceptor:这是一个Chrome扩展,可同步浏览器的Cookies到Postman,方便进行登录状态的测试。 2. Postman Collection Runner:批量执行集合中的请求,便于进行端到端测试。 3. Postman ...
- **Interceptor插件**: Postman Interceptor插件可以帮助捕获浏览器发出的请求,将其导入到Postman中进行调试。 - **Mock Server**: 可以创建Mock Server模拟API响应,方便前端开发与测试。 - **监控**: Postman...
- “Interceptor”插件可以捕获浏览器的网络请求,便于调试和测试。 - Postman还支持导入和导出请求、集合,方便在不同设备间同步。 总之,Postman作为一个功能强大的接口测试工具,不仅简化了API的调试过程,还...
此外,Postman的Interceptor插件能捕获浏览器中的网络请求,这对于复制和调试网页与服务器之间的交互非常有用。同时,Postman的History功能可以记录所有的请求历史,方便回溯和分析。 总结起来,Postman作为一款...
Struts2的核心组件包括Action类、配置文件(struts.xml)、拦截器(Interceptor)等,这些都可能在yz_music文件夹中的源代码中找到。 **Spring3** 是一个全面的Java企业级应用开发框架,提供了依赖注入(DI)和面向...
- 使用“Interceptor”插件捕获浏览器的网络请求,便于在Postman中复用。 - 利用“Pre-request Script”和“Tests”实现自定义逻辑,比如设置动态变量、数据验证等。 - 创建“Mock Server”来模拟API响应,便于...
还可以利用"Interceptor"插件与浏览器同步,方便调试网页应用的API请求。 7. **Postman API**:Postman不仅用于测试API,自身也提供了API,允许开发者通过编程方式与Postman集成,实现自动化工作流。 8. **学习...
- 使用"Interceptor"扩展可以捕获浏览器发出的请求,方便测试。 - 利用"Newman"命令行工具,可以将Postman集合进行命令行自动化测试。 总的来说,Postman是一个功能强大的API工具,无论你是独立开发者还是团队的...
- 启动Postman后,你会看到一个简洁的界面,主要包括以下几个部分:收藏夹(Favorites)、历史(History)、集合(Collections)、环境(Environments)和个人空间(Spaces)。 - 收藏夹用于保存常用的请求。 - 历史记录了...
3. **BOM(浏览器对象模型)**:window对象,location,history,navigator等。 4. **AJAX**:异步请求,XMLHttpRequest对象,Promise,fetch API。 5. **闭包**:作用域,变量持久化,私有变量。 6. **原型与原型链...
该库的灵感来自iOS版应用程序的“ Network Request History功能。 如何使用? Android Snooper适用于几乎所有HTTP客户端都支持的。 您需要做的就是使用AndroidSnooper.init(this);初始化Android Snooper ...
\contentsline {chapter}{Contents}{2}{section*.1} {1}Java基础}{17}{chapter.1} {1.1}基本语法}{17}{section.1.1} {1.2}数字表达方式}{17}{section.1.2} {1.3}补码}{19}{section.1.3} {1.3.1}总结}{23}{...