目录
1、引入依赖
2、切面方法
3、Log类
4、LogAspect类
5、SysLog实体类
6、服务类和服务实现类
7、实际调用
1、引入依赖
org.aspectj aspectjweaverorg.springframework.boot spring-boot-starter-aoptest org.projectlombok lombok
2、切面方法
切面方法说明如下:
| @Aspect | 作用是把当前类标识为一个切面供容器读取 |
| @Pointcut | (切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式 |
| @Before | 标识一个前置增强方法,相当于BeforeAdvice的功能 |
| @AfterReturning | 后置增强,相当于AfterReturningAdvice,方法退出时执行 |
| @AfterThrowing | 异常抛出增强,相当于ThrowsAdvice |
| @After | final增强,不管是抛出异常或者正常退出都会执行 |
| @Around | 环绕增强,相当于MethodInterceptor |
3、Log类
package com.shucha.deveiface.biz.aspect;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
String menu() default "";
String operation() default "";
boolean isData() default true;
}
4、LogAspect类
package com.shucha.deveiface.biz.aspect;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.sdy.common.model.Response;
import com.sdy.mvc.controller.BaseController;
import com.sdy.mvc.utils.HttpUtil;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import feign.Request;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
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;
import java.lang.reflect.Parameter;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@Aspect
@Component
@Slf4j
@Order(1)
public class LogAspect {
@Autowired
private SysLogService sysLogService;
private final ThreadLocal startTime = new ThreadLocal<>();
// 配置织入点
@Pointcut("@annotation(Log)")
public void logPointCut() {
}
@Before("logPointCut()")
private void before() {
startTime.set( System.currentTimeMillis());
}
@AfterReturning(returning = "res", pointcut = "logPointCut()")
public void afterReturning(JoinPoint joinPoint, Response res) throws Exception {
long nowTime = System.currentTimeMillis();
HttpServletRequest request = getRequest();
handleLog(joinPoint, null, res, nowTime, request);
}
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e) throws Exception {
// 从上下文中获取reqeust
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
// HttpServletRequest request = getRequest();
HttpServletRequest request = servletRequestAttributes.getRequest();
handleLog(joinPoint, e, null, System.currentTimeMillis(), request);
}
protected void handleLog(final JoinPoint joinPoint, final Exception e, Response jsonResult, Long nowTime, HttpServletRequest request) throws Exception {
Log controllerLog = getAnnotationLog(joinPoint);
ProceedingJoinPoint point = (ProceedingJoinPoint)joinPoint;
if (controllerLog == null) {
return;
}
// 数据库日志
SysLog sysLog = new SysLog();
// 接口地址
String requestUrl = request.getRequestURL().toString();
// 请求的IP地址
String ip = HttpUtil.getIpAddr(request);
sysLog.setIp(ip);
// 获取操作内容
String content = controllerLog.menu();
// 获取请求参数
String requestData = "";
if(controllerLog.isData()){
requestData = getRequestParams(point, request);
}
if (jsonResult == null) {
content = content + "--出现服务异常!";
}
if (jsonResult != null && !jsonResult.getSuccess()) {
content = content + "--执行失败!";
}
sysLog.setContent(content)
.setType(content)
.setCreateTime(new Date())
.setRequestUrl(requestUrl)
.setRequestData(requestData);
// 保存数据库
sysLogService.save(sysLog);
}
private Log getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(Log.class);
}
return null;
}
private HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return attributes.getRequest();
}
private String getParameterName(HttpServletRequest request){
// 增加查询日志 获取所有查询的参数名称和值 json格式存储
Map map = new HashMap();
Enumeration paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
String[] paramValues = request.getParameterValues(paramName);
if (paramValues.length == 1) {
String paramValue = paramValues[0];
if (paramValue.length() != 0) {
map.put(paramName, paramValue);
}
}
}
return JSON.toJSONString(map);
}
public String getRequestParams(ProceedingJoinPoint point, HttpServletRequest request) {
MethodSignature methodSignature = (MethodSignature)point.getSignature();
Method method = methodSignature.getMethod();
String queryString = null;
String requestMethod = request.getMethod();
if (requestMethod.equals(Request.HttpMethod.POST.name())) {
//参数值
Object[] args = ArrayUtils.toArray(point.getArgs());
queryString = JSON.toJSONString(args[0], SerializerFeature.WriteMapNullValue);
}
else {
//参数名
Parameter[] parameters = method.getParameters();
//参数值
Object[] args = ArrayUtils.toArray(point.getArgs());
Map map = new HashMap<>();
for (int i = 0; i < parameters.length; i++) {
map.put(parameters[i].getName(), args[i]);
}
queryString = JSON.toJSONString(map);
}
return queryString;
}
}
5、SysLog实体类
package com.shucha.deveiface.biz.model;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sdy.common.model.BaseModel;
import com.sdy.common.utils.DateUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class SysLog extends BaseModel {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "主键")
@TableId
private Long id;
@ApiModelProperty(value = "操作用户id")
private Long userId;
@ApiModelProperty(value = "请求参数")
private String requestData;
@ApiModelProperty(value = "请求接口地址")
private String requestUrl;
@ApiModelProperty(value = "IP地址")
private String ip;
@ApiModelProperty(value = "操作内容")
private String content;
@ApiModelProperty(value = "操作类型")
private String type;
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = DateUtil.DATETIME_FORMAT)
private Date createTime;
}
package com.shucha.deveiface.biz.aspect;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.sdy.common.model.Response;
import com.sdy.mvc.controller.BaseController;
import com.sdy.mvc.utils.HttpUtil;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import feign.Request;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
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;
import java.lang.reflect.Parameter;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@Aspect
@Component
@Slf4j
@Order(1)
public class LogAspect {
@Autowired
private SysLogService sysLogService;
private final ThreadLocal startTime = new ThreadLocal<>();
// 配置织入点
@Pointcut("@annotation(Log)")
public void logPointCut() {
}
@Before("logPointCut()")
private void before() {
startTime.set( System.currentTimeMillis());
}
@AfterReturning(returning = "res", pointcut = "logPointCut()")
public void afterReturning(JoinPoint joinPoint, Response res) throws Exception {
long nowTime = System.currentTimeMillis();
HttpServletRequest request = getRequest();
handleLog(joinPoint, null, res, nowTime, request);
}
@AfterThrowing(value = "logPointCut()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Exception e) throws Exception {
// 从上下文中获取reqeust
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
// HttpServletRequest request = getRequest();
HttpServletRequest request = servletRequestAttributes.getRequest();
handleLog(joinPoint, e, null, System.currentTimeMillis(), request);
}
protected void handleLog(final JoinPoint joinPoint, final Exception e, Response jsonResult, Long nowTime, HttpServletRequest request) throws Exception {
Log controllerLog = getAnnotationLog(joinPoint);
ProceedingJoinPoint point = (ProceedingJoinPoint)joinPoint;
if (controllerLog == null) {
return;
}
// 数据库日志
SysLog sysLog = new SysLog();
// 接口地址
String requestUrl = request.getRequestURL().toString();
// 请求的IP地址
String ip = HttpUtil.getIpAddr(request);
sysLog.setIp(ip);
// 获取操作内容
String content = controllerLog.menu();
// 获取请求参数
String requestData = "";
if(controllerLog.isData()){
requestData = getRequestParams(point, request);
}
if (jsonResult == null) {
content = content + "--出现服务异常!";
}
if (jsonResult != null && !jsonResult.getSuccess()) {
content = content + "--执行失败!";
}
sysLog.setContent(content)
.setType(content)
.setCreateTime(new Date())
.setRequestUrl(requestUrl)
.setRequestData(requestData);
// 保存数据库
sysLogService.save(sysLog);
}
private Log getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(Log.class);
}
return null;
}
private HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return attributes.getRequest();
}
private String getParameterName(HttpServletRequest request){
// 增加查询日志 获取所有查询的参数名称和值 json格式存储
Map map = new HashMap();
Enumeration paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
String[] paramValues = request.getParameterValues(paramName);
if (paramValues.length == 1) {
String paramValue = paramValues[0];
if (paramValue.length() != 0) {
map.put(paramName, paramValue);
}
}
}
return JSON.toJSONString(map);
}
public String getRequestParams(ProceedingJoinPoint point, HttpServletRequest request) {
MethodSignature methodSignature = (MethodSignature)point.getSignature();
Method method = methodSignature.getMethod();
String queryString = null;
String requestMethod = request.getMethod();
if (requestMethod.equals(Request.HttpMethod.POST.name())) {
//参数值
Object[] args = ArrayUtils.toArray(point.getArgs());
queryString = JSON.toJSONString(args[0], SerializerFeature.WriteMapNullValue);
}
else {
//参数名
Parameter[] parameters = method.getParameters();
//参数值
Object[] args = ArrayUtils.toArray(point.getArgs());
Map map = new HashMap<>();
for (int i = 0; i < parameters.length; i++) {
map.put(parameters[i].getName(), args[i]);
}
queryString = JSON.toJSONString(map);
}
return queryString;
}
}
5、SysLog实体类
package com.shucha.deveiface.biz.model;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sdy.common.model.BaseModel;
import com.sdy.common.utils.DateUtil;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class SysLog extends BaseModel {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "主键")
@TableId
private Long id;
@ApiModelProperty(value = "操作用户id")
private Long userId;
@ApiModelProperty(value = "请求参数")
private String requestData;
@ApiModelProperty(value = "请求接口地址")
private String requestUrl;
@ApiModelProperty(value = "IP地址")
private String ip;
@ApiModelProperty(value = "操作内容")
private String content;
@ApiModelProperty(value = "操作类型")
private String type;
@ApiModelProperty(value = "创建时间")
@JsonFormat(pattern = DateUtil.DATETIME_FORMAT)
private Date createTime;
}
创建表和插入数据
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_log
-- ----------------------------
DROP TABLE IF EXISTS `sys_log`;
CREATE TABLE `sys_log` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` int(11) NULL DEFAULT NULL COMMENT '操作用户id',
`ip` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT 'IP地址',
`content` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '操作内容',
`request_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '请求接口地址',
`request_data` longtext CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL COMMENT '请求参数',
`type` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '操作类型rn0:登陆rn1:新增用户rn2:开户rn3:用户基本信息编辑rn4:用户资源编辑rn5:新增角色rn6编辑角色rn7:角色权限编辑rn8:角色关联用户编辑rn9:新增菜单rn10:菜单编辑rn11:日志查询',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_user_id`(`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '操作日志信息' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_log
-- ----------------------------
INSERT INTO `sys_log` VALUES (1, NULL, '192.168.0.111', '查询数据', 'http://192.168.0.111:50041/test/getData', '{}', '查询数据', '2022-08-08 17:21:51');
INSERT INTO `sys_log` VALUES (2, NULL, '192.168.0.111', '新增数据发发发', NULL, NULL, NULL, NULL);
INSERT INTO `sys_log` VALUES (3, NULL, '192.168.0.111', '新增数据', 'http://192.168.0.111:50041/test/saveData', '{"content":"新增数据发发发","createTime":null,"id":2,"ip":"192.168.0.111","requestData":null,"requestUrl":null,"type":null,"userId":null}', '新增数据', '2022-08-08 17:22:12');
SET FOREIGN_KEY_CHECKS = 1;
6、服务类和服务实现类
package com.shucha.deveiface.biz.service;
import com.sdy.mvc.service.BaseService;
import com.shucha.deveiface.biz.model.SysLog;
public interface SysLogService extends BaseService {
}
package com.shucha.deveiface.biz.service.impl;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import com.shucha.deveiface.biz.mapper.SysLogMapper;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class SysLogServiceImpl extends BaseServiceImpl implements SysLogService {
@Autowired
private SysLogMapper sysLogMapper;
}
7、实际调用
package com.shucha.deveiface.web.controller;
import com.sdy.common.model.Response;
import com.shucha.deveiface.biz.aspect.Log;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private SysLogService logService;
@Log(menu = "查询数据")
@GetMapping("/getData")
public Response test(){
return Response.success("请求成功");
}
@Log(menu = "新增数据")
@PostMapping("/saveData")
public Response saveData(@RequestBody SysLog sysLog){
logService.save(sysLog);
return Response.success();
}
}
package com.shucha.deveiface.web.controller;
import com.sdy.common.model.Response;
import com.shucha.deveiface.biz.aspect.Log;
import com.shucha.deveiface.biz.model.SysLog;
import com.shucha.deveiface.biz.service.SysLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private SysLogService logService;
@Log(menu = "查询数据")
@GetMapping("/getData")
public Response test(){
return Response.success("请求成功");
}
@Log(menu = "新增数据")
@PostMapping("/saveData")
public Response saveData(@RequestBody SysLog sysLog){
logService.save(sysLog);
return Response.success();
}
}


