该需求目标:以最小的变更实现用户操作日志,并记录操作之前数据值。
经分析得知,该需求的主要目的就是拦截用户操作日志,由于需要记录用户、操作记录,故拦截Mybatis的操作日志。
具体代码如下:
核心类(实现mybatis Interceptor接口)
@Component
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class SqlLogInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(SqlLogInterceptor.class);
@Autowired
private SysOperationLogServiceImpl sysOperationLogService;
@Override
public Object intercept(Invocation invocation) throws Throwable {
SysOperationLog sol = new SysOperationLog();
// 获取当前用户ID
SysUser token = (SysUser) SecurityUtils.getSubject().getPrincipal();
String userId = token == null ? "--" : token.getId() + "";
logger.info("-->userID " + userId);
if (token != null) {
sol.setUserId(token.getId());
sol.setUserRealName(token.getRealName());
}
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
BoundSql boundSql = mappedStatement.getBoundSql(invocation.getArgs()[1]);
Configuration configuration = mappedStatement.getConfiguration();
// 获取sql语句
String sql = showSql(configuration, boundSql);
sql = sql.replaceAll("\'", "").replace("\"", "");
String splod = sql.toLowerCase().replace("call", "");
if(splod.indexOf("sys_operation_log") == -1){
String tableName = null;
sol.setLogTime(new Date());
sol.setSqlLog(splod);
logger.info(splod.indexOf("update") + "----");
if (splod.indexOf("update") > -1) {
sol.setLogType("UPADTE");
// 修改日志记录
tableName = splod.substring(splod.indexOf("update") + 7, splod.indexOf(" set")).trim();
sol.setTableName(tableName);
logger.info(splod + " tableName---> " + tableName);
// 拼接修改操作之前的SQL语句
String condition = splod.split("where")[1];
this.saveLog(sol,tableName,condition);
} else if (splod.indexOf("insert") > -1) {
sol.setLogType("INSERT");
// 新增日志记录
tableName = splod.substring(splod.indexOf("into") + 5, splod.indexOf("(")).trim();
sol.setTableName(tableName);
this.saveLog(sol,null,null);
} else if (splod.indexOf("delete") > -1) {
sol.setLogType("DELETE");
// 删除日志记录
tableName = splod.substring(splod.indexOf("from") + 5, splod.indexOf(" where")).trim();
sol.setTableName(tableName);
String condition = splod.split("where")[1];
this.saveLog(sol,tableName,condition);
}
}
// 执行结果
Object returnValue = null;
returnValue = invocation.proceed();
return returnValue;
}
public void saveLog(SysOperationLog sol,String tableName,String condition){
try{
if (sysOperationLogService == null) {// 解决service为null无法注入问题
System.out.println("sysOperationLogService is null!!!");
sysOperationLogService = (SysOperationLogServiceImpl) SpringContextUtil
.getBean("sysOperationLogServiceImpl");
}
if (sysOperationLogService != null) {
if(null != tableName){
Map<String,Object > map = sysOperationLogService.query(tableName,condition);
sol.setSqlValue(JSONUtils.valueToString(map));
}
int a = sysOperationLogService.save(sol);
logger.info("插入操作日志:TABLE:"+sol.getTableName()+" 响应条数:"+a);
}
}catch(RuntimeException re){
logger.error("等待日志对象注入(由于tomcat加载机制,启动时出现该错误正常): "+re);
}
catch(Exception e){
logger.error("日志插入失败:",e);
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
private String getParameterValue(Object obj) {
String value = null;
if (obj instanceof String) {
value = "'" + obj.toString() + "'";
} else if (obj instanceof Date) {
DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
value = "'" + formatter.format(obj) + "'";
} else {
if (obj != null) {
value = obj.toString();
} else {
value = "";
}
}
return value;
}
public String showSql(Configuration configuration, BoundSql boundSql) {
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
String sql = boundSql.getSql().replaceAll("[\\s]+", " ");
if (parameterMappings.size() > 0 && parameterObject != null) {
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
sql = sql.replaceFirst("\\?", getParameterValue(parameterObject));
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
Object obj = metaObject.getValue(propertyName);
sql = sql.replaceFirst("\\?", getParameterValue(obj));
} else if (boundSql.hasAdditionalParameter(propertyName)) {
Object obj = boundSql.getAdditionalParameter(propertyName);
sql = sql.replaceFirst("\\?", getParameterValue(obj));
}
}
}
}
return sql;
}
}
拦截器配置:
日志记录实体类
service层实现。
Dao层实现
注:仅个人观点,不足之处还请留言或微信相互学习交流!