一. 概述
在日常开发中, 我们经常会和其他系统做对接, 系统间的对接有时会出现异常, 为了方便排查接口对接异常, 通常我们都会把对接的信息记录下来, 本文将简单介绍通过动态代理+注解的形式记录接口对接日志
二. 实现过程
2.1 创建接口日志记录表
本例子就不写sql了, 直接来看实体类吧
@Data
public class InterfaceLogDTO implements Serializable {
/**
* 日志ID
*/
@TableId("LOG_ID")
private Long logId;
/**
* 接口名称
*/
@TableField("SERVICE_NAME")
private String serviceName;
/**
* 接口类型(HTTP,WEBSERVICE)
*/
@TableField("SERVICE_TYPE")
private String serviceType;
/**
* 传输类型(RECEIVE:接收,SEND:发送)
*/
@TableField("TYPE")
private String type;
/**
* 状态(SUCCESS:成功,FAIL:失败)
*/
@TableField("STATUS")
private String status;
/**
* 单据类型
*/
@TableField("BILL_TYPE")
private String billType;
/**
* 完成时间
*/
@TableField("FINISH_DATE")
private Date finishDate;
/**
* 目标系统
*/
@TableField("TARGET_SYS")
private String targetSys;
/**
* 访问地址
*/
@TableField("URL")
private String url;
/**
* 传输内容
*/
@TableField("SERVICE_INFO")
private String serviceInfo;
/**
* 返回信息
*/
@TableField("RETURN_INFO")
private String returnInfo;
/**
* 报错信息
*/
@TableField("ERROR_INFO")
private String errorInfo;
/**
* 创建时间开始
*/
private Date creationDateBegin;
/**
* 创建时间结束
*/
private Date creationDateEnd;
}
2.2 编写日志注解
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiLog {
/**
* 接口名称
*/
String serviceName();
/**
* 接口类型(HTTP,WEBSERVICE)
* 默认HTTP
*/
String serviceType() default "HTTP";
/**
* 传输类型(RECEIVE:接收,SEND:发送)
*/
String type() default "SEND";
/**
* 单据类型
*/
String billType() default "";
/**
* 目标系统
*/
String targetSys() default "";
/**
* 访问地址
*/
String url() default "";
/**
* 回调检查结果方法类
* @return
*/
Class<? extends LogWriteBack> aClass();
}
说明: 注解主要记录接口的基本信息,其中回调方法是用来检查接口返回结果的状态判断是否成功,因为每种业务场景都不一样,所以要手动写一个回调方法
2.3 编写回调方法接口
public interface LogWriteBack<R> {
/**
* 处理业务执行返回信息, 获取状态和报错信息
* @param r
* @return
*/
LogWriteBackDto getReturnStatusInfo(R r);
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LogWriteBackDto {
/**
* 状态(SUCCESS:成功,FAIL:失败)
* 用来判断是否成功或失败
* @see com.midea.cloud.common.enums.api.ResultStatus
*/
@TableField("STATUS")
private String status;
/**
* 报错信息(没有可以为空)
*/
private String errorInfo;
}
2.4 编写日志代理
@Aspect
@Slf4j
@Component
public class ApiLogAop {
@Around(value = "@annotation(com.midea.cloud.common.annotation.ApiLog)")
public Object apiLog(ProceedingJoinPoint pjp) throws Throwable{
Object obj ;
InterfaceLogDTO interfaceLogDTO = new InterfaceLogDTO();
// 设置请求参数
setServiceInfo(pjp, interfaceLogDTO);
//创建开始时间
interfaceLogDTO.setCreationDateBegin(new Date());
interfaceLogDTO.setDealTime(1L);
// 回调方法类
LogWriteBack logWriteBack = null;
// 获取注解信息
MethodSignature signature = (MethodSignature) pjp.getSignature();
ApiLog annotation = signature.getMethod().getAnnotation(ApiLog.class);
if(null != annotation){
// 设置日志基础信息
interfaceLogDTO.setServiceName(annotation.serviceName());
interfaceLogDTO.setServiceType(annotation.serviceType());
interfaceLogDTO.setType(annotation.type());
interfaceLogDTO.setBillType(annotation.billType());
interfaceLogDTO.setTargetSys(annotation.targetSys());
interfaceLogDTO.setUrl(annotation.url());
logWriteBack = annotation.aClass().newInstance();
}
try {
// 具体业务方法
obj = pjp.proceed();
LogWriteBackDto returnStatusInfo = null;
// 记录返回参数
setReturnInfo(obj, interfaceLogDTO);
// 执行回调方法
executeCallback(obj, interfaceLogDTO, logWriteBack);
} catch (Exception e) {
String errorMsg = ExceptionUtil.getErrorMsg(e);
interfaceLogDTO.setErrorInfo(errorMsg);
interfaceLogDTO.setStatus(ResultStatus.FAIL.name());
throw e;
}finally {
try {
interfaceLogDTO.setCreationDateEnd(new Date());
// 保存日志操作
// createInterfaceLog(interfaceLogDTO);
} catch (Exception e) {
String errorMsg = ExceptionUtil.getErrorMsg(e);
log.error(interfaceLogDTO.getServiceName()+"保存日志报错{}" + errorMsg);
}
}
return obj;
}
public void setReturnInfo(Object obj, InterfaceLogDTO interfaceLogDTO) {
if (!ObjectUtils.isEmpty(obj)) {
try {
// 获取请求参数
String paramJson = JSON.toJSONString(obj);
interfaceLogDTO.setReturnInfo(paramJson);
} catch (Exception e) {
String errorMsg = ExceptionUtil.getErrorMsg(e);
interfaceLogDTO.setServiceInfo("请求参数解析报错{}" + errorMsg);
}
}
}
// 执行回调方法
public void executeCallback(Object obj, InterfaceLogDTO interfaceLogDTO, LogWriteBack logWriteBack) {
try {
LogWriteBackDto returnStatusInfo;
if(null != logWriteBack){
returnStatusInfo = logWriteBack.getReturnStatusInfo(obj);
interfaceLogDTO.setStatus(returnStatusInfo.getStatus());
interfaceLogDTO.setErrorInfo(returnStatusInfo.getErrorInfo());
if (ResultStatus.SUCCESS.name().equals(returnStatusInfo.getStatus())) {
interfaceLogDTO.setFinishDate(new Date());
}
}
} catch (Exception e) {
String errorMsg = ExceptionUtil.getErrorMsg(e);
interfaceLogDTO.setErrorInfo("执行回调方法报错=>"+errorMsg);
interfaceLogDTO.setStatus(ResultStatus.FAIL.name());
}
}
public void setServiceInfo(ProceedingJoinPoint pjp, InterfaceLogDTO interfaceLogDTO) {
try {
// 获取请求参数
Object[] args = pjp.getArgs();
if(!ObjectUtils.isEmpty(args)){
String paramJson = JSON.toJSONString(args);
interfaceLogDTO.setServiceInfo(paramJson);
}
} catch (Exception e) {
String errorMsg = ExceptionUtil.getErrorMsg(e);
interfaceLogDTO.setServiceInfo("请求参数解析报错{}" + errorMsg);
}
}
}
2.5 使用示例
- 编写回调接口
public class LogWriteBackImpl implements LogWriteBack<Map<String,Object>>{
@Override
public LogWriteBackDto getReturnStatusInfo(Map<String,Object> map) {
return LogWriteBackDto.builder().status(ResultStatus.SUCCESS.name()).build();
}
}
- 发送数据接口记录日志
@ApiLog(serviceName = "测试Api日志Aop",aClass = LogWriteBackImpl.class,billType = "测试",targetSys = "测试")
public Map<String,Object> testApiLog(@RequestBody Map<String,Object> param){
// 进行发送数据返回结果
return param;
}