实体属性变更历史记录框架(一)-变更历史记录从此无忧(http://blog.csdn.net/lk_blog/article/details/8007777)

实体属性变更历史记录框架(二)-变更历史记录从此无忧(http://blog.csdn.net/lk_blog/article/details/8092925)

本文是对上两篇的补充,使用Spring的AOP自动将变更历史进行记录.

效果图:

配置和代码如下:

1)spring中配置:

<!-- 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 -->

2)HistoryAspect.java

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;}}

实体属性变更历史记录框架(三)-变更历史记录从此无忧相关推荐

  1. 实体属性变更历史记录框架(一)-变更历史记录从此无忧

    在实际mis项目中增删改查必不可少,针对"改"的操作,重要的项目中都要有变更历史记录.本实例提供了一个实体属性变更历史记录工具类,只要写很少的代码就能实现强大的变更历史记录功能.本 ...

  2. vue框架:变更页面background背景颜色 - 代码篇

    vue框架:变更body,html页面background背景颜色 场景bug介绍: vue页面切换,导致后面的页面背景颜色被上一个页面背景色覆盖,如何避免这个问题. Method 1. 修改 sty ...

  3. Hibernate实体对象的生命周期(三种状态详解)

    Hibernate生命周期会经历三种不同的状态: 1.Transient(瞬态):实体对象在内存是自由存在的,即与数据库中的数据没有任何关系.换句话说就是:该实体从未与任何持久化上下文关联过,它没有持 ...

  4. wifi名称可以有空格吗_收购公司后可以变更公司名称吗,变更公司名称和股权如何处理?...

    [点击文末小程序,免费咨询法律问题] 公司收购是指二手设备收购,指向目标公司的二手设备,废旧物资,进而获取目标公司的全部或部分业务,取得对拆除的控制权.那么,收购公司后可以变更公司名称吗,变更公司名称 ...

  5. 手机360浏览器怎么清空历史记录 手机360浏览器历史记录清空方法分享

    任何一款浏览器产品在使用一段时间后都会出现历史记录,手机360浏览器自然也不能例外.而这些历史记录如果长期不清理的话,则导致手机越来越卡!那么,手机360浏览器怎么清空历史记录?不清楚具体操作的朋友, ...

  6. VMWarevSphere Client 克隆虚拟机、变更IP地址、变更主机名、修改MAC地址

    VMWarevSphere Client 克隆虚拟机.变更IP地址.变更主机名.修改MAC地址 vSphere 是VMware公司推出一套服务器虚拟化解决方案 一.VMWarevSphere Clie ...

  7. 如何做好需求变更管理?——需求变更流程规范

    一.引言 由于目前公司内部对产品的需求变动都只是口头或邮件中进行通知,并没有进行内部评审和相关需求变动后的记录,导致后续出的产品某些需求增加了,某些没有进行增加.这样就会导致测试得到的信息不完整,以及 ...

  8. 基于特性(Attribute)的实体属性验证方案设计

      各位朋友,我是Payne,大家好,欢迎大家关注我的博客,我的博客地址是https://qinyuanpei.github.io.在这篇文章中,我想和大家探讨下数据校验的相关问题,为什么我会对这个问 ...

  9. MyBatis实体属性与表的字段不对应的解决方案

    MyBatis实体属性与表的字段不对应的解决方案 参考文章: (1)MyBatis实体属性与表的字段不对应的解决方案 (2)https://www.cnblogs.com/EasonJim/p/765 ...

最新文章

  1. Linux环境Nginx安装多版本PHP
  2. 分别用BFS和DFS求给定的矩阵中“块”的个数
  3. 微软发布预览版SQL Server跨平台开发工具
  4. Mashmokh and Numbers CodeForces - 415C
  5. 外国人看我国量子计算机祖冲之号,1.2小时完成超算8年!我国“祖冲之号”量子计算机刷新记录...
  6. PowerDesigner如何将物理模型转为对象模型,将对象模型转生成Java类
  7. OpenCV实现最大最小距离聚类算法
  8. 设计模式---组合模式
  9. 3.集--LinkedTransferQueue得知
  10. android 对话框 重复,如何在Android上重复使用AlertDialog for Yes / No?
  11. oracle sysaux表空间不足,sysaux 表空间不足问题处理
  12. hdu1284钱币兑换问题
  13. 清华山维软件EPS2012常用快捷键
  14. 跨考计算机要选择408吗,408难度比较大,对于跨考更是如此,应从以下三个方面做准备...
  15. 从零开始 了解C++
  16. 小知识--电脑的快捷键
  17. 简单教学 apache 配置 Expire/Cache-Control 头
  18. 解读全球十大公司物联网战略,一个万物智能的世界即将到来
  19. android ROM设置默认Launcher(主屏幕应用)
  20. Linux网络服务中,bond网络模式

热门文章

  1. 读《Computer Systems: A Programmer’s Perspective》
  2. linux下图形远程桌面
  3. 一到软考网络工程师试题
  4. windows2003路由和远程访问 试图连接到数据存储时出错
  5. JAVA面试--电商业内大厂
  6. 不全屏放映ppt的方法
  7. 实验三 类和对象
  8. 前嗅ForeSpider教程:采集图片/视频/资源文件的链接地址 1
  9. 短视频直播一对一源码“皇冠”花落谁家
  10. SQL优化的思路及基本原则(mysql)