内容简介: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)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
个体与交互
Ken Howard、Barry Rogers / 贾永娜、张凯峰 / 机械工业出版社华章公司 / 2012-3-20 / 45.00元
对敏捷软件开发的关注重点,通常都集中在“机制”方面,即过程和工具。“敏捷宣言”认为,个体与交互的价值要高于过程和工具,但这一点很容易被遗忘。在敏捷开发中,如果你重新将注意力放在人的方面,将会收获巨大利益。 本书展示了如何解决敏捷团队在实际项目中遭遇的问题。同时,本书也是很有实用价值的敏捷用户指南,其中包含的故事、最佳实践方法、经验以及技巧均可应用到实际项目当中。通过逐步实践,你将学会如何让团......一起来看看 《个体与交互》 这本书的介绍吧!