Commit defdfe32 by 陈皓

添加接口日志

parent 87efa3b4
package com.zq.im.annotation.rest;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* <p>
* 用户操作日志处理切面
* </p>
*
* @author chenhao
* @since 2022/10/15 17:23
*/
@Order(1)
@Aspect
@Component
public class ApiLogAspect {
// private static final Logger LOGGER = LoggerFactory.getLogger(com.zq.im.annotation.ApiLog.class);
// private final LogServiceImpl logService;
//
// @Autowired
// public ApiLogAspect(LogServiceImpl logService) {
// this.logService = logService;
// }
//
// /**
// * 声明切入点
// */
// @Pointcut("@annotation(com.zq.im.annotation.ApiLog)")
// public void pointCut() {}
//
// /**
// * 环绕通知
// */
// @Around("pointCut()")
// public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
// // 记录接口调用时间
// long startTime = System.currentTimeMillis();
// Object result = joinPoint.proceed();
// long endTime = System.currentTimeMillis();
// // 获取方法
// Signature signature = joinPoint.getSignature();
// MethodSignature methodSignature = (MethodSignature) signature;
// Method method = methodSignature.getMethod();
// // 获取Log注解的信息,查看是否需要保存操作记录
// boolean isSave = false;
// String value = "";
// if (method.isAnnotationPresent(com.yww.admin.annotation.Log.class)) {
// com.yww.admin.annotation.Log annotation = method.getAnnotation(com.yww.admin.annotation.Log.class);
// isSave = annotation.save();
// value = annotation.value();
// }
// // 打印注解上的消息
// if (StrUtil.isNotBlank(value)) {
// LOGGER.info(value);
// }
// // 若是选择保存到数据库,则获取信息后保存
// if (!isSave) {
// return result;
// }
// // 获取当前请求对象
// ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// if (attributes == null) {
// return result;
// }
// HttpServletRequest request = attributes.getRequest();
// //记录请求信息
// Log.LogBuilder builder = Log.builder();
// // 记录Operation的注解信息
// if (method.isAnnotationPresent(Operation.class)) {
// Operation operation = method.getAnnotation(Operation.class);
// builder.summary(operation.summary()).description(operation.description());
// }
// String urlStr = request.getRequestURL().toString();
// builder.basePath(StrUtil.removeSuffix(urlStr, URLUtil.url(urlStr).getPath()))
// .uri(request.getRequestURI())
// .url(request.getRequestURL().toString())
// .browser(IpUtil.getBrowser(request).getBrowser().getName())
// .ip(IpUtil.getLongIpAddr(request))
// .method(request.getMethod())
// .parameter(JSONUtil.parse(getParameter(method, joinPoint.getArgs())).toString())
// .result(JSONUtil.parse(result).toString())
// .spendTime((int) (endTime - startTime))
// .startTime(LocalDateTimeUtil.of(startTime));
// Log log = builder.build();
// LOGGER.info(log.toString());
// logService.save(log);
// return result;
// }
//
// /**
// * 根据方法和传入的参数获取请求参数
// *
// * @param method 方法
// * @param args 传入参数
// * @return 请求参数
// */
// private Object getParameter(Method method, Object[] args) {
// List<Object> argsList = new ArrayList<>();
// Parameter[] parameters = method.getParameters();
// for (int i = 0; i < parameters.length; i++) {
// // 将RequestBody注解修饰的参数作为请求参数
// RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
// if (requestBody != null) {
// argsList.add(args[i]);
// }
// // 将RequestParam注解修饰的参数作为请求参数
// RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
// if (requestParam != null) {
// Map<String, Object> map = new HashMap<>(16);
// String key = parameters[i].getName();
// if (StrUtil.isNotBlank(requestParam.value())) {
// key = requestParam.value();
// }
// map.put(key, args[i]);
// argsList.add(map);
// }
// }
// if (argsList.size() == 0) {
// return null;
// } else if (argsList.size() == 1) {
// return argsList.get(0);
// } else {
// return argsList;
// }
// }
}
package com.zq.im.aspect;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zq.im.exception.BusinessException;
import com.zq.im.modules.api.form.ApiForm;
import com.zq.im.modules.system.dao.ApiUserInfoDao;
import com.zq.im.modules.system.dao.OpenApiLogDao;
import com.zq.im.modules.system.entity.ApiUserInfo;
import com.zq.im.modules.system.entity.OpenApiLog;
import com.zq.im.utils.IpUtil;
import com.zq.im.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
* <p>
* 用户操作日志处理切面
* </p>
*
* @author chenhao
* @since 2022/10/15 17:23
*/
@Order(1)
@Aspect
@Slf4j
@Component
public class ApiLogAspect {
private final OpenApiLogDao openApiLogDao;
private final ApiUserInfoDao apiUserInfoDao;
@Autowired
public ApiLogAspect(OpenApiLogDao openApiLogDao, ApiUserInfoDao apiUserInfoDao) {
this.openApiLogDao = openApiLogDao;
this.apiUserInfoDao = apiUserInfoDao;
}
ThreadLocal<Long> currentTime = new ThreadLocal<>();
/**
* 声明切入点
*/
@Pointcut("@annotation(com.zq.im.aspect.OpenApi)")
public void pointCut() {}
/**
* 环绕通知
*/
@Around("pointCut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
currentTime.set(System.currentTimeMillis());
// 执行目标方法
Object result = joinPoint.proceed();
// 计算执行耗时
long time = System.currentTimeMillis() - currentTime.get();
currentTime.remove();
// 获取方法名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method signatureMethod = signature.getMethod();
// 获取注解信息
OpenApi openApi = AnnotationUtils.getAnnotation(signatureMethod, OpenApi.class);
// 获取当前请求对象
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = null;
if (attributes != null) {
request = attributes.getRequest();
}
// 保存日志
insertLog(openApi, request, "INFO", "", time);
return result;
}
/**
* 配置异常通知
*
* @param joinPoint join point for advice
* @param e exception
*/
@AfterThrowing(pointcut = "pointCut()", throwing = "e")
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
// 计算执行耗时
long time = System.currentTimeMillis() - currentTime.get();
currentTime.remove();
String errMsg = "";
if (e instanceof BusinessException) {
errMsg = e.getMessage();
}
// 获取方法名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method signatureMethod = signature.getMethod();
// 获取注解信息
OpenApi openApi = AnnotationUtils.getAnnotation(signatureMethod, OpenApi.class);
// 获取当前请求对象
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = null;
if (attributes != null) {
request = attributes.getRequest();
}
// 保存日志
insertLog(openApi, request, "ERROR", errMsg, time);
}
@Async
public void insertLog(OpenApi openApi, HttpServletRequest request, String logType, String errMsg, long timeCost) {
try {
// 获取IP信息
String clientIp = IpUtil.getIpAddr(request);
// 获取请求对象
ApiForm apiForm = ServletUtil.toBean(request, ApiForm.class, true);
OpenApiLog openApiLog = new OpenApiLog();
openApiLog.setLogType(logType);
DecodedJWT decodedJWT = TokenUtil.getUserContext();
if (decodedJWT != null) {
openApiLog.setAppId(TokenUtil.getAppid(decodedJWT));
openApiLog.setApplyer(TokenUtil.getApplyer(decodedJWT));
} else {
ApiUserInfo apiUserInfo = apiUserInfoDao.selectOne(
Wrappers.lambdaQuery(ApiUserInfo.builder().appId(apiForm.getAppId()).build())
);
if (apiUserInfo == null) {
openApiLog.setLogType("ERROR");
} else {
openApiLog.setAppId(apiUserInfo.getAppId());
openApiLog.setApplyer(apiUserInfo.getApplyer());
}
}
openApiLog.setVersion(getVersion(request));
openApiLog.setMethod(apiForm.getMethod());
openApiLog.setClientIp(clientIp);
openApiLog.setDescription(openApi == null ? "" : openApi.value());
openApiLog.setServerIp(NetUtil.getLocalhostStr());
openApiLog.setErrMsg(errMsg);
openApiLog.setTimeCost(timeCost);
openApiLog.setCreateTime(DateUtil.now());
// 保存日志
openApiLogDao.insert(openApiLog);
} catch (Exception e) {
log.error("记录日志发生错误", e);
}
}
/**
* 获取版本号
*/
public String getVersion(HttpServletRequest request) {
String requestUri = request.getRequestURI();
if (StrUtil.isBlank(requestUri)) {
log.warn("为获取到版本号,URI [{}]", request);
return "";
}
return requestUri.replace("/api/", "").replace("/action", "");
}
}
package com.zq.im.annotation; package com.zq.im.aspect;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
...@@ -14,10 +14,8 @@ import java.lang.annotation.Target; ...@@ -14,10 +14,8 @@ import java.lang.annotation.Target;
*/ */
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface ApiLog { public @interface OpenApi {
String value() default ""; String value() default "";
boolean save() default false;
} }
\ No newline at end of file
package com.zq.im.config.mybatis;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* <p>
* Mybatis-plus的自动填充处理处理
* 注意是对象属性名不是表的字段名
* </p>
*
* @author chenhao
* @since 2022/10/12 20:57
*/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入数据时填充创建和修改时间
*/
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
/**
* 修改数据时更新修改时间
*/
@Override
public void updateFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
package com.zq.im.modules.api.service.impl; package com.zq.im.modules.api.service.impl;
import com.zq.im.aspect.OpenApi;
import com.zq.im.modules.api.form.ApiForm; import com.zq.im.modules.api.form.ApiForm;
import com.zq.im.modules.api.form.ApiResp; import com.zq.im.modules.api.form.ApiResp;
import com.zq.im.modules.api.service.IApiLogic; import com.zq.im.modules.api.service.IApiLogic;
...@@ -28,6 +29,7 @@ public class ApiV1Logic extends BaseApiLogic implements IApiLogic { ...@@ -28,6 +29,7 @@ public class ApiV1Logic extends BaseApiLogic implements IApiLogic {
private ImgProcService imgProcService; private ImgProcService imgProcService;
@Override @Override
@OpenApi("获取Token")
public ApiResp getApiToken(ApiForm form) { public ApiResp getApiToken(ApiForm form) {
String appId = form.getString("appId"); String appId = form.getString("appId");
String appSecret = form.getString("appSecret"); String appSecret = form.getString("appSecret");
...@@ -38,6 +40,7 @@ public class ApiV1Logic extends BaseApiLogic implements IApiLogic { ...@@ -38,6 +40,7 @@ public class ApiV1Logic extends BaseApiLogic implements IApiLogic {
} }
@Override @Override
@OpenApi("检测图片信息")
public ApiResp detection(ApiForm form) { public ApiResp detection(ApiForm form) {
ImageReq req = form.toBean(ImageReq.class); ImageReq req = form.toBean(ImageReq.class);
AssertUtils.hasText(req.getFileContent(), "缺少文件内容"); AssertUtils.hasText(req.getFileContent(), "缺少文件内容");
......
...@@ -18,9 +18,8 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -18,9 +18,8 @@ import org.springframework.web.bind.annotation.RestController;
* 图片处理相关接口 * 图片处理相关接口
* </p> * </p>
* *
* @ClassName ImgApi * @author chenhao
* @Author chenhao * @since 2022/10/27 17:55
* @Date 2022/10/27 17:55
*/ */
@Slf4j @Slf4j
@RestController @RestController
...@@ -31,7 +30,6 @@ public class ImgProcController { ...@@ -31,7 +30,6 @@ public class ImgProcController {
private final ImgProcService service; private final ImgProcService service;
@ApiOperation("检测图片信息")
@PostMapping(value = "/detection") @PostMapping(value = "/detection")
public ResultVo detection(@RequestBody ImageReq req) { public ResultVo detection(@RequestBody ImageReq req) {
AssertUtils.hasText(req.getFileContent(), "缺少文件内容"); AssertUtils.hasText(req.getFileContent(), "缺少文件内容");
......
package com.zq.im.modules.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zq.im.modules.system.entity.OpenApiLog;
import org.springframework.stereotype.Repository;
/**
* 开放接口日志Dao层
*
* @author chenhao
*/
@Repository
public interface OpenApiLogDao extends BaseMapper<OpenApiLog> {
}
package com.zq.im.modules.system.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
*
* 开放接口日志实体类
*
* @author chenhao
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "open_api_log")
public class OpenApiLog {
/**
* ID
*/
@TableId(type = IdType.AUTO)
@ApiModelProperty("ID")
private String id;
/**
* APPID
*/
private String appId;
/**
* 申请人名称
*/
private String applyer;
/**
* 调用方法
*/
private String method;
/**
* IP
*/
private String serverIp;
/**
* 版本号
*/
private String version;
/**
* 接口描述
*/
private String description;
/**
* 报错描述
*/
private String errMsg;
/**
* 日志级别
*/
private String logType;
/**
* IP
*/
private String clientIp;
/**
* 耗时-毫秒
*/
private Long timeCost;
/**
* 创建时间
*/
private String createTime;
}
...@@ -52,7 +52,7 @@ public class ApiUserInfoService { ...@@ -52,7 +52,7 @@ public class ApiUserInfoService {
AssertUtils.isTrue(apiAppInfo.getState() == 1, "账号未激活"); AssertUtils.isTrue(apiAppInfo.getState() == 1, "账号未激活");
String sessionKey = IdUtil.simpleUUID(); String sessionKey = IdUtil.simpleUUID();
String apiToken = TokenUtil.createToken(apiAppInfo.getAppId(), sessionKey); String apiToken = TokenUtil.createToken(apiAppInfo.getAppId(), sessionKey, apiAppInfo.getApplyer());
log.debug(">> [session-key]:{}", sessionKey); log.debug(">> [session-key]:{}", sessionKey);
redisUtil.setStr(TokenUtil.getApiTokenKey(apiAppInfo.getAppId()), apiToken, 120L); redisUtil.setStr(TokenUtil.getApiTokenKey(apiAppInfo.getAppId()), apiToken, 120L);
......
...@@ -27,21 +27,14 @@ import java.util.Map; ...@@ -27,21 +27,14 @@ import java.util.Map;
* 3. signature, 签名,防止Token被篡改 * 3. signature, 签名,防止Token被篡改
* </p> * </p>
* *
* @ClassName TokenUtil * @author chenhao
* @Author yww * @since 2022/10/15 14:31
* @Date 2022/10/15 14:31
*/ */
public class TokenUtil { public class TokenUtil {
/** public static final String APPID = "appId";
* 用户名
*/
public static final String USER_NAME = "userName";
/**
* sessionKey
*/
public static final String SESSIONKEY = "sessionKey"; public static final String SESSIONKEY = "sessionKey";
public static final String APPLYER = "applyer";
/** /**
* 过期时长 * 过期时长
...@@ -59,7 +52,7 @@ public class TokenUtil { ...@@ -59,7 +52,7 @@ public class TokenUtil {
* *
* @return Token * @return Token
*/ */
public static String createToken(String username, String sessionKey) { public static String createToken(String appId, String sessionKey, String applyer) {
// 设置Token头部(不设置也会默认有这两个值) // 设置Token头部(不设置也会默认有这两个值)
Map<String, Object> header = new HashMap<String, Object>(2) { Map<String, Object> header = new HashMap<String, Object>(2) {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
...@@ -74,8 +67,9 @@ public class TokenUtil { ...@@ -74,8 +67,9 @@ public class TokenUtil {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
{ {
put(USER_NAME, username); put(APPID, appId);
put(SESSIONKEY, sessionKey); put(SESSIONKEY, sessionKey);
put(APPLYER, applyer);
} }
}; };
// 过期时间三小时 // 过期时间三小时
...@@ -109,25 +103,36 @@ public class TokenUtil { ...@@ -109,25 +103,36 @@ public class TokenUtil {
} }
/** /**
* 获取用户名 * 获取APPID
* *
* @param decoded 解析后的Token * @param decoded 解析后的Token
* @return 用户名 * @return appId
*/ */
public static String getUserName(DecodedJWT decoded) { public static String getAppid(DecodedJWT decoded) {
return decoded.getClaim(USER_NAME).asString(); return decoded.getClaim(APPID).asString();
} }
/** /**
* 获取用户名 * 获取SessionKey
* *
* @param decoded 解析后的Token * @param decoded 解析后的Token
* @return 用户名 * @return sessionKey
*/ */
public static String getSessionkey(DecodedJWT decoded) { public static String getSessionkey(DecodedJWT decoded) {
return decoded.getClaim(SESSIONKEY).asString(); return decoded.getClaim(SESSIONKEY).asString();
} }
/**
* 获取Applyer
*
* @param decoded 解析后的Token
* @return applyer
*/
public static String getApplyer(DecodedJWT decoded) {
return decoded.getClaim(APPLYER).asString();
}
public static String getApiTokenKey(String tokenKey) { public static String getApiTokenKey(String tokenKey) {
return TokenConstant.TOKEN_PREFIX + tokenKey; return TokenConstant.TOKEN_PREFIX + tokenKey;
} }
......
...@@ -204,10 +204,10 @@ public class V1Demo { ...@@ -204,10 +204,10 @@ public class V1Demo {
public static void main(String[] args) { public static void main(String[] args) {
// 这两个值可以存起来,不需每次都获取 // 这两个值可以存起来,不需每次都获取
// ApiInfo apiInfo = getApiInfo(); ApiInfo apiInfo = getApiInfo();
// String sessionKey = apiInfo.getKey(); String sessionKey = apiInfo.getKey();
// System.out.println(sessionKey); System.out.println(sessionKey);
String sessionKey = "9bd298e1e8c544358e592f736b37b0a3"; // String sessionKey = "860a013f4e7344bca5869b361a186648";
Map<String, Object> params = new HashMap<>(2); Map<String, Object> params = new HashMap<>(2);
params.put("filename", "6.png"); params.put("filename", "6.png");
params.put("fileContent", Base64.encode(FileUtil.file("C:\\Users\\11419\\Desktop\\Deskew\\TestImages\\6.png"))); params.put("fileContent", Base64.encode(FileUtil.file("C:\\Users\\11419\\Desktop\\Deskew\\TestImages\\6.png")));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment