在项目中需要在特定场合进行记录日志,这里使用 spring AOP 自定义注解方式实现日志管理
如果代码中有注解不明白的地方,欢迎提问。
1、spring 配置文件添加
<!--如果不写proxy-target-class="true"这句话也没问题-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
2、编写注解类
@Target(value = ElementType.METHOD)
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
public @interface SysOperationLog {
/**
* 操作类型
*/
String operTypeId() default "";
/**
* 方法描述
*/
String methodDesc();
}
3、编写切面类(这里使用的是环绕通知,切 Controller 和 Service,项目中有些事件不通过Controller 所以 Service 也切过去)
@Component
@Aspect
public class SysOperationLogAspect {
@Autowired
private SysOperationLogService sysOperationLogService;
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Around("within(@org.springframework.stereotype.Controller * || @org.springframework.stereotype.Service *) && @annotation(sysOperationLog)")
public Object recordOperationLog(ProceedingJoinPoint jp, SysOperationLog sysOperationLog) throws Throwable {
logger.debug("[recordOperationLog] start....");
Map<String, Object> logMap = new HashMap<String, Object>(8);
Signature sig = jp.getSignature();
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能用于方法!");
}
logMap.put("method", jp.getSignature().getName());
logMap.put("methodDesc", sysOperationLog.methodDesc());
logMap.put("operTypeId", sysOperationLog.operTypeId());
sysOperationLogService.save(logMap);
logger.debug("[recordOperationLog] end.");
return jp.proceed();
}
4、编写service类(这里使用线程池,异步保存,)
@Service
public class SysOperationLogService {
@Autowired
private SysOperationLogDao sysOperationLogDao;
@Autowired
@Qualifier("taskExecutor")
private ThreadPoolTaskExecutor taskExecutor;
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 异步保存
*
* @param logMap
*/
public void save(Map<String, Object> logMap) {
//获取登录人员信息
logMap.put("operStaffName", ThreadLocalInfoHolder.getLoginUser().getUserName());
logMap.put("operStaffNbr", ThreadLocalInfoHolder.getLoginUser().getLoginName());
taskExecutor.execute(new RecordLogHandler(logMap));
}
public class RecordLogHandler implements Runnable {
private Map<String, Object> logMap;
public RecordLogHandler(Map<String, Object> logMap) {
this.logMap = logMap;
}
@Override
public void run() {
logger.debug("#### ThreadName: " + Thread.currentThread().getName() + " record log .");
sysOperationLogDao.recordLog(logMap);
}
}
}
5、编写dao类
@Repository
public class SysOperationLogDao extends BaseJdbcDao {
public int recordLog(Map<String, Object> params) {
Iterator<String> it = params.keySet().iterator();
for (; it.hasNext(); ) {
String k = it.next();
logger.debug(k + "=" + MapUtils.getString(params, k));
}
StringBuilder sb = new StringBuilder(256);
sb.append("INSERT INTO AST_CHECK_OPERATION_LOG \n");
sb.append(" (LOG_ID, OPER_TYPE_ID, OPER_STAFF_NBR, OPER_STAFF_NAME, OPER_DATE, \n");
sb.append(" TASK_ID, TASK_NAME, TASK_CODE, AST_ID, AST_CODE) \n");
sb.append("VALUES \n");
sb.append(" (SEQ_AST_CHECK_OPERATION_LOG.NEXTVAL, ?, ?, ?, SYSDATE) \n");
return getJdbcTemplate().update(sb.toString(),
MapUtils.getString(params, "operTypeId", ""),
MapUtils.getString(params, "operStaffNbr", ""),
MapUtils.getString(params, "operStaffName", "")
}
}
6、测试类方法
@SysOperationLog(methodDesc = "查询操作", operTypeId = "803")
public Map<String, Object> queryInventoryHistoryList(Map<String, Object> param) {
System.out.println("记录查询");
}
如果在实际的项目中运行效率不好,在这里请看到博客的大牛给点建议!!