1. 需要引用的依赖
<!-- aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 创建实体类
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value="SysLog对象", description="日志记录表")
public class SysLog implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "主键id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "用户名")
private String userName;
@ApiModelProperty(value = "删除,修改")
private String operation;
@ApiModelProperty(value = "操作方法")
private String method;
@ApiModelProperty(value = "操作人ip地址")
private String ip;
@ApiModelProperty(value = "操作时间")
private Date operateTime;
}
3. 使用spring 的 aop 技术切到自定义注解上,所以先创建一个自定义注解类
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface MyLog {
String value() default "";
}
4. 创建aop切面实现类
package com.evaluation.tcvl.aop;
import com.evaluation.tcvl.entity.SysLog;
import com.evaluation.tcvl.jwt.JwtTokenUtil;
import com.evaluation.tcvl.mapper.UserLoginMapper;
import com.evaluation.tcvl.service.SysLogService;
import com.evaluation.tcvl.util.HttpContextUtil;
import com.evaluation.tcvl.util.IPUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
@Aspect
@Component
public class SysLogAspect {
@Autowired
private SysLogService sysLogService;
@Autowired
private UserLoginMapper userLoginMapper;
//定义切点 @Pointcut
//在注解的位置切入代码
@Pointcut("@annotation(com.evaluation.tcvl.aop.MyLog)")
public void logPoinCut() {
}
//切面 配置通知
@AfterReturning("logPoinCut()")
public void saveSysLog(JoinPoint joinPoint) {
//保存日志
SysLog sysLog = new SysLog();
//从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
//获取操作
MyLog myLog = method.getAnnotation(MyLog.class);
if (myLog != null) {
String value = myLog.value();
sysLog.setOperation(value);//保存获取的操作
}
//获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
//获取请求的方法名
String methodName = method.getName();
sysLog.setMethod(className + "." + methodName);
sysLog.setOperateTime(new Date());
//获取用户ip地址
HttpServletRequest request = HttpContextUtil.getHttpServletRequest();
sysLog.setIp(IPUtils.getIPAddress(request));
//获取用户名
String token = request.getHeader("Access-Token");
Integer id = JwtTokenUtil.getUserIdFromToken(token);
String userName = userLoginMapper.selectById(id).getUserName();
sysLog.setUserName(userName);
//调用service保存SysLog实体类到数据库
sysLogService.save(sysLog);
}
}
package com.evaluation.tcvl.util;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
public class HttpContextUtil {
private HttpContextUtil(){
}
//获取HttpServletRequest请求
public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
}
}
package com.evaluation.tcvl.util;
import javax.servlet.http.HttpServletRequest;
public class IPUtils {
public static String getIPAddress(HttpServletRequest request) {
String ip = null;
//X-Forwarded-For:Squid 服务代理
String ipAddresses = request.getHeader("X-Forwarded-For");
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//Proxy-Client-IP:apache 服务代理
ipAddresses = request.getHeader("Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//WL-Proxy-Client-IP:weblogic 服务代理
ipAddresses = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//HTTP_CLIENT_IP:有些代理服务器
ipAddresses = request.getHeader("HTTP_CLIENT_IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//X-Real-IP:nginx服务代理
ipAddresses = request.getHeader("X-Real-IP");
}
//有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
if (ipAddresses != null && ipAddresses.length() != 0) {
ip = ipAddresses.split(",")[0];
}
//还是不能获取到,最后再通过request.getRemoteAddr();获取
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
5. 接下来就可以在需要监控的方法上添加 aop的自定义注解.
格式为 @+自定义注解的类名 @MyLog
@MyLog(value = "更新学期信息记录")
@PutMapping("/update")
@ApiOperation(value = "更新学期信息", notes = "传入学期实体对象")
public Re update(@RequestBody Semester semester){
try{
semesterService.updateById(semester);
}catch (Exception e){
return Re.error().message("更新失败");
}
return Re.ok().message("更新成功");
}