1、实现前准备,MySQL数据库中创建表

CREATE TABLE `sys_log` (

`oper_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',

`title` varchar(50) DEFAULT '' COMMENT '模块标题',

`business_type` int(11) DEFAULT '0' COMMENT '业务类型(0其它 1新增 2修改 3删除)',

`method` varchar(100) DEFAULT '' COMMENT '方法名称',

`request_method` varchar(10) DEFAULT '' COMMENT '请求方式',

`operator_type` int(11) DEFAULT '0' COMMENT '操作类别( 0、用户端 1、平台管理端)',

`oper_name` varchar(50) DEFAULT '' COMMENT '操作人员',

`oper_url` varchar(255) DEFAULT '' COMMENT '请求URL',

`oper_ip` varchar(128) DEFAULT '' COMMENT '主机地址',

`oper_location` varchar(255) DEFAULT '' COMMENT '操作地点',

`oper_param` varchar(2000) DEFAULT '' COMMENT '请求参数',

`json_result` varchar(2000) DEFAULT '' COMMENT '返回参数',

`status` int(11) DEFAULT '0' COMMENT '操作状态(1正常 0异常)',

`error_msg` varchar(2000) DEFAULT '' COMMENT '错误消息',

`oper_time` datetime DEFAULT NULL COMMENT '操作时间',

PRIMARY KEY (`oper_id`) USING BTREE

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='操作日志记录';

        2、依赖(aop依赖,至于其他依赖(Druid,MybatisPlus)自行处理)

org.springframework.boot

spring-boot-starter-aop

        3、自定义注解(具体如何自定义注解,请自行学习,这里不做详细说明)

import com.xiarg.genius.annotation.entry.BusinessTypeEnum;

import java.lang.annotation.*;

/**

*

* Log 注解配置

* @Author xiarg

* @CreateTime 2023/02/16 16:41

*/

@Target({ElementType.METHOD,ElementType.PARAMETER})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Log {

/**

* 日志标题

*/

public String title() default "";

/**

* 操作类型

*/

public BusinessTypeEnum businessType() default BusinessTypeEnum.OTHER;

}

        4、切面

import com.alibaba.fastjson2.JSON;

import com.xiarg.genius.annotation.annotation.Log;

import com.xiarg.genius.annotation.entry.SysLog;

import com.xiarg.genius.annotation.service.ISysLogService;

import lombok.Data;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.reflect.MethodSignature;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;

import org.springframework.validation.BindingResult;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;

import org.springframework.web.multipart.MultipartFile;

import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.time.LocalDateTime;

import java.util.Collection;

import java.util.Map;

/**

*

* Log 注解切面配置

* @Author xiarg

* @CreateTime 2023/02/16 16:46

*/

@Data

@Aspect

@Component

public class LogConfig {

private static final Logger log = LoggerFactory.getLogger(LogConfig.class);

/**

* 引入日志Service,用于存储数据进数据库

*/

private final ISysLogService sysLogService;

/**

* 配置切入点-xxx代表自定义注解的存放位置,如:com.xiarg.genius.annotation.annotation.Log

*/

@Pointcut("@annotation(com.xiarg.genius.annotation.annotation.Log)")

public void logPointCut() {}

/**

* 处理完请求后执行此处代码

*

* @param joinPoint 切点

*/

@AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")

public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult){

handleLog(joinPoint, controllerLog, null, jsonResult);

}

/**

* 如果处理请求时出现异常,在抛出异常后执行此处代码

*

* @param joinPoint 切点

* @param e 异常

*/

@AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")

public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e){

handleLog(joinPoint, controllerLog, e, null);

}

/**

* 日志处理

*/

protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult){

try {

MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

// 获取当前的用户

String userName = "genius";

// *========数据库日志=========*//

SysLog sysLog = new SysLog();

sysLog.setStatus(1);

// 请求的地址 ip和localtion是前端获取到传过来的

ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

assert requestAttributes != null;

HttpServletRequest request = requestAttributes.getRequest();

Map parameterMap = request.getParameterMap();

String ip = getIpAddr(request);

sysLog.setOperIp(ip);

sysLog.setOperLocation(request.getHeader("location"));

sysLog.setOperParam(JSON.toJSONString(parameterMap));

sysLog.setOperUrl(request.getRequestURI());

sysLog.setOperName(userName);

if (e != null) {

sysLog.setStatus(0);

int length = e.getMessage().length();

sysLog.setErrorMsg(e.getMessage().substring(0,length>2000?2000:length));

}

// 设置方法名称

String className = joinPoint.getTarget().getClass().getName();

String methodName = joinPoint.getSignature().getName();

sysLog.setMethod(className + "." + methodName + "()");

// 设置请求方式

sysLog.setRequestMethod(request.getMethod());

// 处理设置注解上的参数

getControllerMethodDescription(joinPoint, controllerLog, sysLog, jsonResult, request);

// 保存数据库

sysLog.setOperTime(LocalDateTime.now());

// 返回数据

sysLog.setJsonResult(jsonResult==null?"":jsonResult.toString());

// 将处理好的日至对象存储进数据库

sysLogService.save(sysLog);

} catch (Exception exp) {

// 记录本地异常日志

log.error("==前置通知异常==");

log.error("异常信息:{}", exp.getMessage());

exp.printStackTrace();

}

}

/**

* 获取操作ip地址

* @param request

* @return

*/

public static String getIpAddr(HttpServletRequest request) {

if (request == null) {

return "unknown";

}

String ip = request.getHeader("x-forwarded-for");

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("Proxy-Client-IP");

}

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("X-Forwarded-For");

}

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("WL-Proxy-Client-IP");

}

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

ip = request.getHeader("X-Real-IP");

}

if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {

ip = request.getRemoteAddr();

}

return ip;

}

/**

* 获取注解信息

* @param joinPoint

* @param log

* @param sysLog

* @param jsonResult

* @param request

* @throws Exception

*/

public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysLog sysLog, Object jsonResult, HttpServletRequest request) throws Exception {

// 设置action动作

sysLog.setBusinessType(log.businessType().ordinal());

sysLog.setTitle(log.title());

}

private void setRequestValue(JoinPoint joinPoint, SysLog sysLog, HttpServletRequest request) throws Exception {

String requestMethod = sysLog.getRequestMethod();

if (RequestMethod.PUT.name().equals(requestMethod) || RequestMethod.POST.name().equals(requestMethod)) {

String params = argsArrayToString(joinPoint.getArgs());

sysLog.setOperParam(params.substring(0,2000));

} else {

Map paramsMap = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);

sysLog.setOperParam(paramsMap.toString().substring(0,2000));

}

}

/**

* 解析方法参数信息

* @param paramsArray

* @return

*/

private String argsArrayToString(Object[] paramsArray) {

StringBuilder params = new StringBuilder();

if (paramsArray != null && paramsArray.length > 0) {

for (Object o : paramsArray) {

if (o != null && !isFilterObject(o)) {

try {

Object jsonObj = JSON.toJSON(o);

params.append(jsonObj.toString()).append(" ");

} catch (Exception e) {

log.error(e.getMessage());

}

}

}

}

return params.toString().trim();

}

@SuppressWarnings("rawtypes")

public boolean isFilterObject(final Object o) {

Class clazz = o.getClass();

if (clazz.isArray()) {

return clazz.getComponentType().isAssignableFrom(MultipartFile.class);

} else if (Collection.class.isAssignableFrom(clazz)) {

Collection collection = (Collection) o;

for (Object value : collection) {

return value instanceof MultipartFile;

}

} else if (Map.class.isAssignableFrom(clazz)) {

Map map = (Map) o;

for (Object value : map.entrySet()) {

Map.Entry entry = (Map.Entry) value;

return entry.getValue() instanceof MultipartFile;

}

}

return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse

|| o instanceof BindingResult;

}

}

        5、枚举和实体类

/**

* @Author xiarg

* @CreateTime 2023/02/16 16:45

*/

public enum BusinessTypeEnum {

/**

* 其它

*/

OTHER,

/**

* 新增

*/

INSERT,

/**

* 修改

*/

UPDATE,

/**

* 删除

*/

DELETE,

/**

* 授权

*/

GRANT,

}

import com.baomidou.mybatisplus.annotation.IdType;

import com.baomidou.mybatisplus.annotation.TableId;

import lombok.Data;

import java.time.LocalDateTime;

/**

* @Author xiarg

* @CreateTime 2023/02/16 16:40

*/

@Data

public class SysLog {

@TableId(value = "oper_id", type = IdType.AUTO)

private Long operId;

private String title;

private Integer businessType;

private String method;

private String requestMethod;

private String operName;

private String operUrl;

private String operIp;

private String operLocation;

private String operParam;

private String jsonResult;

private Integer status;

private String errorMsg;

private LocalDateTime operTime;

}

        6、具体的控制层应用

import com.xiarg.genius.annotation.annotation.Log;

import com.xiarg.genius.annotation.entry.BusinessTypeEnum;

import org.springframework.web.bind.annotation.*;

/**

* @Author xiarg

* @CreateTime 2023/02/16 17:16

*/

@RestController

@RequestMapping("test")

public class TestController {

@Log(title = "查询列表",businessType = BusinessTypeEnum.OTHER)

@GetMapping()

public String list(@RequestParam("id") String id) {

return "返回数据列表";

}

@Log(title = "添加数据",businessType = BusinessTypeEnum.INSERT)

@PostMapping

public String save() {

try {

System.out.println(1/0);

} catch (Exception e) {

throw e;

}

return "数据添加成功";

}

@Log(title = "修改数据",businessType = BusinessTypeEnum.UPDATE)

@PutMapping

public String update() {

return "修改数据成功";

}

@Log(title = "删除数据",businessType = BusinessTypeEnum.DELETE)

@DeleteMapping

public String delete() {

return "删除数据成功";

}

}

        7、综上即实现功能,但是注意:ip和localtion是前端获取到传过来的,要不然无法获取到。

参考文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: