内容简介: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)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Music Recommendation and Discovery
Òscar Celma / Springer / 2010-9-7 / USD 49.95
With so much more music available these days, traditional ways of finding music have diminished. Today radio shows are often programmed by large corporations that create playlists drawn from a limited......一起来看看 《Music Recommendation and Discovery》 这本书的介绍吧!
XML、JSON 在线转换
在线XML、JSON转换工具
RGB CMYK 转换工具
RGB CMYK 互转工具