需求:开发中,需要简单的记录用户的操作日志。
AOP技术利用一种称为“横切”的技术,解剖封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,这样就能减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。
具体实现:
第一步:spring-mvc.xml文件中配置
<mvc:annotation-driven/>
<!-- 启动对@AspectJ注解的支持 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
第二步:自定义注解
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)@Documented
public @interface SystemLog {
String name() default "";
}
第三步:定义切面
@Aspect
@Component
public class LogAop {
private final Logger logger = Logger.getLogger(MqttMessageHandlerRunnable.class);
@Autowired
private IApiCallRecordService callService;
/**
*
* (后置通知)
* @Title: afterExec
* @param joinPoint 切点
* @param rtv 方法返回值
*/
@AfterReturning(value="@annotation(com.lingyun.llkmc.log.SystemLog)",returning = "rtv")
public void afterExec(JoinPoint joinPoint,Object rtv){
try {
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
String methodName = method.getAnnotation(SystemLog.class).name();
int developId = getDevelopId(joinPoint); //从切点中获取,方法的请求参数中的用户Id
JSONObject ro = (JSONObject)rtv; //我们系统中controller接口方法返回都是json格式
//记录操作日志,哪个用户调用了哪个方法+返回状态码
saveLog(methodName,ro.getString("statusCode"),developId);
} catch (Exception e) {
logger.error("记录接口调用日志错误",e);
}
}
/**
*
* (异常通知)
* @Title: afterThrowing
* @param joinPoint 切点
* @param t 抛出的异常
*/
@AfterThrowing(value="@annotation(com.lingyun.llkmc.log.SystemLog)",throwing = "t")
public void afterThrowing(JoinPoint joinPoint,Throwable t){
try {
MethodSignature ms=(MethodSignature) joinPoint.getSignature();
Method method=ms.getMethod();
String methodName = method.getAnnotation(SystemLog.class).name();
int developId = getDevelopId(joinPoint);
//记录日志
saveLog(methodName,"500",developId);
logger.error(method.getName()+"接口调用日志异常",t);
} catch (Exception e) {
logger.error("记录接口调用日志错误",e);
}
}
/**
*
* (插入日志到数据库)
* @Title: saveLog
* @param method
* @param statusCode
* @param developerId
*/
private void saveLog(String method, String statusCode, Integer developerId) {
ApiCallRecord record = new ApiCallRecord(method, statusCode, developerId);
callService.insert(record);
}
/**
*
* (获取用户Id)
* @Title: getDevelopId
* @param joinPoint
* @return
*/
private int getDevelopId(JoinPoint joinPoint) {
Object[] os = joinPoint.getArgs();
int developerId = 0;
for (int i = 0; i < os.length; i++) {
Object o = os[i];
if (o instanceof DeveloperUser) {
developerId = ((DeveloperUser) o).getDeveloperId();
break;
}
}
return developerId;
}
}
第四步:在controller的接口方法上使用我们的自定义注解
@SystemLog(name="添加设备")
@ResponseBody
@RequestMapping(value="addDevice/{openToken}", method=RequestMethod.POST)
public JSONObject addDevice(HttpServletRequest request){
}