之前做的一个项目有这么个要求,在日志管理系统里,需要将某些日志信息存储到数据库里,供用户、管理员查看分析。因此我就花了点时间搞了一下这一功能。
说白了就是在用户在调用某接口的时候,相应的会在数据库进行保存,是谁对什么做了什么样的操作,要写明白,在这里使用spring提供的AOP来将切面类织入个个接口中,话不多说,直接上代码
public class LogAspect {
//自定义一个切面类
private static final Logger LOGGER = LogManager.getLogger(LogAspect.class);
private static final String LOG_CONTENT = "[类名]:%s,[方法]:%s,[参数]:%s";
private static final String[] METHOD_CONTENT = { "insert", "delete", "update", "save","select" };
@Autowired
private ISysLogService logService;
/**
* 前置通知
*
* @date 2018年11月22日
*
* @param joinPoint
*/
public void before(JoinPoint joinPoint) {
LOGGER.info("前置通知");
saveLog(joinPoint, null);
}
/**
* 异常操作并带有返回值
*
* @author Dingdong
* @date 2017年5月24日
*
* @param joinPoint
* @param argObj
*/
public void afterThrowing(JoinPoint joinPoint, Exception exception) {
LOGGER.info("异常操作");
saveLog(joinPoint, exception);
}
/**
* 保存日志到数据库
*
* @author Dingdong
* @date 2017年5月24日
*
* @param joinPoint
* @param exception
*/
private void saveLog(JoinPoint joinPoint, Exception exception) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String methodName = joinPoint.getSignature().getName();// 方法名
Method method = currentMethod(joinPoint, methodName);
OperationLogger log = method.getAnnotation(OperationLogger.class);
SysLog logs = new SysLog();
logs.setUserId(1);
logs.setDateTime(new Date());
logs.setContent(operateContent(joinPoint, methodName, request));
if (exception != null) {
LOGGER.info("Service出现异常");
logs.setOperation("异常");
logs.setAbnormity(exception.toString());
logService.insert(logs);
} else {
LOGGER.info("方法名:" + methodName);
if (isWriteLog(methodName)) {
logs.setOperation((log != null) ? log.description() : null);
logService.insert(logs);
}
}
}
/**
* 判断是哪些方法可以写入LOG
*
* @author Dingdong
* @date 2017年5月24日
*
* @param method
* @return
*/
private boolean isWriteLog(String method) {
boolean falg = false;
for (String s : METHOD_CONTENT) {
if (method.indexOf(s) > -1) {
falg = true;
break;
}
}
return falg;
}
/**
* 获取当前执行的方法并判断
*
* @param joinPoint
* 连接点
* @param methodName
* 方法名称
* @return 方法
*/
private Method currentMethod(JoinPoint joinPoint, String methodName) {
Method[] methods = joinPoint.getTarget().getClass().getMethods();
Method resultMethod = null;
for (Method method : methods) {
if (method.getName().equals(methodName)) {
resultMethod = method;
break;
}
}
return resultMethod;
}
/**
* 获取当前传递的参数
*
* @param joinPoint
* 连接点
* @param methodName
* 方法名称
* @return 操作内容
*/
private String operateContent(JoinPoint joinPoint, String methodName, HttpServletRequest request) {
String className = joinPoint.getTarget().getClass().getName();
Object[] params = joinPoint.getArgs();
StringBuffer bf = new StringBuffer();
if (params != null && params.length > 0) {
Enumeration<String> paraNames = request.getParameterNames();
while (paraNames.hasMoreElements()) {
String key = paraNames.nextElement();
bf.append(key).append("=");
bf.append(request.getParameter(key)).append("&");
}
if (StringUtils.isBlank(bf.toString())) {
bf.append(request.getQueryString());
}
}
return String.format(LOG_CONTENT, className, methodName, bf.toString());
}
}
将切面类织入个个service,自定义一个注解,为了识别接口操作的类型
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationLogger {
String description() default "";
}
这样基本就大功告成了,接下来就是关于AOP的配置文件的配置(只附了事务aop相关的配置)
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="select*" propagation="REQUIRED" read-only="true" />
<tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception" />
<tx:method name="*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<!--将日志类注入到bean中。 -->
<bean id="logAspect" class="切面类位置"></bean>
<!-- 启用@AspectJ支持 -->
<aop:aspectj-autoproxy/>
<!-- 配置切面 -->
<aop:config>
<aop:pointcut id="transactionPointcut" expression="execution(需要在哪里进行织入切面类)" />
<aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />
<!--调用日志类 -->
<aop:aspect id="LogAspect" ref="logAspect" order="1">
<!--配置在service包下所有的类在调用之前都会被拦截 -->
<!-- <aop:after-returning pointcut-ref="transactionPointcut" returning="argObj" arg-names="argObj" method="afterReturning"/> -->
<aop:after-throwing pointcut-ref="transactionPointcut" throwing="exception" arg-names="exception" method="afterThrowing"/>
</aop:aspect>
</aop:config>
这样就大功告成啦,需要源码的可以私聊我!!!!