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