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

实体属性变更历史记录框架(一)-变更历史记录从此无忧(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:around
				pointcut="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;
	}

	@Override
	public 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;
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值