Maven项目学习(11)SSM项目使用Spring的AOP(后置)增强对系统的操作进行日志管理(实战)

本文主要是介绍Maven项目学习(11)SSM项目使用Spring的AOP(后置)增强对系统的操作进行日志管理(实战),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

       这几天在学习Spring的AOP,然后自己做了一个功能,这个功能是这样的:用户进行对数据进行添加操作之后,系统将操作的用户的ID、操作的模块和操作的内容记录到数据库中。

 

AOP相关术语:

JoinPoint:连接点,指的是可以被拦截的点

PointCut:切入点,指的是真正被拦截的点

Advice:增强,指的是拦截切入点后需要做得事

Target:对象,指的是使用增强的那个对象类

Wearing:织入,指的是将增强应用到对象类的过程

Aspect:切面,指的是切入点与增强的组合

 

       aop实现原理其实是java动态代理,但是jdk的动态代理必须实现接口,所以spring的aop是用cglib这个库实现的,cglib使用了asm这个直接操纵字节码的框架,所以可以做到不实现接口的情况下完成动态代理。(转)

 

 

实验开始

1.数据库

logs表:(此表记录着用户操作的信息)

2.数据库操作层

实体类:

package com.myhomes.entity;import java.util.Date;public class Logs {private Integer id;private Date operationTime;private String types;private String operator;private String modules;private String operation;private String result;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getModules() {return modules;}public void setModules(String modules) {this.modules = modules;}public Date getOperationTime() {return operationTime;}public void setOperationTime(Date operationTime) {this.operationTime = operationTime;}public String getTypes() {return types;}public void setTypes(String types) {this.types = types;}public String getOperator() {return operator;}public void setOperator(String operator) {this.operator = operator;}public String getOperation() {return operation;}public void setOperation(String operation) {this.operation = operation;}public String getResult() {return result;}public void setResult(String result) {this.result = result;}
}

接口类:

package com.myhomes.dao;import com.myhomes.entity.Logs;
import org.springframework.stereotype.Repository;@Repository("logsDao")
public interface LogsDao {void insertLogs(Logs log);
}

映射实现:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.4//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.myhomes.dao.LogsDao"><resultMap id="logs" type="Logs"><result property="id" column="id" javaType="Integer"></result><result property="operationTime" column="operation_time" javaType="java.sql.Date"></result><result property="types" column="types" javaType="String"></result><result property="operator" column="operator" javaType="String"></result><result property="modules" column="modules" javaType="String"></result><result property="operation" column="operation" javaType="String"></result><result property="result" column="result" javaType="String"></result></resultMap><insert id="insertLogs" parameterType="Logs" useGeneratedKeys="true" keyColumn="id">insert into logs(operation_time,types,operator,modules,operation,result) value(#{operationTime},#{types},#{operator},#{modules},#{operation},#{result})</insert></mapper>

3.增强类

新建一个增强类,我是在服务层那里建的。

       因为操作日志是一定要知道是谁操作的,而如何获取操作者,我看有些朋友是通过HttpServletRequest获得session,再从session获得Attribute来知道用户身份的。但是个人感觉session不好,而且我的增强是放在服务层的,服务层没有web层的类,就比如这个类:HttpServletRequest,如果要用这个类,还要在服务层pom文件导入web层的pom文件,同时还将服务层的spring文件导入web层的spring文件的内容,麻烦得紧。而且这么做的话在IDEA启动tomcat还要确认导包之类什么的。。。

      这个例子我还是有用到session(等我把话说完哈),在前端把session中的用户信息放在一个公用的地方,赋值到一个hidden属性的a标签中,提交添加请求的时候获取a标签的内容(也就是用户在数据库表中唯一的id)与数据一同提交到服务器上,只要我把代码修改不要session是能做到的(就是用户登录之后在转发页面的时候带上用户的id,在每次用户需要自己的id进行提交操作时都发送给服务器,服务器处理之后再给会这个id给用户)。

