AOP写日志
1.表SQL
DROP TABLE IF EXISTS `sys_oper_log`;
CREATE TABLE `sys_oper_log` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志主键',
`title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '模块标题',
`business_type` tinyint NULL DEFAULT 0 COMMENT '业务类型(0=其它,1=新增,2=修改,3=删除)',
`method` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '方法名称',
`request_method` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '请求方式',
`operator_type` tinyint NULL DEFAULT 1 COMMENT '操作类别(0=其它,1=后台用户,2=手机端用户)',
`oper_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '操作人员',
`dept_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '部门名称',
`oper_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '请求URL',
`oper_ip` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '主机地址',
`oper_location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '操作地点',
`oper_param` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '请求参数',
`json_result` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '返回参数',
`status` tinyint NULL DEFAULT 0 COMMENT '操作状态(0=正常,1=异常)',
`error_msg` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '错误消息',
`oper_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
`cost_time` bigint NULL DEFAULT 0 COMMENT '消耗时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_business_type`(`business_type` ASC) USING BTREE,
INDEX `idx_status`(`status` ASC) USING BTREE,
INDEX `idx_oper_time`(`oper_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 27 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '操作日志记录' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
2.定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface OperLogAnnotation {
String title() default ""; // 模块标题
String businessType() default "0"; // 业务类型(0=其他,1=新增,2=修改,3=删除)
}
3.地图工具类
主要是拿到省市信息用的
public class GeoUtils {
// ip->地址信息
public static IpLocationResponse IpToAddressDTO(String key,String ip){
String url =String.format("https://restapi.amap.com/v3/ip?key=%s&ip=%s",key,ip);
String json = HutoolHttpUtil.sendGet(url, new HashMap<>());
return JSONUtil.toBean(json, IpLocationResponse.class);
}
}
返回实体
@Data
public class IpLocationResponse {
private String status;
private String info;
private String infocode;
private String province;
private String city;
private String adcode;
private String rectangle;
}
{
* "status": "1",
* "info": "OK",
* "infocode": "10000",
* "province": "江苏省",
* "city": "无锡市",
* "adcode": "320200",
* "rectangle": "120.1788533,31.4648817;120.4605818,31.68307651"
* }
4.进行AOP切面
@Aspect
@Component
@Slf4j
public class OperLogAspect {
@Autowired
private OperLogMapper operLogMapper;
@Autowired
private HttpServletRequest request;
@Value("${GaoDe.key:linxi}")
private String key;
@Value("${GaoDe.open:false}")
private boolean open;
@Around("@annotation(top.remained.site.common.annotation.OperLogAnnotation)")
public Object logOperation(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
OperLog operLog = new OperLog();
// 获取方法上的注解信息
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
OperLogAnnotation annotation = signature.getMethod().getAnnotation(OperLogAnnotation.class);
if (annotation != null) {
operLog.setTitle(annotation.title());
operLog.setBusinessType(Integer.parseInt(annotation.businessType()));
}
// 设置操作信息
operLog.setOperName(getUsernameFromSecurity());
operLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName());
operLog.setRequestMethod(request.getMethod());
operLog.setOperUrl(request.getRequestURI());
operLog.setOperIp(request.getRemoteAddr());
if (open) {
IpLocationResponse ipLocationResponse = GeoUtils.IpToAddressDTO(key, request.getRemoteAddr());
operLog.setOperLocation(ipLocationResponse.getProvince()+ipLocationResponse.getCity());
}
operLog.setOperTime(LocalDateTime.now());
// 设置操作类别(后台/移动端用户)
String userAgent = request.getHeader("User-Agent");
operLog.setOperatorType(getOperatorTypeFromUserAgent(userAgent));
// 设置请求参数
Object[] args = joinPoint.getArgs();
operLog.setOperParam(args != null ? args.toString() : null);
Object result;
try {
result = joinPoint.proceed(); // 执行目标方法
operLog.setStatus(0); // 操作成功
operLog.setJsonResult(result != null ? result.toString() : null);
} catch (Exception e) {
operLog.setStatus(1); // 操作失败
operLog.setErrorMsg(e.getMessage());
throw e;
} finally {
long endTime = System.currentTimeMillis();
operLog.setCostTime(endTime - startTime);
// 保存日志
operLogMapper.insert(operLog);
}
return result;
}
/**
* 从 Spring Security 中获取用户名
*/
private String getUsernameFromSecurity() {
try {
return SecurityUtils.getUsername();
} catch (Exception e) {
log.warn("无法从 SecurityContext 中获取用户名");
return "Unknown";
}
}
private int getOperatorTypeFromUserAgent(String userAgent) {
if (userAgent == null) {
return 0; // 未知
}
userAgent = userAgent.toLowerCase();
if (userAgent.contains("mobile") || userAgent.contains("iphone") || userAgent.contains("android")) {
return 2; // 移动端用户
}
return 1; // 后台用户(浏览器端)
}
}
5.使用
@PostMapping("/login")
@ApiOperation("登录")
@OperLogAnnotation(title = "登录")
public Result<TokenVo> login(@Validated @RequestBody LoginDto loginDto) {
return Result.ok(loginService.login(loginDto.getUsername(),loginDto.getPassword()));
}
标签:COMMENT,String,utf8mb4,DEFAULT,operLog,AOP,日志,NULL
From: https://blog.csdn.net/qq_46058550/article/details/144718602