热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:数据后台管理AOP日志

为了增加数据的安全性,在数据管理的过程中,我们需要将操作者访问时间,操作者的名称,访问的IP,访问资源的URL,执行时长,访问方法记录下来存储到数据库中,并可以通过页面

为了增加数据的安全性,在数据管理的过程中,我们需要将操作者访问时间,操作者的名称,访问的IP,访问资源的URL,执行时长,访问方法记录下来存储到数据库中,并可以通过页面查看。

1.将日志信息存储到数据库中


1.1根据需要记录的日志内容在数据库中创建表syslog和对应的实体类SysLog

日志表syslog

技术图片

SysLog类

技术图片技术图片

1 package club.nipengfei.ssm.domain;
2
3 import java.util.Date;
4
5 public class SysLog {
6 private String id;
7 private Date visitTime;
8 private String visitTimeStr;
9 private String username;
10 private String ip;
11 private String url;
12 private Long executionTime;
13 private String method;
14
15 public String getId() {
16 return id;
17 }
18
19 public void setId(String id) {
20 this.id = id;
21 }
22
23 public Date getVisitTime() {
24 return visitTime;
25 }
26
27 public void setVisitTime(Date visitTime) {
28 this.visitTime = visitTime;
29 }
30
31 public String getVisitTimeStr() {
32 return visitTimeStr;
33 }
34
35 public void setVisitTimeStr(String visitTimeStr) {
36 this.visitTimeStr = visitTimeStr;
37 }
38
39 public String getUsername() {
40 return username;
41 }
42
43 public void setUsername(String username) {
44 this.username = username;
45 }
46
47 public String getIp() {
48 return ip;
49 }
50
51 public void setIp(String ip) {
52 this.ip = ip;
53 }
54
55 public String getUrl() {
56 return url;
57 }
58
59 public void setUrl(String url) {
60 this.url = url;
61 }
62
63 public Long getExecutionTime() {
64 return executionTime;
65 }
66
67 public void setExecutionTime(Long executionTime) {
68 this.executiOnTime= executionTime;
69 }
70
71 public String getMethod() {
72 return method;
73 }
74
75 public void setMethod(String method) {
76 this.method = method;
77 }
78 }


SysLog

1.2在controller包下新建一个切面类LogAop来获取需要记录日志内容

注意该类作为切面类需要注解@Aspect

在该切面类内创建一个前置通知@Before("execution(* club.nipengfei.ssm.controller.*.*(..))"),一个后置通知@After("execution(* club.nipengfei.ssm.controller.*.*(..))"),注解内的属性表示切入点表达式,在这里表示controller包下的所有类。

1.2.1获取操作者的访问时间

直接在前置通知内new一个Date()

1.2.2获取操作者名称


1 // 获取当前操作的用户
2 SecurityContext cOntext= SecurityContextHolder.getContext();
3 User user =(User) context.getAuthentication().getPrincipal();
4 String username = user.getUsername();


1.2.3获取访问IP

先在web.xml中新增一个监听器

1 <listener>
2 <listener-class>org.springframework.web.context.request.RequestContextListenerlistener-class>
3 listener>

通过getRemoteAddr()方法获取IP

1 // 获取IP地址
2 String ip = request.getRemoteAddr();


 1.2.4获取访问资源的URL

思路:获取类上注解的@RequestMapping的属性值和方法上注解@RequestMapping的属性值,并将两者拼接。

获取类上注解属性值:通过反射获取操作的类,使用getAnnotation(RequestMapping.class)方法获取@RequestMapping注解,使用value()获取属性

获取方法上注解属性值:通过反射获取操作的类,使用getMethod()方法获取方法,使用getAnnotation(RequestMapping.class)方法获取@RequestMapping注解,使用value()获取属性

具体代码放下面。

1.2.5获取执行时长

在后置通知内new一个Date()减去前置通知的Date()。

1 // 获取访问时长
2 long time = new Date().getTime()-visitTime.getTime();


1.2.6获取访问方法

通过类的getMethod()方法获取方法。

注意:有些方法含参,有些不含参需要分开处理。

