最近做项目实现操作记录添加日志,由于aop这两种实现方式各有优缺点,所以都实现了一下以后根据具体业务选择。

1实现方式一注入:

1.1首先在xml中开启aop注入,需要引入的包此处省略,可百度自己查找。

<aop:aspectj-autoproxy />

1.2添加链接点

package com.oasis.wyvern.res.service.base.logService;

import java.lang.annotation.*;

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysSecureServiceLog {
String description() default "";
}

1.3添加切入点,可以添加多个切入点同理也可添加多个链接点

package com.oasis.wyvern.res.service.base.logService;

import com.oasis.wyvern.res.common.biz.enums.base.type.ActionType;
import com.oasis.wyvern.res.common.biz.enums.base.type.ServiceAopType;
import com.oasis.wyvern.res.common.biz.vo.record.oplog.BizOpLogVo;
import com.oasis.wyvern.res.dao.biz.record.oplog.SecureOpLogDao;
import com.oasis.wyvern.res.model.base.context.secure.SecurityContextHolder;
import com.oasis.wyvern.res.model.biz.record.oplog.SecureOpLog;
import com.oasis.wyvern.res.service.base.record.oplog.BizOpLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Arrays; @Aspect
@Component
public class Aop2Log {
private static final Logger logger = LoggerFactory.getLogger(Aop2Log.class);
@Resource
private BizOpLogService bizOpLogVoService; @Resource
private SecureOpLogDao secureOpLogDao;
/**
* 用户Service层切点
*/
@Pointcut("@annotation(com.oasis.wyvern.res.service.base.logService.ServiceLog)")
public void serviceAspect() {
} /**
* 系统安全层面切入点
*/
@Pointcut("@annotation(com.oasis.wyvern.res.service.base.logService.SysSecureServiceLog)")
public void sysSecureServiceAspect() {
} /**
* 用户service
* @param point
*/
@AfterReturning("serviceAspect()")
public void doAfter2Service(JoinPoint point){
try {
String actor ="";
if(SecurityContextHolder.getContext().getUser()!=null){
actor = SecurityContextHolder.getContext().getUser().getLoginName();
}
String method = point.getSignature().getName();
String entity = point.getTarget().getClass().getSimpleName();
String args = getAvailableArgs(point.getArgs());
BizOpLogVo bizOpLogVo = new BizOpLogVo();
bizOpLogVo.setActor(actor);
bizOpLogVo.setEntityType(entity.replace("ServiceImpl",""));
bizOpLogVo.setAction(methodType(method));
bizOpLogVo.setUdf1(args.length()>200?args.substring(0,200):args);
bizOpLogVo.setUdf2(method);
bizOpLogVo.setUdf3(getServiceMthodDescription(point,"ServiceLog"));
bizOpLogVoService.createBizOpLog(bizOpLogVo);
} catch (Exception e) {
logger.error("日志类异常");
logger.error(e.getMessage());
}
} /**
* 用户操作异常
* @param jp
* @param e
* @throws Exception
*/
@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
public void afterThrowing2Service(JoinPoint jp,Throwable e) throws Exception{
logger.error("异常:"+jp.getTarget().getClass().getName()+"."+jp.getSignature().getName());
logger.error(e.getMessage());
} /**
* 系统服务层操作
* @param point
*/
@AfterReturning("sysSecureServiceAspect()")
public void doAfter2Sys(JoinPoint point){
try {
String actor ="";
if(SecurityContextHolder.getContext().getUser()!=null){
actor = SecurityContextHolder.getContext().getUser().getLoginName();
}
String method = point.getSignature().getName();
String entity = point.getTarget().getClass().getSimpleName();
String args = getAvailableArgs(point.getArgs());
SecureOpLog secureOpLog = new SecureOpLog();
secureOpLog.setActor(actor);
secureOpLog.setEntityType(entity.replace("ServiceImpl",""));
secureOpLog.setAction(methodType(method));
secureOpLog.setUdf1(args.length()>200?args.substring(0,200):args);
secureOpLog.setUdf2(method);
secureOpLog.setUdf3(getServiceMthodDescription(point,"SysSecureServiceLog"));
secureOpLogDao.insert(secureOpLog);
} catch (Exception e) {
logger.error("日志类异常");
logger.error(e.getMessage());
}
} //在方法抛出异常是拦截
@AfterThrowing(pointcut = "sysSecureServiceAspect()", throwing = "e")
public void afterThrowing2Sys(JoinPoint jp,Throwable e) throws Exception{
logger.error("异常:"+jp.getTarget().getClass().getName()+"."+jp.getSignature().getName());
logger.error(e.getMessage());
} private ActionType methodType(String method){
method = method.toLowerCase();
if(method.contains("create")||method.contains("insert")||method.contains("save")){
return ActionType.CREATE;
}else if(method.contains("delete")){
return ActionType.DELETE;
}else if(method.contains("edit")||method.contains("update")){
return ActionType.UPDATE;
}else if(method.contains("frozen")){
return ActionType.FROZEN;
}else if(method.contains("unfrozen")) {
return ActionType.UNFROZEN;
}
else {
return ActionType.SEARCH;
}
} private String getAvailableArgs(Object [] args){
String strArgs = Arrays.toString(args);
String []params= strArgs.split(",");
String argsStr="";
for (String arg:params){
if(arg.contains("[")&&!arg.endsWith(">")){
argsStr = arg.substring(arg.lastIndexOf("["));
}else if(!arg.contains("[")&&!arg.endsWith(">")){
argsStr+=","+arg;
}
}
return argsStr;
} private String getServiceMthodDescription(JoinPoint joinPoint ,String which)
throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
if(which.equals(ServiceAopType.ServiceLog.toString())) {
description = method.getAnnotation(ServiceLog.class).description();
}else if(which.equals(ServiceAopType.SysSecureServiceLog.toString())){
description = method.getAnnotation(SysSecureServiceLog.class).description();
}
break;
}
}
}
return description;
}
}

