内容简介:1 业务需求:今日,公司要求对操作的业务和日志统一做处理,需要把业务表数据相关信息存入日志表中,比如表名,方法名,业务id,操作操作时间modifyTIme等等。除了在业务主动插入日志数据之外,有个比较好的方法就是用面向切面aop处理,明确跟业务逻辑分开,把业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。3 注意事项:该方式主要是通过注解的方式,个人觉得比较便利,当然也可以通过另外一种方式xml,比如
1 业务需求:今日,公司要求对操作的业务和日志统一做处理,需要把业务表数据相关信息存入日志表中,比如表名,方法名,业务id,操作操作时间modifyTIme等等。
除了在业务主动插入日志数据之外,有个比较好的方法就是用面向切面aop处理,明确跟业务逻辑分开,把业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
2 业务开发,这边处理的方式是用方式1【两种方式 1 利用注解方式 2 通过xml配置】
- 2.1 定义切入点接口类
package com.hec.dup.facade.mgr.annotation;
import java.lang.annotation.*;
/**
* 标记需要做业务日志的方法
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface OperateLogAnnotation {
/**
* 被修改的实体的唯一标识,例如:菜单实体的唯一标识为"id"
*/
String key() default "id";
/**
* 业务模块类型,例如:"01菜单管理"
*/
String moduleType() default "";
/**
* 业务模块名称,例如:"菜单管理"
*/
String moduleName() default "";
/**
* 业务模块功能名称,例如:"新增菜单功能"
*/
String functionName() default "";
/**
* 操作日志内容,例如:"修改菜单"
*/
String operateContent() default "";
/**
* 业务模块表名,例如:"SYS_MENU"
*/
String tableName() default "";
}
- 2.2 定义日志记录切面类
package com.hec.dup.facade.mgr.aspect;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hec.dup.beans.base.PrjUserEntity;
import com.hec.dup.beans.base.vo.PrjCurrUserInfo;
import com.hec.dup.beans.com.DupComOperateLogEntity;
import com.hec.dup.common.utils.UuidUtil;
import com.hec.dup.facade.base.IPrjUserService;
import com.hec.dup.facade.com.IDupComOperateLogService;
import com.hec.dup.facade.mgr.annotation.OperateLogAnnotation;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Date;
/**
* 日志记录切面
* @author
*/
@Aspect
@Component
public class OperateLogAspect {
private Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired(required = false)
private IDupComOperateLogService operateLogService;
@Autowired(required = false)
private IPrjUserService prjUserService;
/**
* 通过AOP方式,拦解注解的日志
* 后置通知:如果需要访问其他建议类型的连接点上下文,则应使用JoinPoint参数类型而不是ProceedingJoinPoint。
*/
@Pointcut(value = "@annotation(com.hec.dup.facade.mgr.annotation.OperateLogAnnotation)")
public void logAspect() {
}
@After("logAspect()")
public Object recordLog(JoinPoint point) throws Throwable {
//先执行业务
Object result = point.proceed();
try {
this.handle(point);
} catch (Exception e) {
e.printStackTrace();
log.error("日志记录出错!", e);
}
return result;
}
/**
* 获取拦截方法参数,处理日志
* @param point
* @throws Exception
*/
private void handle(ProceedingJoinPoint point) throws Exception {
//获取拦截的方法名
Signature sig = point.getSignature();
MethodSignature msig = null;
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法");
}
msig = (MethodSignature) sig;
Object[] params = point.getArgs();
Object target = point.getTarget();
Method method = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
//如果当前用户未登录,不做日志
PrjCurrUserInfo userInfo = (PrjCurrUserInfo)SecurityUtils.getSubject().getPrincipal();
if (null == userInfo) {
return;
}
//获取拦截方法的参数,获取登录用户对象
PrjUserEntity userEntity = userInfo.getUserEntity();
/**
// 拦截的实体类
Object target = joinPoint.getTarget();
// 拦截的方法名称
String methodName = joinPoint.getSignature().getName();
// 拦截的方法参数
Object[] args = joinPoint.getArgs();
// 拦截的参数类型
Class[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
**/
//获取注解日志内容
OperateLogAnnotation annotation = method.getAnnotation(OperateLogAnnotation.class);
//字典,替换成用table查询表注释
//Class dictClass = annotation.dict();
//通过表名,动态获取表字段名和注释
/* Map<String,String> metaMap = new HashMap<>();
//MetaTableVo metaTableVo = metaTableService.getByTableName(table);
if(StringUtil.isNotEmpty(table)){
List<MetaColumVo> metaColumns = metaColumService.queryByTable(table);
if(metaColumns!=null && metaColumns.size()>0){
for(MetaColumVo vo:metaColumns){
metaMap.put(vo.getColumnName(),vo.getColumnAlias());
}
}
}*/
StringBuilder sb = new StringBuilder();
for (Object param : params) {
sb.append(param);
sb.append(" & ");
}
//如果涉及到修改,比对修改前后值的变化内容
String logmsg ="";
/*if (methodName.indexOf("update") != -1 || methodName.indexOf("modify") != -1
|| methodName.indexOf("edit") != -1) {
Map<String, String> newMap = HttpKit.getRequestParameters(); //对象被修改后的内容
Object oldObj = redisSupport.getObject(HttpKit.getRequest().getSession().getId());
//Object oldObj = LogObjectHolder.me().get(); //获取为null
logmsg = ContrastObjFactory.contrastObj(table,key,metaMap,newMap,oldObj);
} else {
logmsg=content;
}*/
//记录操作日志
DupComOperateLogEntity operateLogEntity = getOperaLog( userEntity, target, method, logmsg, params );
operateLogService.save(operateLogEntity);
}
/**
* 封装操作日志实体对象
*
* @Date 2017/3/30 18:45
*/
public static DupComOperateLogEntity getOperaLog(PrjUserEntity userEntity, Object target, Method method, String msg, Object[] params) {
String classPath = target.getClass().getName(); //类名称,含路径
String classMethod = method.getName(); //方法名(英文)
OperateLogAnnotation annotation = method.getAnnotation( OperateLogAnnotation.class );
DupComOperateLogEntity operaLog = new DupComOperateLogEntity();
operaLog.setId( UuidUtil.getUuid() ); //主键
operaLog.setClassPath( classPath ); //类名称,含路径
operaLog.setClassMethod( classMethod ); //方法名(英文)
operaLog.setIpHost( userEntity.getLastLoginIp() ); //IP地址
operaLog.setOperateTime( new Date() ); //操作时间
operaLog.setOperateUserId( userEntity.getId() );//用户ID
operaLog.setOperateUserName( userEntity.getUserName() ); //用户名称
operaLog.setUserAccount( userEntity.getAccount() ); //用户帐号
operaLog.setUserType( userEntity.getUserType() ); //帐号类型
operaLog.setModuleType( annotation.moduleType() );//业务模块类型
operaLog.setModuleName( annotation.moduleName() );//业务模块名称
operaLog.setFunctionName( annotation.functionName() );//业务模块名称
operaLog.setTableName( annotation.tableName() ); //操作表名
JSONArray paramArray = JSONObject.parseArray( params.toString() ); //获取第一个参数的id
operaLog.setTableId( paramArray.getJSONObject( 0 ).getString( "id" ) );
operaLog.setOperateContent( annotation.operateContent() ); //操作内容
return operaLog;
}
}
-
2.3 定义applicationContext.xml配置
- 2.4 接口添加注解,接口被调用的时候会调用被aop处理
@OperateLogAnnotation(moduleType = "01") //这边添加切入点接口的注解
@RequestMapping(value = "testAop01")
@ResponseBody
public JsonResult testAop(BaseEntity baseEntity) {
JsonResult jr = new JsonResult();
baseEntity.setCreateTime( new Date() );
baseEntity.setDbUser( "123456789," );
baseEntity.setExport( true );
jr.setData( baseEntity );
return jr;
}
3 注意事项:该方式主要是通过注解的方式,个人觉得比较便利,当然也可以通过另外一种方式xml,比如 AOP实现方式3——通过<aop:config>来配置 ,需要注意的是aop的执行顺序,可参考 Spring AOP @Before @Around @After 等 advice 的执行顺序
以上所述就是小编给大家介绍的《Spring AOP 实现业务和异常日志记录实战》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- struts实战--登录功能实现
- java并发实战:连接池实现
- AudioQueue实现音频流实时播放实战
- Kubernetes 实战:Operator Finalizers 实现
- Redis 实战之实现定时执行任务
- struts实战--实现条件查询(利用dbutils)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
UNIX 时间戳转换
UNIX 时间戳转换
RGB HSV 转换
RGB HSV 互转工具