一、简要说明
如今SpringBoot技术快速发展,采用注解开发更是现在开发的热潮。博主自己就结合自己在项目中关于日志功能的实现,采用AOP来拦截前端请求,获取我们所需的信息来实现日志功能。我会从搭建项目到能自己根据需求获得自己想要的数据,一步一步,让大家明白如何实现日志管理功能的。由于博主个人 能力有限,对 文章的描述就采用大白话,如果有描述不清楚的地方,希望各位大佬指正!
二、关于AOP的介绍
一谈到aop大家可能就会想到Spring,因为Spring具有两大特征IOC与AOP,而AOP又是里面的核心。一说AOP条件反射随口而出"切面编程",说定义大家都懂,但如何利用AOP我相信大多数人还是一头雾水。不过不用担心,我相信通过我接下来的介绍,会让大家重新有一个对AOP不一样的认识。
三、项目搭建
以下内容是关于如何创建一个SpringBoot的项目的步骤,会的小伙伴,自动跳过即可。
①:
②:③:四、准备工作
1、导入依赖
2、创建数据库表
关于mylog表中的字段根据自己的需求设定了,我就设置几个比较常用的,后面我会介绍还可以请求到 那些数据
四、后台代码的书写
这里博主先将基础的MVC架构的代码写出来,再写关于自定义注解的方法
1、pojo层
@Data
@TableName("mylog")
public class Mylog {
@TableId(type = IdType.AUTO)
private Integer operationId;
private String operationModel;
private String operationDescribe;
private String requestMethod;
private String requestParam;
private String operationUrl;
}
2、DAO层
@Mapper
public interface MylogDao extends BaseMapper
}
3、Service层
public interface MylogService {
int SaveLog(Mylog mylog);
}
@Service
public class MylogServiceImp implements MylogService {
@Resource
private MylogDao mylogDao;
@Override
public int SaveLog(Mylog mylog) {
return mylogDao.insert(mylog);
}
}
4、controller层
当我们写完所有代码时,在测试的时候,就是调用的controller层下的方法,看aop是否拦截我们所需的数据。
@Controller
public class MyLogController {
@Log(operationModel = "登录模块" , operationDescribe = "访问登录模块")
@GetMapping("/login/{name}/{age}")
@ResponseBody
public String Login(@PathVariable("name") String name, @PathVariable("age") Integer age){
return name+"今年"+age+"岁登录了系统";
}
}
5、自定义注解(重点)
从这里开始就是我们需要学习的重点部分了,首先我们像普通注解一样定义一个自己用于切面的注解,代码如下:
@Documented
@Target({ElementType.METHOD})//表示放在controller层的方法上
@Retention(RetentionPolicy.RUNTIME)//表示注解在那个阶段执行
public @interface Log {
//写在注解里面,可以用于存到数据库时的对方法的描述
String operationModel() default " ";//操作模块
String operationDescribe() default " ";//操作说明
}
6、定义切面(重点)
如果只有自定义的注解,没有定义切面和切点,AOP是没有起到拦截的作用,先呈上代码再做详细 解释。
@Component// 让SpringBoot来识别到
@Aspect//切面 定义了 通知与切点的关系
public class LogAspect {
private Mylog mylog;
@Resource
private MylogService mylogService;
@Pointcut("@annotation(com.ghs.test.annotation.Log)")//定义切点 表示注解加在哪里(添加全路径)
public void PointCut(){
}
@Before("PointCut()")
public void Before(JoinPoint joinPoint){
mylog = new Mylog();
ServletRequestAttributes requests = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requests.getRequest();
//通过HttpServletRequest对象request获取method、url;
mylog.setOperationUrl(request.getRequestURI());
mylog.setRequestMethod(request.getMethod());
mylog.setRequestParam(Arrays.toString(joinPoint.getArgs()));
//通过反射机制获得切入点处的方法
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
//获取在自定义的注解@Log()中的内容
Log annotation = method.getAnnotation(Log.class);
mylog.setOperationModel(annotation.operationModel());
mylog.setOperationDescribe(annotation.operationDescribe());
}
@Around("PointCut()")
public Object Around(ProceedingJoinPoint point) throws Throwable {
Object proceed = point.proceed();
mylogService.SaveLog(mylog);
System.out.println(mylog.toString());
return proceed;
}
}
上述代码中,除了有注释的地方,我会强调以下几个点:
①该代码理解
ServletRequestAttributes requests = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requests.getRequest();
如果你只是拿得到代码后就只是CV,那么对你个人能力的提升是大大打折扣的。现在让我来说明一下为什么可以拿到HttpServletRequest对象以及为什么要拿到它。
为什么可以拿到HttpServletRequest对象:
首先RequestContextHolder是Spring框架中的一个工具类,在该工具类中调用其静态方法法getRequestAttributes()获取当前线程中绑定的请求属性,然后将 RequestAttributes 对象转换为 ServletRequestAttributes 对象,最后,再通过servletRequestAttributes.getRequest()得到HttpServletRequest对象。
为什么要拿到HttpServletRequest对象呢:
HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息。
换句话说,当我们得到HttpServletRequest对象,我们可以从idea中看到有那些方法;
String getMethod();
String getPathInfo();
String getPathTranslated();
default PushBuilder newPushBuilder() {
return null;
}
String getContextPath();
String getQueryString();
String getRemoteUser();
boolean isUserInRole(String var1);
Principal getUserPrincipal();
String getRequestedSessionId();
String getRequestURI();
StringBuffer getRequestURL();
String getServletPath();
HttpSession getSession(boolean var1);
HttpSession getSession();
String changeSessionId();
boolean isRequestedSessionIdValid();
boolean isRequestedSessionIdFromCookie();
boolean isRequestedSessionIdFromURL();
以上等等方法都是HttpServletRequest自带的,我也是从中挑了几个比较常用的,所以我在前面说,你们可以根据自己的需求来设计需要的日志表哦。而且在我们真实的项目中需要获取session的时候,也可以通过该方法获得哦。
②该代码的理解
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Method method = signature.getMethod();
Log annotation = method.getAnnotation(Log.class);
Signature是 Java 反射 API 中的一个接口,在SpringAOP中可以通过 JoinPoint 对象获得连接点的相关信息,在该对象中通过getSignature() 方法获取到 Signature 对象,但因为我们的链接点是一个方法,可以将Signature 对象转换为 MethodSignature 对象,通过MethodSignature 对象可以获取到更加详细的方法签名信息。再通过反射获取自定义的注解,这样一来就可以得到我们自定义在@Log()里面的内容了。
③几个注解的理解
@Before("PointCut()")
表示在程序执行前执行。
@After("PointCut()")
表示在程序执行之后执行
@Around("PointCut()")
表示环绕整个程序执行
五、测试结果
我们访问MyLogController层下的"localhost:8080/login/567/18"接口,看是否能访问我们所需的信息。
效果展示
总上所述,我们成功将,需要拦截的方法描述、请求方法、请求参数、访问路径等信息在控制台输出并存到日志表中。
六、总结
通过上面的描述我们就可以实现一个基本的采用SpringAOP实现的日志管理功能了,上面的代码虽小,但还是五脏俱全了,就算应付一些比较复杂的要求,明白了原理多查查相关资料也是能搞定的。如果,这篇文章对正在阅读的小伙伴来说有一定帮助的话,小伙伴不要忘记点赞多多支持博主哦。如果需要将我们的日志管理写在项目中,就记得在留言区留言,如果需要的小伙伴比较多,我后期就写一个HTML页面的,关于日志管理的模块(包含一些基本的操作的)。
好文推荐
发表评论