1.4在具体的方法上需要时添加链接点

    @Override
@SysSecureServiceLog(description= "delete user")
public int deleteUser(Long userId){
int res = userDao.delete(userId);
associateDao.deleteByAssoc(AssociateTable.ROLE_USER,userId);
return res;
}

2方式二通过xml声明配置实现:

2.1首先在xml配置如下:因为考虑到日志保存在操作异常或者事务回滚的情况下 操作日志不需要写入数据库,或者也需要回滚,故用了 配置的order顺序来解决。

<!--添加操作日志-->
<bean id = "logs" class="com.oasis.wyvern.res.service.base.logService.Aop2Log"/>
<aop:config >
<aop:aspect ref="logs" order="3">
<!-- 定义切入点 -->
<!-- aop包下的所有以Service结尾的类的方法 -->
<aop:pointcut id="doMethod"
expression="(execution(* com.oasis.wyvern.res.service.biz..*Service.save*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.create*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.insert*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.update*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.change*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.lock*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.unLock*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.reset*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.delete*(..)) )" />
<aop:after-returning method="doAfter" pointcut-ref="doMethod"/>
</aop:aspect>
</aop:config>
<!--异常时-->
<aop:config>
<aop:aspect ref="logs" order="1">
<aop:pointcut id="throwinglog"
expression="(execution(* com.oasis.wyvern.res.service.biz..*Service.save*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.create*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.insert*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.update*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.change*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.lock*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.unLock*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.reset*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.delete*(..)) )" />
<aop:after-throwing pointcut-ref="throwinglog" throwing="e" method="afterThrowing"/>
</aop:aspect>
</aop:config> <tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="add*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="update*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="delete*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--事务回滚-->
<aop:config>
<aop:pointcut id="serviceMethods"
expression="(execution(* com.oasis.wyvern.res.service.biz..*Service.save*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.create*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.insert*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.update*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.change*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.lock*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.unLock*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.reset*(..)) or
execution(* com.oasis.wyvern.res.service.biz..*Service.delete*(..)) )"
/>
<aop:advisor advice-ref="txAdvice"
pointcut-ref="serviceMethods" order="2"/>
</aop:config>

