在項目開發中,相信不管什麼類型的項目,多多少少都會有涉及到業務日誌的記錄需求,即將用戶對數據的新增、修改、甚至某些特殊的查詢進行日誌記錄。今天,日月將教大家一種使用自定義註解+AOP的方式對接口進行記錄日誌,做到日誌代碼和業務代碼分離解耦,OK,話不多說,直接上代碼。
本次示例將對用戶的註冊登陸進行日誌記錄
1、創建自定義註解
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author chenqi
* @Description 自定義元註解--用於記錄日誌
**/
@Target({ java.lang.annotation.ElementType.METHOD })//字段註解 , 用於描述方法
@Retention(RetentionPolicy.RUNTIME)//在運行期保留註解信息
public @interface PartnerLog {
public abstract int value();
}
2、創建日誌枚舉類
/**
* @Author chenqi
* @Description 日誌枚舉
**/
public enum PartnerLogEnum {
/**=== 用戶相關【10001-10200】 ===**/
LOGTYPE_USER_10001(10001,"註冊"),
LOGTYPE_USER_10002(10002,"登錄"),
;
/*兩個屬性*/
private Integer logType;
private String name;
/*構造函數*/
private PartnerLogEnum(Integer logType , String name) {
this.logType = logType;
this.name = name;
}
/*屬性的setter和getter*/
public Integer getLogType() {
return logType;
}
public void setLogType(Integer logType) {
this.logType = logType;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3、定義AOP-Aspect
/**
* @Author chenqi
* @Description 日誌記錄 AOP
**/
@Aspect
@Component
@Slf4j
public class PartnerLogAspect {
@Pointcut("@annotation(自定義註解類的包路徑.PartnerLog)")
public void partnerLogPointCut() {}
@Around("partnerLogPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
//方法執行並返回結果result
Object result = point.proceed();
//記錄日誌
savePartnerLog(point,result);
//返回結果
return result;
}
private void savePartnerLog(ProceedingJoinPoint joinPoint,Object result) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
PartnerLog partnerlog = (PartnerLog) method.getAnnotation(PartnerLog.class);
if (partnerlog != null) {
Object[] args = joinPoint.getArgs();
if(partnerlog.value() == PartnerLogEnum.LOGTYPE_USER_10001.getLogType().intValue()) {//註冊
PartnerUserRegisterDTO dto = (PartnerUserRegisterDTO)args[0];//可以獲取到接口方法的入參對象
R<Boolean> r = (R<Boolean>)result;
//執行成功記錄日誌
if(!CheckUtils.objCheckNull(r) && r.getCode() == 0 && r.getData()) {
//記錄日誌 日誌的打印可以配合logback輸出到日誌文件中進行存儲。
log.info("【註冊】:用戶[{}]完成註冊,邀請碼爲[{}]",
dto.getUserName(),
dto.getRecommenderCode());
}
}
if(partnerlog.value() == PartnerLogEnum.LOGTYPE_USER_10002.getLogType().intValue()) {//登錄
PartnerUserLoginDTO dto = (PartnerUserLoginDTO)args[0];
R<PartnerUserLoginVO> r = (R<PartnerUserLoginVO>)result;
//執行成功記錄日誌
if(!CheckUtils.objCheckNull(r) && r.getCode() == 0 &&
!CheckUtils.objCheckNull(r.getData()) &&
!CheckUtils.strCheckNull(r.getData().getToken())) {
//記錄日誌
String loginTypeStr = dto.getType().intValue() == 1 ? "賬號密碼登錄" : "短信登錄";
log.info("【登錄】:用戶[{}]成功登錄了XXX系統,登錄方式爲[{}]",
dto.getUserName(),loginTypeStr);
}
}
}
}
}
4、業務接口方法添加日誌註解
/**
* @Author chenqi
* @Description 註冊
**/
@PartnerLog(10001)
@Transactional(rollbackFor = Exception.class)
@Override
public R<Boolean> register(PartnerUserRegisterDTO partnerUserRegisterDTO) {
//此處省略業務代碼
。。。。。。
return synRegisterDataToApp(dto);
}
OK,到這裏就完成了,登陸的示例我就不貼了,大家可以看到,我們最終只需要將自定義的日誌註解添加到需要記錄日誌的接口方法上即可實現日誌代碼與業務代碼完全分離。
如果該文章有幫助到您,就留言點個贊吧!您的支持與肯定是我持續更新最大的動力。