实体属性变更历史记录框架(三)-变更历史记录从此无忧
实体属性变更历史记录框架(一)-变更历史记录从此无忧(http://blog.csdn.net/lk_blog/article/details/8007777)
实体属性变更历史记录框架(二)-变更历史记录从此无忧(http://blog.csdn.net/lk_blog/article/details/8092925)
本文是对上两篇的补充,使用Spring的AOP自动将变更历史进行记录.
<!-- historylog config start --><bean id="historyDao" class="com.tgb.lk.util.log.historylog.dao.impl.HistoryDaoImpl"parent="baseHibernateDao" /><bean id="historyService"class="com.tgb.lk.util.log.historylog.service.impl.HistoryServiceImpl"parent="baseHibernateService"><property name="historyDao" ref="historyDao" /></bean><bean id="historyAction" class="com.tgb.lk.util.log.historylog.web.action.HistoryAction"><property name="historyService" ref="historyService" /></bean><bean id="historyAspect" class="com.tgb.lk.util.log.historylog.aop.HistoryAspect"parent="baseHibernateService"><property name="historyDao" ref="historyDao" /></bean><aop:config><aop:aspect id="historyLogAspect" ref="historyAspect"order="2"><!--<aop:after pointcut="execution(*com.tgb.lk.service.impl.*.*(..))" method="release" /><aop:before pointcut="execution(*com.tgb.lk.service.impl.*.*(..))" method="authority" /><aop:after-returning pointcut="execution(*com.tgb.lk.service.impl.*.*(..))" method="log" />--><!-- 定义个Around增强处理,直接指定切入点表达式,以切面 Bean 中的 processTx() 方法作为增强处理方法 --><aop:aroundpointcut="execution(* com.tgb.lk.util.base.dao.BaseHibernateDaoSupport.*update(..))"method="log" /></aop:aspect></aop:config><!-- historylog config end -->
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;import javax.persistence.Id;import org.apache.struts2.ServletActionContext;
import org.aspectj.lang.ProceedingJoinPoint;import com.tgb.lk.util.ClassUtil;
import com.tgb.lk.util.log.historylog.annotate.HistoryAlias;
import com.tgb.lk.util.log.historylog.annotate.HistoryNotRecord;
import com.tgb.lk.util.log.historylog.dao.HistoryDao;
import com.tgb.lk.util.log.historylog.model.*;
import com.tgb.lk.util.log.historylog.service.HistoryService;
import com.tgb.lk.util.auth.model.User;
import com.tgb.lk.util.base.dao.BaseHibernateDao;
import com.tgb.lk.util.base.model.BaseModel;
import com.tgb.lk.util.base.service.BaseHibernateServiceImpl;
import com.tgb.lk.util.constants.AppConstants;public class HistoryAspect extends BaseHibernateServiceImpl<History>implements HistoryService {private HistoryDao historyDao;public void setHistoryDao(HistoryDao historyDao) {this.historyDao = historyDao;}@Overridepublic BaseHibernateDao<History> getBaseDao() {return this.historyDao;}public Object log(ProceedingJoinPoint jp) throws java.lang.Throwable {// System.out.println("执行目标方法之前,模拟开始事物...");Object[] args = jp.getArgs();List<History> histories = new ArrayList<History>();if (args != null) {Object newObj = args[0];// System.out.println(newObj);Class<?> clazz = newObj.getClass();Object oldObj = null;String id = "";if (newObj instanceof BaseModel) {id = ((BaseModel) newObj).getId();oldObj = historyDao.find(clazz, id);}User user_info = (User) ServletActionContext.getRequest().getSession().getAttribute(AppConstants.USER_INFO);histories = getHistories(clazz, oldObj, newObj, user_info.getUsername());//System.out.println(histories);oldObj = null;// 清空对象.}historyDao.getSession().clear();// 防止报错a different object with the same// identifier value was already// associated with the...Object rvt = jp.proceed(); // 执行目标方法,并保存目标方法执行后的返回值// System.out.println("执行目标方法之后,模拟结束事物...");if (histories != null && histories.size() > 0) {historyDao.save(histories);}return rvt;}/*** 比较两个对象哪些属性发生变化,将变化的属性保存为History对象.* * @param clazz* 修改类* @param oldObj* 老对象* @param newObj* 新对象* @param entityId* 实体Id* @param user* 修改人*/private List<History> getHistories(Class<?> clazz, Object oldObj,Object newObj, String entityId, String user) {if (oldObj == newObj) {return null;// 如果两个对象相同直接退出}List<History> list = new ArrayList<History>();Field[] fields = clazz.getDeclaredFields();// 得到指定类的所有属性Field.for (Field field : fields) {field.setAccessible(true);// 设置类的私有字段属性可访问.try {if ((field.get(oldObj) == null ^ field.get(newObj) == null)|| (!field.get(oldObj).equals(field.get(newObj)))) {History history = new History();history.setEntity(clazz.toString());history.setProperty(field.getName());history.setOldValue(String.valueOf(field.get(oldObj)));history.setNewValue(String.valueOf(field.get(newObj)));history.setModifyDate(new Date());history.setEntityId(entityId);// 记录修改的对象的主键Id.history.setUserId(user);// 记录修改者list.add(history);}} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}return list;}/*** 比较两个对象哪些属性发生变化,将变化的属性保存为History对象. 实体中用@HistoryId注解的自动保存到实体类的Id字段中.* 实体中有@HistoryAlias的注解自动解析为指定的别名.* * @param clazz* 修改类* @param oldObj* 老对象* @param newObj* 新对象* @param user* 修改人*/private List<History> getHistories(Class<?> clazz, Object oldObj,Object newObj, String user) {if (oldObj == newObj) {return null;// 如果两个对象相同直接退出}List<History> list = new ArrayList<History>();// Field[] fields = clazz.getDeclaredFields();// 得到指定类的所有属性Field.List<Field> tmpFields = new ArrayList<Field>();tmpFields = ClassUtil.getMappedField(clazz, tmpFields);List<Field> fields = new ArrayList<Field>();Field idField = null;// 找出Id字段,便于记录for (Field field : tmpFields) {field.setAccessible(true);// 设置类的私有字段属性可访问.if (field.isAnnotationPresent(Id.class)) {idField = field;}// 设置了不记录变化的注解字段不记录变更历史.if (!field.isAnnotationPresent(HistoryNotRecord.class)&& !Modifier.toString(field.getModifiers()).contains("final")) {fields.add(field);}}// 比较实体对象的属性值,每个属性值不同的都新建一个History对象并保存入库.for (Field field : fields) {field.setAccessible(true);// 设置类的私有字段属性可访问.field.getAnnotation(HistoryAlias.class);try {// ^是异或运算符if ((field.get(oldObj) == null ^ field.get(newObj) == null)|| (!field.get(oldObj).equals(field.get(newObj)))) {History history = new History();history.setEntity(clazz.toString());history.setProperty(field.getName());if (field.isAnnotationPresent(HistoryAlias.class)) {history.setAlias(field.getAnnotation(HistoryAlias.class).alias());}history.setOldValue(String.valueOf(field.get(oldObj)));history.setNewValue(String.valueOf(field.get(newObj)));history.setModifyDate(new Date());if (idField != null) {history.setEntityId(String.valueOf(idField.get(oldObj)));// 记录修改的对象的主键Id.}history.setUserId(user);// 记录修改者list.add(history);}} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}return list;}}
实体属性变更历史记录框架(三)-变更历史记录从此无忧相关推荐
- 实体属性变更历史记录框架(一)-变更历史记录从此无忧
在实际mis项目中增删改查必不可少,针对"改"的操作,重要的项目中都要有变更历史记录.本实例提供了一个实体属性变更历史记录工具类,只要写很少的代码就能实现强大的变更历史记录功能.本 ...
- vue框架:变更页面background背景颜色 - 代码篇
vue框架:变更body,html页面background背景颜色 场景bug介绍: vue页面切换,导致后面的页面背景颜色被上一个页面背景色覆盖,如何避免这个问题. Method 1. 修改 sty ...
- Hibernate实体对象的生命周期(三种状态详解)
Hibernate生命周期会经历三种不同的状态: 1.Transient(瞬态):实体对象在内存是自由存在的,即与数据库中的数据没有任何关系.换句话说就是:该实体从未与任何持久化上下文关联过,它没有持 ...
- wifi名称可以有空格吗_收购公司后可以变更公司名称吗,变更公司名称和股权如何处理?...
[点击文末小程序,免费咨询法律问题] 公司收购是指二手设备收购,指向目标公司的二手设备,废旧物资,进而获取目标公司的全部或部分业务,取得对拆除的控制权.那么,收购公司后可以变更公司名称吗,变更公司名称 ...
- 手机360浏览器怎么清空历史记录 手机360浏览器历史记录清空方法分享
任何一款浏览器产品在使用一段时间后都会出现历史记录,手机360浏览器自然也不能例外.而这些历史记录如果长期不清理的话,则导致手机越来越卡!那么,手机360浏览器怎么清空历史记录?不清楚具体操作的朋友, ...
- VMWarevSphere Client 克隆虚拟机、变更IP地址、变更主机名、修改MAC地址
VMWarevSphere Client 克隆虚拟机.变更IP地址.变更主机名.修改MAC地址 vSphere 是VMware公司推出一套服务器虚拟化解决方案 一.VMWarevSphere Clie ...
- 如何做好需求变更管理?——需求变更流程规范
一.引言 由于目前公司内部对产品的需求变动都只是口头或邮件中进行通知,并没有进行内部评审和相关需求变动后的记录,导致后续出的产品某些需求增加了,某些没有进行增加.这样就会导致测试得到的信息不完整,以及 ...
- 基于特性(Attribute)的实体属性验证方案设计
各位朋友,我是Payne,大家好,欢迎大家关注我的博客,我的博客地址是https://qinyuanpei.github.io.在这篇文章中,我想和大家探讨下数据校验的相关问题,为什么我会对这个问 ...
- MyBatis实体属性与表的字段不对应的解决方案
MyBatis实体属性与表的字段不对应的解决方案 参考文章: (1)MyBatis实体属性与表的字段不对应的解决方案 (2)https://www.cnblogs.com/EasonJim/p/765 ...
最新文章
- Linux环境Nginx安装多版本PHP
- 分别用BFS和DFS求给定的矩阵中“块”的个数
- 微软发布预览版SQL Server跨平台开发工具
- Mashmokh and Numbers CodeForces - 415C
- 外国人看我国量子计算机祖冲之号,1.2小时完成超算8年!我国“祖冲之号”量子计算机刷新记录...
- PowerDesigner如何将物理模型转为对象模型,将对象模型转生成Java类
- OpenCV实现最大最小距离聚类算法
- 设计模式---组合模式
- 3.集--LinkedTransferQueue得知
- android 对话框 重复,如何在Android上重复使用AlertDialog for Yes / No?
- oracle sysaux表空间不足,sysaux 表空间不足问题处理
- hdu1284钱币兑换问题
- 清华山维软件EPS2012常用快捷键
- 跨考计算机要选择408吗,408难度比较大,对于跨考更是如此,应从以下三个方面做准备...
- 从零开始 了解C++
- 小知识--电脑的快捷键
- 简单教学 apache 配置 Expire/Cache-Control 头
- 解读全球十大公司物联网战略,一个万物智能的世界即将到来
- android ROM设置默认Launcher(主屏幕应用)
- Linux网络服务中,bond网络模式