2.2包路径图,别把切入点的类添加到连接点扫描中:execution表达式可百度,根据业务需要配置不同的拦截规则。

2.3切入点代码

package com.oasis.wyvern.res.service.base;

import com.oasis.wyvern.res.common.biz.enums.base.type.ActionType;
import com.oasis.wyvern.res.common.biz.vo.record.oplog.BizOpLogVo;
import com.oasis.wyvern.res.model.base.context.secure.SecurityContextHolder;
import com.oasis.wyvern.res.service.base.record.oplog.BizOpLogService;
import org.aspectj.lang.JoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import java.util.Arrays; public class Aop2Log {
private static final Logger logger = LoggerFactory.getLogger(Aop2Log.class);
@Autowired
private BizOpLogService bizOpLogVoService;
public void doAfter(JoinPoint point){
String actor ="";
if(SecurityContextHolder.getContext().getUser()!=null){
actor = SecurityContextHolder.getContext().getUser().getLoginName();
}
String method = point.getSignature().getName();
String entity = point.getTarget().getClass().getSimpleName();
String args = getAvailableArgs(Arrays.toString(point.getArgs()));
BizOpLogVo bizOpLogVo = new BizOpLogVo();
bizOpLogVo.setActor(actor);
bizOpLogVo.setEntityType(entity.replace("ServiceImpl",""));
bizOpLogVo.setAction(methodType(method));
bizOpLogVo.setUdf1(args.length()>200?args.substring(0,200):args);
bizOpLogVo.setUdf2(method);
bizOpLogVoService.createBizOpLog(bizOpLogVo);
} //在方法抛出异常是拦截
public void afterThrowing(JoinPoint jp,Throwable e) throws Exception{
logger.error("异常:"+jp.getTarget().getClass().getName()+"."+jp.getSignature().getName());
logger.error(e.getMessage());
} private ActionType methodType(String method){
method = method.toLowerCase();
if(method.contains("create")||method.contains("insert")||method.contains("save")){
return ActionType.CREATE;
}else if(method.contains("delete")){
return ActionType.DELETE;
}else if(method.contains("edit")||method.contains("update")){
return ActionType.UPDATE;
}else if(method.contains("frozen")){
return ActionType.FROZEN;
}else if(method.contains("unfrozen")) {
return ActionType.UNFROZEN;
}
else {
return ActionType.SEARCH;
}
} private String getAvailableArgs(String args){
String []params= args.split(",");
String argsStr="";
for (String arg:params){
if(arg.contains("[")&&!arg.endsWith(">")){
argsStr = arg.substring(arg.lastIndexOf("["));
}else if(!arg.contains("[")&&!arg.endsWith(">")){
argsStr+=","+arg;
}
}
return argsStr;
}
}

好了,到此为止两种方法完全介绍完整。

