1. 添加日志思路分析
1. 日志:是用于记录当前用户/系统进行了哪些操作的,会将操作信息 保存起来
-
在本项目中,日志管理模块中有添加日志的功能,不是由用户添加的,而是由程序来添加的。原理为:程序对当前用户进行的所有操作都会记录(将日志数据保存到数据库中)
-
本项目中日志添加功能分析:
2. AOP:
-
aop:Aspect oriented programming 面向切面编程,是一种编程思想
-
aop的好处:将核心业务代码和横切关注点解耦,提高了项目的维护性以及扩展性
-
aop的应用:日志记录,声明式事务管理,性能统计,shiro框架的授权功能
-
专业术语:
1. Aspect(切面):切面类 2. Join point(连接点):可能会成为切点的所有方法 3. Pointcut(切点/切入点):调用时真正有切面注入的方法 4. Advice(通知):切面类中的方法(前置,后置,环绕) 5. Target object(目标对象):最终切面要切入的方法所在的对象 6. Weaving(织入):动作,将通知注入到切点中
- 练习识别:
- 练习识别:
-
通知类型:
1. 前置通知:通知的代码在业务代码之前执行 @Before 2. 后置通过:通知的代码在业务代码之后执行 @After 3. 环绕通知:在业务代码之前和之后都会有通知的代码执行 @Around 返回值类型Object,表示业务代码的返回值 4.返回后通知 5.抛出异常后通知
-
aop代理机制:
- JDK动态代理:只能为实现了接口的类生产代理对象
- 利用了反射
- CGLIB代理机制:可以直接为类生产代理对象
- JDK动态代理:只能为实现了接口的类生产代理对象
3. 日志添加实现:–aop的应用
-
持久层开发–添加日志数据
-
在接口中定义抽象方法
Integer insertLog(Log log)
-
在映射文件中写sql语句
-
id字段的值是自增长的,不需要插入
-
createdTime字段的值
- 在Java代码中new Date()
- 也可在sql语句中调用数据库的now()函数
-
sql语句”
<insert id="insertLog"> insert into sys_logs( username,operation, method,params, time,ip,createdTime) values( #{userName},#{operation}, #{method},#{params}, #{time},#{ip},now() ) </insert>
-
-
在测试类中完成测试
@Test public void insertLogTest() { Log log = new Log(null, "test", "测试操作", "cn.tedu....", "visitor", 20L, "0.0.0.1", null); Integer rows = logMapper.insertLog(log); System.err.println(rows); }
-
-
添加日志的准备工作:
- 获取一个日志对象的数据包括:
- userName:当前用户名称,正常应该是从session对象中获取的,但是因为目前我们还没有实现登录,没有向session中存数据,此时先给出一个固定值。
- operation:删除xx,查询xx,更新xx—是根据调用的方法来给出的,此处我们自定义一个注解@Operation,该注解用于方法上方,给出操作的名称
- method:调用的方法名称,通知中会执行业务方法,通知的参数列表中会存在目标方法对象
- params:调用方式时传递的实参
- time:目标方法运行耗时 ,在业务方法执行前后分别获取时间,求差值即可
- ip:获取当前用户的ip地址 – IPUtil
- 获取一个日志对象的数据包括:
-
自定义Operation注解
-
定义注解类
@Target({ElementType.METHOD}) //表示Operation注解是作用在方法上的 @Retention(RetentionPolicy.RUNTIME) //表示Operation注解的有效期至运行期 public @interface Operation { String value() default ""; }
-
在日志业务模块方法上方添加该注解进行测试:
@Operation("删除日志") public void removeLogs(Integer[] ids) { @Operation("查询日志列表") public PageInfo<Log> findLogList(String us....
-
-
写添加日志记录的切面类
-
先导入相关的依赖–aspect
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency>
-
定义切面类LogAspect,类上方添加注解@Aspect,@Component
@Aspect @Component public class LogAspect { @Autowired private LogMapper logMapper; @Around("execution(* cn.tedu.sysmanagement.Service.impl.*.*(..))&&@annotation(anno)") public Object logAddAdvice(ProceedingJoinPoint pjp, Operation anno) throws Throwable { long beforTime = System.currentTimeMillis(); //获取当前时间 Object returnVal = pjp.proceed(); //目标方法执行 long afterTime = System.currentTimeMillis(); //再次获取时间 long time = afterTime-beforTime; //方法耗时得到 //获取方法上方注解Operation的value值,表示方法的操作 String operation = anno.value(); //调用saveLog方法 saveLog(pjp,time,operation); return returnVal; } public void saveLog(ProceedingJoinPoint pjp,long time,String operation) throws JsonProcessingException { //继续获取剩余的参数 String userName = "visitor"; //获取方法全名(包名.类名.方法名)--通过pjp获取类名+通过pjp获取的方法名 String className = pjp.getTarget().getClass().getName(); //获取方法名,Signature-方法签名 String methodName = pjp.getSignature().getName(); String method = className+"."+methodName; //获取方法的入参值 Object[] paramsArr = pjp.getArgs(); //将参数数组转换为字符串类型 String params = new ObjectMapper().writeValueAsString(paramsArr); //获取用户的ip地址值,IPUtils工具类已提供 String ip = IPUtils.getIpAddr(); //将以上的属性封装到Log对象中 Log log = new Log(null,userName,operation,method,params,time,ip,null); //调用持久层插入日志数据 logMapper.insertLog(log); } }
-