传统日志
有关反射的一些基本知识就不说了,可以自行Google,也可以看下上一篇文章反射基础。
日志相信大家都不陌生,在实际开发中一些比较敏感的数据表我们需要对它的每一次操作都记录下来。
先来看看传统的写法:
@Test
public void insertSelective() throws Exception {
Content content = new Content() ;
content.setContent("asdsf");
content.setCreateDate("2016-12-09");
contentService.insertSelective(content) ;
ContentLog log = new ContentLog();
log.setContentId(content.getContentId());
log.setContent("asdsf");
log.setCreateDate("2016-12-09");
contentLogService.insertSelective(log);
}
非常简单,就是在保存完数据表之后再把相同的数据保存到日志表中。
但是这样有以下几个问题:
-
如果数据表的字段较多的话,比如几百个。那么日志表的setter()方法就得写几百次,还得是都写对的情况下。
-
如果哪天数据表的字段发生了增加,那么每个写日志的地方都得增加该字段,提高了维护的成本。
针对以上的情况就得需要反射这个主角来解决了。
利用反射构建日志
public void insertSelective() throws Exception{
Content content = new Content;
content.setContent("asdsf");
content.setCreateDate(new Date());
contentService.insertSelective(content) ;
ContentLog log = new ContentLog();
CommonUtil.setLogValueModelToModel(content,log);
contentLogService.insertSelective(log);
}
同样的保存日志,不管多少字段,只需要三行代码即可解决。
而且就算之后字段发生改变写日志这段代码仍然不需要改动。
其实这里最主要的一个方法就是CommonUtil.setLogValueModelToModel(content, log);
来看下是如何实现的:
package org.java;
import java.lang.reflect.Method;
/**
* @author yangkun
* @date 2021-04-07
*/
public class CommonUtil {
public static void setLogValueModelToModel(Object objectFrom, Object objectTo) {
Class<? extends Object> clazzFrom = objectFrom.getClass();
Class<? extends Object> clazzTo = objectTo.getClass();
Method[] methods = clazzTo.getMethods();
for(Method toSetMethod : methods){
String name = toSetMethod.getName();
if(name.startsWith("set")){
//字段名
String field = name.substring(3);
//获取from的值
Object fieldValue = null;
try{
if ("LogId".equals(field)) {
continue;
}
Method fromGetMethod = clazzFrom.getMethod("get" + field);
fieldValue = fromGetMethod.invoke(objectFrom);
//设置值
toSetMethod.invoke(objectTo,fieldValue);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
}
再使用之前我们首先需要构建好主的数据表,然后new一个日志表的对象。
在setLogValueModelToModel()方法中:
-
分别获得数据表和日志表对象的类类型。
-
获取到日志对象的所有方法集合。
-
遍历该集合,并拿到该方法的名称。
-
只取其中set开头的方法,也就是set方法。因为我们需要在循环中为日志对象的每一个字段赋值。
-
之后截取方法名称获得具体的字段名称。
-
用之前截取的字段名称,通过getMethod()方法返回数据表中的该字段的getter方法。
-
相当于执行了String content = content.getContent();
-
执行该方法获得该字段具体的值。
-
利用当前循环的setter方法为日志对象的每一个字段赋值。
-
相当于执行了log.setContent(“asdsf”);
-
其中字段名称为LogId时跳出了当前循环,因为LogId是日志表的主键,是不需要赋值的。
当循环结束时,日志对象也就构建完成了。之后只需要保存到数据库中即可。