前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何创建一个与Servlet-api完全解耦和的管理员后台操作日志监控

如何创建一个与Servlet-api完全解耦和的管理员后台操作日志监控

作者头像
止术
发布2020-09-15 10:01:44
3480
发布2020-09-15 10:01:44
举报
文章被收录于专栏:求道求道

技术框架MyBatis+Spring+SpringMVC 邮箱:huangfusuper@163.com欢迎交流


在日常开发系统后台时,需要针对管理员操作进行监控,如果使用Spring这一套技术体系,使用AOP切面编程+自定义注解不妨是一个好办法,但是在使用这一套体系的同时也会出现一些坑。比如这一套体系是完全依赖于WEB环境,脱离WEB环境就会出现出现ServletRequestAttributes为null的情况。那么如何解决这个问题。

首先快速搭建一个Spring 的运行环境具体jar参照下图:

<dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <!--jstl--> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!--spring--> <!--spring相关依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!--springmvc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.2.RELEASE</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.2.5</version> </dependency> <!--mybatis-spring--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.2</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <!--commons-fileupload--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3</version> </dependency> <!--jackson--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency> <!--log4j--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> </dependency> <!--junit测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>

首先对前面的开发步骤做一个简单的讲解,首先开发一个自定义注解:

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //在方法上使用 @Target({ElementType.METHOD}) //类一旦运行 起作用 @Retention(RetentionPolicy.RUNTIME) public @interface LogAnnotation { public String value(); }

开发环绕通知(常规做法,下面做修改)

import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpSession; import java.lang.reflect.Method; import java.util.Date; /* * * 这是一个环绕通知 * 需要实现 * */ public class Around implements MethodInterceptor { @Override public Object invoke(MethodInvocation mi) throws Throwable { /* * 1.什么人-------- * 2.什么时间 new Date() * 3.什么事情----方法名 * 4.是否成功-----能 * */ ServletRequestAttributes s = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); //获取HttpRequst对象,于Servlet强耦合 HttpSession session = s.getRequest().getSession(); //拿到存放在Session的数据 String adminName = (String)session.getAttribute("admin"); //时间 Date date = new Date(); //什么事情 Method method = mi.getMethod(); //拿到类对象 反射 LogAnnotation annotation = method.getAnnotation(LogAnnotation.class); //通过反射拿到的实例 调用方法 String name = annotation.value(); //是否成功 boolean flag = false; Object proceed = null; try { proceed = mi.proceed(); flag=true; }catch (Exception a){ a.printStackTrace(); } //这里不做插入数据库的操作 System.out.println(adminName+"管理员在"+date+"执行了"+name+"成功了么?"+flag); return proceed; } }

上述实现的修改(于Servlet弱耦合),利用Spring的DI特性,实现对操作对象的自动注入。 import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import java.lang.reflect.Method; import java.util.Date; /* * 这是一个环绕通知 * 需要实现 * */ public class Around implements MethodInterceptor { //将操作对象声明为成员变量 private String adminName; //设置公开访问方法,实现未来的数据注入 public void setAdminName(String adminName) { this.adminName = adminName; } @Override public Object invoke(MethodInvocation mi) throws Throwable { Date date = new Date(); //什么事情 Method method = mi.getMethod(); //拿到类对象 反射 LogAnnotation annotation = method.getAnnotation(LogAnnotation.class); //通过反射拿到的实例 调用方法 String name = annotation.value(); //是否成功 boolean flag = false; Object proceed = null; try { proceed = mi.proceed(); flag=true; }catch (Exception a){ a.printStackTrace(); } System.out.println(adminName+"管理员在"+date+"执行了"+name+"成功了么?"+flag); return proceed; } }

以上将操作数据设定为成员变量,未来我可以在controller层和业务层增加一个过滤器,实现对操作数据的注入。

3. 对通知类使用Spring进行管理

<!--配置组装切面--> <aop:config proxy-target-class="true"> <!--配置切入点--> <aop:pointcut id="pc" expression="@annotation(com.baizhi.aop.LogAnnotation)"/> <!--组装切面--> <aop:advisor advice-ref="around" pointcut-ref="pc"/> </aop:config>

过滤器的开发

import com.baizhi.aop.Around; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.io.IOException; public class LogFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { filterChain.doFilter(servletRequest, servletResponse); HttpServletRequest res = (HttpServletRequest)servletRequest; HttpSession session = res.getSession(); String admin = (String) session.getAttribute("admin"); ServletContext servletContext = session.getServletContext(); //使用这个web工具类拿到WebApplicationContext对象 WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext); //能通过WebApplicationContext类拿到已经初始化的Bean Around around = (Around) webApplicationContext.getBean("around"); //通过set方法注入数据 around.setAdminName(admin); } @Override public void destroy() { } }

5.最后在web.xml中进行配置

<!--配置过滤器位置--> <filter> <filter-name>log</filter-name> <filter-class>com.baizhi.filter.LogFilter</filter-class> </filter> <!--过滤器拦截位置--> <filter-mapping> <filter-name>log</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

搞定测试,这样做的好处是可以在测试某个模块时,只关注于String类型的name就行了,不必去考虑web的session的获取问题和null值问题

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-01-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JAVA程序狗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档