1 @Before("execution(* club.nipengfei.ssm.controller.*.*(..))")
2 public void doBefore(JoinPoint jp) throws NoSuchMethodException {
3 visitTime = new Date(); // 当前时间就是开始访问的类
4 clazz = jp.getTarget().getClass(); // 具体访问的类
5 String methodName = jp.getSignature().getName(); // 获取访问方法名称
6 Object[] args = jp.getArgs(); // 获取访问方法参数
7
8 // 获取具体执行方法Method对象
9 if (args==null || args.length==0){
10 method = clazz.getMethod(methodName);
11 } else {
12 Class[] classArgs = new Class[args.length];
13 for (int i=0;i){
14 classArgs[i] = args[i].getClass();
15 }
16 method = clazz.getMethod(methodName,classArgs);
17 }
18 }

 LogAop类的代码:

1 package club.nipengfei.ssm.controller;
2
3 import club.nipengfei.ssm.domain.SysLog;
4 import club.nipengfei.ssm.service.ISysLogService;
5 import org.aspectj.lang.JoinPoint;
6 import org.aspectj.lang.annotation.After;
7 import org.aspectj.lang.annotation.Aspect;
8 import org.aspectj.lang.annotation.Before;
9 import org.springframework.beans.factory.annotation.Autowired;
10 import org.springframework.security.core.context.SecurityContext;
11 import org.springframework.security.core.context.SecurityContextHolder;
12 import org.springframework.security.core.userdetails.User;
13 import org.springframework.stereotype.Component;
14 import org.springframework.web.bind.annotation.RequestMapping;
15
16 import javax.servlet.http.HttpServletRequest;
17 import java.lang.reflect.Method;
18 import java.util.Date;
19
20 @Component
21 @Aspect
22 public class LogAop {
23
24 @Autowired
25 private HttpServletRequest request;
26
27 @Autowired
28 private ISysLogService sysLogService;
29
30 private Date visitTime; // 开始时间
31 private Class clazz; // 访问的类
32 private Method method; // 访问的方法
33
34 // 前置通知 主要获取开始时间,执行的类哪一个,执行的哪一个方法
35 @Before("execution(* club.nipengfei.ssm.controller.*.*(..))")
36 public void doBefore(JoinPoint jp) throws NoSuchMethodException {
37 visitTime = new Date(); // 当前时间就是开始访问的类
38 clazz = jp.getTarget().getClass(); // 具体访问的类
39 String methodName = jp.getSignature().getName(); // 获取访问方法名称
40 Object[] args = jp.getArgs(); // 获取访问方法参数
41
42 // 获取具体执行方法Method对象
43 if (args==null || args.length==0){
44 method = clazz.getMethod(methodName);
45 } else {
46 Class[] classArgs = new Class[args.length];
47 for (int i=0;i){
48 classArgs[i] = args[i].getClass();
49 }
50 method = clazz.getMethod(methodName,classArgs);
51 }
52 }
53
54 // 后置通知
55 @After("execution(* club.nipengfei.ssm.controller.*.*(..))")
56 public void doAfter(JoinPoint jp) throws Exception {
57
58 // 获取访问时长
59 long time = new Date().getTime()-visitTime.getTime();
60
61 String url = "";
62 // 获取url
63 if (clazz != null && method !=null && clazz!=LogAop.class){
64 // 获取类的@RequestMapping("/orders")
65 RequestMapping clazzAnnotation =(RequestMapping) clazz.getAnnotation(RequestMapping.class);
66 if (clazzAnnotation != null){
67 String[] classValue = clazzAnnotation.value();
68 // 获取方法上的@RequestMapping("xxx")
69 RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
70 if (methodAnnotation != null){
71 String[] methodValue = methodAnnotation.value();
72 url=classValue[0]+methodValue[0];
73
74 // 获取IP地址
75 String ip = request.getRemoteAddr();
76
77 // 获取当前操作的用户
78 SecurityContext cOntext= SecurityContextHolder.getContext();
79 User user =(User) context.getAuthentication().getPrincipal();
80 String username = user.getUsername();
81
82 // 将日志相关信息封装到SysLog对象
83 SysLog sysLog = new SysLog();
84 sysLog.setExecutionTime(time);
85 sysLog.setIp(ip);
86 sysLog.setMethod("[类名] "+clazz.getName()+"[方法名] "+method.getName());
87 sysLog.setUrl(url);
88 sysLog.setUsername(username);
89 sysLog.setVisitTime(visitTime);
90
91 // 调用service完成操作
92 sysLogService.save(sysLog);
93 }
94 }
95
96 }
97 }
98 }


1.3在service.impl包下新建一个SysLogServiceImpl类,生成一个save方法将SysLog类对象放到数据表中