package com.myhomes.biz.advice;import com.myhomes.biz.LogsBiz;
import com.myhomes.entity.Logs;
import org.aspectj.lang.JoinPoint;
import org.springframework.beans.factory.annotation.Autowired;public class LogsAdvice {@Autowiredprivate LogsBiz logsBiz;public void addOperationLog(JoinPoint joinPoint){Logs logs = new Logs();//target对象logs.setModules(joinPoint.getTarget().getClass().getSimpleName());//操作方法logs.setOperation(joinPoint.getSignature().getName());//操作者//System.out.println("后置增强:joinPoint.getArgs()[0].toString():"+joinPoint.getArgs()[0].toString());logs.setOperator(joinPoint.getArgs()[0].toString());//增强方法访问成功logs.setResult("1");logsBiz.addOperationLog(logs);}}

4.Spring文件中配置增强

最后那个配置

<aop:pointcut>标签指的是切入点,id作为切入点的唯一标识,execution定义使用要增强的目标方法;

<aop:aspect>标签指的是切面,ref属性选择ico注入的增强类。

<aop:after-returning>标签指的是“后置增强”,method属性指的是增强方法,pointcut-ref属性选择相关的切入点id。

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!--声明式事务配置在业务层--><!--导入dao层配置文件--><import resource="spring-dao.xml"/><!--开启自动扫描--><context:component-scan base-package="com.myhomes.biz"/><!--aop自动代理--><aop:aspectj-autoproxy/><!--事务管理器--><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!--声明通知,定义规则--><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><tx:method name="get*" read-only="true"/>   <!--不用事务封装--><tx:method name="find*" read-only="true"/><tx:method name="search*" read-only="true"/><tx:method name="*" propagation="REQUIRED"/></tx:attributes></tx:advice><tx:annotation-driven transaction-manager="transactionManager"/><bean id="LogsAdvice" class="com.myhomes.biz.advice.LogsAdvice"></bean><!--通知和切入点进行关联--><aop:config><aop:pointcut id="addPointCut" expression="execution(* com.myhomes.controller.MonthCostController.add*(..))"/>    <!--第一个*号代表任意返回值--><aop:aspect ref="LogsAdvice"><!--<aop:before method="operationLog" pointcut-ref="pointcut1"></aop:before>--><aop:after-returning method="addOperationLog" pointcut-ref="addPointCut"></aop:after-returning></aop:aspect></aop:config></beans>

5.服务层

接口类:(最后那个)

package com.myhomes.biz;import com.myhomes.entity.Logs;public interface LogsBiz {void addSystemLog(Logs logs);void addLoginLog(Logs logs);void addOperationLog(Logs logs);
}

实现类:(最后那个)

package com.myhomes.biz.impl;import com.myhomes.biz.LogsBiz;
import com.myhomes.dao.LogsDao;
import com.myhomes.entity.Logs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;import java.util.Date;@Service("logsBiz")
public class LogsBizImpl implements LogsBiz {@Autowired@Qualifier(value = "logsDao")private LogsDao logsDao;public void addSystemLog(Logs logs) {logs.setOperationTime(new Date());//Systemlogs.setTypes("Sys");logsDao.insertLogs(logs);}public void addLoginLog(Logs logs) {logs.setOperationTime(new Date());logs.setTypes("Login");logsDao.insertLogs(logs);}public void addOperationLog(Logs logs) {logs.setOperationTime(new Date());//Operationlogs.setTypes("Ope");logsDao.insertLogs(logs);}
}

6.控制器层

将要用到增强的add方法,类的其他方法和add()的方法体代码省略了,以免影响观看。

package com.myhomes.controller;import com.myhomes.biz.HouseBiz;
import com.myhomes.biz.MonthCostBiz;
import com.myhomes.biz.UserService;
import com.myhomes.entity.House;
import com.myhomes.entity.MonthCost;
import com.myhomes.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;@Controller("monthCostController")
@RequestMapping(value = "/count")
public class MonthCostController {@Autowiredprivate HouseBiz houseBiz;@Autowiredprivate UserService userService;@Autowiredprivate MonthCostBiz monthCostBiz;@RequestMapping(value = "/add")@ResponseBody@Transactionalpublic Map<String,Object> addMonthCost(@RequestBody Map<String,String> map) throws ParseException {略略略}}

7.页面

利用session将用户id放到a标签里

8.js/jquery

注意看$.ajax({});前面,这里获取用户的id,并且跟数据一同提交到服务器。

//添加数据提交$("#count_house_btn").click(function () {//判断必填选项是否为空if (!$("#count_house_HouseId").val()||!$("#counthouse1").val()||!$("#rent").val()||!$("#waterMeter").val()||!$("#powerMeter").val()){alert("必选内容不能为空!");return false;}if ($("#rent").val()*1<200){alert("租金最低为200!");return false;}//判断水费度数是否比上月小if ($("#waterMeter").val()*1 < lastWaterMeter*1){alert("水费度数不能低于上月水费度数!");return false;}//判断电费度数是否比上月小if ($("#powerMeter").val()*1 < lastPowerMeter*1){alert("电费度数不能低于上月电费度数!");return false;}//判断本次年月日是否比上次计算的日期为同一日if ($("#counthouse1").val() === lastMonth){alert("本日已计算此房间房租,无须再次计算!");return false;}//判断本次年月日是否比上次计算的日期要早var lastmonth = lastMonth;var lastmonth2 = lastmonth.replace(/-/g,'');var thismonth = $("#counthouse1").val();var thismonth2 = thismonth.replace(/-/g,'');if (thismonth2*1 < lastmonth2*1){alert("本次计算房租时间不能比上次计算的房租时间要早!");return false;}//判断本次年月日是否比现在晚var date = new Date();var year = date.getFullYear();var month = date.getMonth()+1;var day = date.getDate();if (month < 10) {month = "0" + month;}if (day < 10) {day = "0" + day;}var nowDate = year + month + day;if (nowDate*1 < thismonth2*1){alert("日期不能比现在晚!");return false;}//判断网费是否小于0if ($("#network").val()*1 < 0){alert("网费不能为负数!");return false;}var houseId = $("#count_house_HouseId").val();var yearsMonth = $("#counthouse1").val();var rent = $("#rent").val()*1;var waterMeter2 = $("#waterMeter").val()*1;var powerMeter2 = $("#powerMeter").val()*1;var network = $("#network").val()*1;var clean = $("#clean").val()*1;var sums = $("#sum_input").val()*1;//获取上月水表数与电表数var lastWaterMeter = $("#lastWaterMeterLabel").text();var lastPowerMeter = $("#lastPowerMeterLabel").text();//用水电表差值进行水电费计算var waterCost = (waterMeter2 - lastWaterMeter) *2.5;var powerCost = (powerMeter2 - lastPowerMeter) *1.5;//提交用户idvar uid = $("#uid").text();// alert("waterCost:"+waterCost+",powerCost:"+powerCost);$.ajax({type:"post",url:"/count/add",dataType : "json",contentType : "application/json;charset=UTF-8",data:JSON.stringify({uid:uid,houseId:houseId,yearsMonth:yearsMonth,rent:rent,waterMeter:waterMeter2,powerMeter:powerMeter2,waterCost:waterCost,powerCost:powerCost,network:network,clean:clean,sum:sums,lastMonth:lastMonth}),success:function (data) {if (data.msg === "add") {$("#counthouse1").val("");$("#rent").val("");$("#waterMeter").val("");$("#powerMeter").val("");$("#network").val("");alert("添加成功!");window.location.href='/count/view';}else if (data.msg === "out") {$("#counthouse1").val("");$("#rent").val("");$("#waterMeter").val("");$("#powerMeter").val("");$("#network").val("");if(data.deposit1 >=0){alert("退房成功!需要向住户返还押金!"+data.deposit1+"元!");}else if(data.deposit2 < 0){alert("退房成功!押金不够抵押本月房租,需要向住户拿!"+data.deposit2+"元!");}window.location.href='/count/view';}else{alert("系统出错!");}}});});
});

9.演示

第一步:

结果:

交互成功,系统进行了添加的操作!

第二步:查看数据库日志表内容

        系统记录了uid=1,(operator字段中,并且有添加的数据),操作时间有,日志类型为操作型,是某个控制器模块,result是“1”表示成功。

第三步:查看用户表id字段为“1”的用户是谁

10.后言

       为什么我不仅把uid记录到数据库中,而且还把添加的信息都记录进去了?因为我个人觉得单单是记录某个人对数据库表进行添加操作的信息是不够的,需要把添加的信息都加进去会好很多。如果是用于修改的增强方法,还要把修改的那一条数据的id给加入到日志信息进去。

11.补

       如果日后要搞个日志查看的模块,这样设计operator字段内容不是很好,因为是要直接显示操作者是谁,如果只显示1大串内容交互不是很好,我修改了下代码,把操作人字段内容就仅添加操作者的id,result字段内容就直接是添加的数据内容和uid。

public class LogsAdvice {@Autowiredprivate LogsBiz logsBiz;public void addOperationLog(JoinPoint joinPoint){Logs logs = new Logs();//target对象logs.setModules(joinPoint.getTarget().getClass().getSimpleName());//操作方法logs.setOperation(joinPoint.getSignature().getName());//操作者//System.out.println("后置增强:joinPoint.getArgs()[0].toString():"+joinPoint.getArgs()[0].toString());Map<String,String> map = (Map<String, String>) joinPoint.getArgs()[0];logs.setOperator(map.get("uid"));//增强方法访问成功logs.setResult(joinPoint.getArgs()[0].toString());logsBiz.addOperationLog(logs);}
}

这篇关于Maven项目学习(11)SSM项目使用Spring的AOP(后置)增强对系统的操作进行日志管理(实战)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/186050

相关文章

Git可视化管理工具(SourceTree)使用操作大全经典

《Git可视化管理工具(SourceTree)使用操作大全经典》本文详细介绍了SourceTree作为Git可视化管理工具的常用操作,包括连接远程仓库、添加SSH密钥、克隆仓库、设置默认项目目录、代码... 目录前言:连接Gitee or github,获取代码:在SourceTree中添加SSH密钥:Cl

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

Java注解之超越Javadoc的元数据利器详解

《Java注解之超越Javadoc的元数据利器详解》本文将深入探讨Java注解的定义、类型、内置注解、自定义注解、保留策略、实际应用场景及最佳实践,无论是初学者还是资深开发者,都能通过本文了解如何利用... 目录什么是注解?注解的类型内置注编程解自定义注解注解的保留策略实际用例最佳实践总结在 Java 编程

Python中模块graphviz使用入门

《Python中模块graphviz使用入门》graphviz是一个用于创建和操作图形的Python库,本文主要介绍了Python中模块graphviz使用入门,具有一定的参考价值,感兴趣的可以了解一... 目录1.安装2. 基本用法2.1 输出图像格式2.2 图像style设置2.3 属性2.4 子图和聚

windows和Linux使用命令行计算文件的MD5值

《windows和Linux使用命令行计算文件的MD5值》在Windows和Linux系统中,您可以使用命令行(终端或命令提示符)来计算文件的MD5值,文章介绍了在Windows和Linux/macO... 目录在Windows上:在linux或MACOS上:总结在Windows上:可以使用certuti

CentOS和Ubuntu系统使用shell脚本创建用户和设置密码

《CentOS和Ubuntu系统使用shell脚本创建用户和设置密码》在Linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设置密码,本文写了一个shell... 在linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设

Python使用Matplotlib绘制3D曲面图详解

《Python使用Matplotlib绘制3D曲面图详解》:本文主要介绍Python使用Matplotlib绘制3D曲面图,在Python中,使用Matplotlib库绘制3D曲面图可以通过mpl... 目录准备工作绘制简单的 3D 曲面图绘制 3D 曲面图添加线框和透明度控制图形视角Matplotlib

Pandas中统计汇总可视化函数plot()的使用

《Pandas中统计汇总可视化函数plot()的使用》Pandas提供了许多强大的数据处理和分析功能,其中plot()函数就是其可视化功能的一个重要组成部分,本文主要介绍了Pandas中统计汇总可视化... 目录一、plot()函数简介二、plot()函数的基本用法三、plot()函数的参数详解四、使用pl

gradle第三方Jar包依赖统一管理方式

《gradle第三方Jar包依赖统一管理方式》:本文主要介绍gradle第三方Jar包依赖统一管理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景实现1.顶层模块build.gradle添加依赖管理插件2.顶层模块build.gradle添加所有管理依赖包