aop为系统添加操作日志,注入或配置声明的方式来实现的更多相关文章

  1. .NetCore中使用ExceptionLess 添加操作日志

    上一篇文章已经扩展了日志,下面我们在结合下处理操作日志 通常我们想到操作日志 可能想到的参数可能有 模块 方法 参数内容 操作人 操作时间 操作 Ip 下面我们就来结合这些信息添加操作日志 如果要在代 ...

  2. 我使用Spring AOP实现了用户操作日志功能

    我使用Spring AOP实现了用户操作日志功能 今天答辩完了,复盘了一下系统,发现还是有一些东西值得拿出来和大家分享一下. 需求分析 系统需要对用户的操作进行记录,方便未来溯源 首先想到的就是在每个 ...

  3. .NetCore 中扩展ExceptionLess 实现链式方法添加操作日志

    在使用ExceptionLess添加日志的时候,发现还是有一些写法上的个人觉得不爽的地方,比如添加Info日志 ExceptionlessClient.Default.CreateLog(source ...

  4. springmvc+log4j操作日志记录,详细配置

    没有接触过的,先了解一下:log4j教程 部分内容来:log4j教程 感谢! 需要导入包: log包:log4j-12.17.jar 第一步:web.xml配置 <!-- log4j配置,文件路 ...

  5. 为table元素添加操作日志

    1.为所有的元素添加函数onchange() <input id="status" value="${status}" onchange="ch ...

  6. spring aop切面编程实现操作日志步骤

    1.在spring-mvc.xml配置文件中打开切面开关: <aop:aspectj-autoproxy proxy-target-class="true"/> 注意: ...

  7. Spring AOP的实现记录操作日志

    适用场景: 记录接口方法的执行情况,记录相关状态到日志中. 注解类:LogTag.java package com.lichmama.spring.annotation; import java.la ...

  8. Yii2如何添加sql日志记录的配置信息

    在使用Yii2框架的时候,常常会出现没有sql日志记录的问题.在代码里一句一句的打印sql语句也不现实.所以就要用文件记录起来. 在 config/web.php 里面的 log配置中增加如下配置 [ ...

  9. 新来的老大,剑走偏锋,干掉AOP做操作日志,实现后我们都惊呆了

    前言 用户在操作我们系统的过程中,针对一些重要的业务数据进行增删改查的时候,我们希望记录一下用户的操作行为,以便发生问题时能及时的找到依据,这种日志就是业务系统的操作日志. 本篇我们来探讨下常见操作日 ...

随机推荐

  1. .NET MVC学习之模型绑定

    ASP.NET MVC学习之模型绑定(2)   继ASP.NET MVC学习之模型绑定继续 3.手工调用模型绑定 很多情况下我们都是通过形参的方式接收来自http流中的数据,这看似是完美的,但是缺少了 ...

  2. jQuery Tags Input 插件显示选择记录

    利用jQuery Tags Input 插件显示选择记录 最近花了不少时间在重构和进一步提炼我的Web开发框架上,力求在用户体验和界面设计方面,和Winform开发框架保持一致,而在Web上,我主要采 ...

  3. 【值得收藏】符号计算软件Maple的学习资料汇编【可免费下载】

    Maple学习教程 Maple是目前世界上最为通用的数学和工程计算软件之一,在数学和科学领域享有盛誉,有“数学家的软件”之称.Maple在全球拥有数百万用户,被广泛地应用于科学.工程和教育等领域,用户 ...

  4. jQuery的入门与简介

    jQuery的入门与简介<思维导图>   <初学者请各位高手指点指点> jQuery是继Prototype之后又一个优秀的JavaScript库,在JavaScript基础上我 ...

  5. [转]Inside Swift

    原文地址:http://www.eswick.com/2014/06/inside-swift/   Inside Swift Swift is Apple's new programming lan ...

  6. Sparse Filtering

    Sparse Filtering 当前很多的特征学习(feature learning)算法需要很多的超参数(hyper-parameter)调节, Sparse Filtering则只需要一个超参数 ...

  7. unittest 框架

    unittest 框架 学习unittest 很好的一个切入点就是从selenium IDE 录制导出脚本.相信不少新手学习selenium 也是从IED 开始的. IDE学习参考: 菜鸟学自动化测试 ...

  8. 什么时候用spring

    论公司spring的滥用   这个公司每个项目用不同的一套开发框架,实在忍不住拿一个出来说说事.

  9. create OpenVPN on ubuntu12.04

    ---恢复内容开始--- 最近比较火的有digitalocean  的SSD VPS,配置还不错.每个月5刀,512MB内存,CPU被虚拟过.不是KVM.链接能量也不大. 节点在西雅图,对环太平洋比较 ...

  10. phpcms 2008 后台发文章chrome和firefox文章不能上传图片的问题

    /web/fckeditor/editor/dialog/fck_image.html /web/fckeditor/editor/dialog/fck_image/fck_image.js 这两个文 ...