1 package club.nipengfei.ssm.service.impl;
2
3 import club.nipengfei.ssm.dao.ISysLogDao;
4 import club.nipengfei.ssm.domain.SysLog;
5 import club.nipengfei.ssm.service.ISysLogService;
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.stereotype.Service;
8 import org.springframework.transaction.annotation.Transactional;
9
10 import java.util.List;
11
12 @Service
13 @Transactional
14 public class SysLogServiceImpl implements ISysLogService {
15
16 @Autowired
17 private ISysLogDao sysLogDao;
18
19 @Override
20 public void save(SysLog sysLog) throws Exception {
21 sysLogDao.save(sysLog);
22 }
23
24 }


1.4在dao包下新建ISysLogDao接口


1 package club.nipengfei.ssm.dao;
2
3 import club.nipengfei.ssm.domain.SysLog;
4 import org.apache.ibatis.annotations.Insert;
5 import org.apache.ibatis.annotations.Select;
6
7 import java.util.List;
8
9 public interface ISysLogDao {
10
11 @Insert("insert into syslog(visitTime,username,ip,url,executionTime,method) values(#{visitTime},#{username},#{ip},#{url},#{executionTime},#{method})")
12 public void save(SysLog sysLog) throws Exception;
13
14 }


1.5存在的问题

当点击订单管理时发现,不能正常访问

技术图片

查看资料发现因为该findAll方法传入的形参是int类型,而我们的切面类通过反射获取该类的方法时传入的参数Integer类型。将findAll方法的int改为Integer,发现能正常访问了。

2.将日志信息展示到页面上

流程分析图:

 技术图片

2.1在ISysLogDao接口中生成一个findAll方法


1 package club.nipengfei.ssm.dao;
2
3 import club.nipengfei.ssm.domain.SysLog;
4 import org.apache.ibatis.annotations.Insert;
5 import org.apache.ibatis.annotations.Select;
6
7 import java.util.List;
8
9 public interface ISysLogDao {
10
11 @Insert("insert into syslog(visitTime,username,ip,url,executionTime,method) values(#{visitTime},#{username},#{ip},#{url},#{executionTime},#{method})")
12 public void save(SysLog sysLog) throws Exception;
13
14 @Select("select * from sysLog")
15 List findAll() throws Exception;
16 }


2.2在SysLogServiceImpl类内调用上面方法


1 package club.nipengfei.ssm.service.impl;
2
3 import club.nipengfei.ssm.dao.ISysLogDao;
4 import club.nipengfei.ssm.domain.SysLog;
5 import club.nipengfei.ssm.service.ISysLogService;
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.stereotype.Service;
8 import org.springframework.transaction.annotation.Transactional;
9
10 import java.util.List;
11
12 @Service
13 @Transactional
14 public class SysLogServiceImpl implements ISysLogService {
15
16 @Autowired
17 private ISysLogDao sysLogDao;
18
19 @Override
20 public void save(SysLog sysLog) throws Exception {
21 sysLogDao.save(sysLog);
22 }
23
24 @Override
25 public List findAll() throws Exception {
26 return sysLogDao.findAll();
27 }
28 }


2.3在controller包下新建一个SysLogController类


1 package club.nipengfei.ssm.controller;
2
3 import club.nipengfei.ssm.domain.SysLog;
4 import club.nipengfei.ssm.service.ISysLogService;
5 import org.springframework.beans.factory.annotation.Autowired;
6 import org.springframework.stereotype.Controller;
7 import org.springframework.web.bind.annotation.RequestMapping;
8 import org.springframework.web.servlet.ModelAndView;
9
10 import java.util.List;
11
12 @Controller
13 @RequestMapping("/sysLog")
14 public class SysLogController {
15
16 @Autowired
17 private ISysLogService sysLogService;
18
19 @RequestMapping("/findAll.do")
20 public ModelAndView findAll() throws Exception {
21 ModelAndView mv = new ModelAndView();
22 List sysLogList = sysLogService.findAll();
23 mv.addObject("sysLogs",sysLogList);
24 mv.setViewName("syslog-list");
25 return mv;
26 }
27 }

 


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 本文介绍了Java高并发程序设计中线程安全的概念与synchronized关键字的使用。通过一个计数器的例子,演示了多线程同时对变量进行累加操作时可能出现的问题。最终值会小于预期的原因是因为两个线程同时对变量进行写入时,其中一个线程的结果会覆盖另一个线程的结果。为了解决这个问题,可以使用synchronized关键字来保证线程安全。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有