spring aop实现日志录入

 

 

1. spring 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task" xmlns:cache="http://www.springframework.org/schema/cache"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:websocket="http://www.springframework.org/schema/websocket"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-4.0.xsd 
       http://www.springframework.org/schema/jee 
       http://www.springframework.org/schema/jee/spring-jee-4.0.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-4.0.xsd
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
       http://www.springframework.org/schema/task  
	   http://www.springframework.org/schema/task/spring-task-3.1.xsd
	   http://www.springframework.org/schema/cache
       http://www.springframework.org/schema/cache/spring-cache.xsd
       http://www.springframework.org/schema/websocket   
       http://www.springframework.org/schema/websocket/spring-websocket.xsd
       http://www.springframework.org/schema/aop
      http://www.springframework.org/schema/aop/spring-aop.xsd">

	<context:annotation-config />
	
	 <!-- 使用注解时要开启注解扫描 要扫描的包 -->
	<context:component-scan base-package="com.cloudtech.web" />
	
	  <!-- 开启aop注解方式 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

	<context:property-placeholder location="classpath*:/config.properties"
		ignore-resource-not-found="true" ignore-unresolvable="true" />
	<!-- <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
		<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" 
		/> <property name="locations"> <list> <value>file:${CONF_DOCTOR}/config/jdbc-125.properties</value> 
		<value>file:${CONF_DOCTOR}/config/config.properties</value> </list> </property> 
		</bean> -->
	<!-- 配置数据源 -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
		init-method="init" destroy-method="close">
		<!-- 数据库驱动 config.decrypt=true -->
		<property name="driverClassName" value="${jdbc.driverClassName}" />
		<!-- 数据库地址 -->
		<property name="url" value="${jdbc.url}" />
		<!-- 数据库用户名 -->
		<property name="username" value="${jdbc.username}" />
		<!-- 数据库密码 -->
		<property name="password" value="${jdbc.password}" />
		<!-- 初始化连接大小 -->
		<property name="initialSize" value="1" />
		<!-- 连接池最大使用连接数量 -->
		<property name="maxActive" value="100" />
		<!-- 连接池最大空闲 -->
		<!-- <property name="maxIdle" value="20" /> -->
		<!-- 连接池最小空闲 -->
		<property name="minIdle" value="5" />
		<!-- 获取连接最大等待时间 -->
		<property name="maxWait" value="60000" />
		<property name="poolPreparedStatements" value="true" />
		<property name="maxPoolPreparedStatementPerConnectionSize"
			value="33" />
		<!-- 用来检测连接是否有效的sql,要求是一个查询语句 -->
		<!-- <property name="validationQuery" value="${validationQuery}" /> -->
		<property name="testOnBorrow" value="false" />
		<property name="testOnReturn" value="false" />
		<property name="testWhileIdle" value="true" />
		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="60000" />
		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="25200000" />
		<!-- 打开removeAbandoned功能 -->
		<property name="removeAbandoned" value="true" />
		<!-- 1800秒,也就是30分钟 -->
		<property name="removeAbandonedTimeout" value="1800" />
		<!-- 关闭abanded连接时输出错误日志 -->
		<property name="logAbandoned" value="true" />
		<!-- 监控数据库 -->
		<property name="filters" value="stat,log4j" />
	</bean>

	<!-- myBatis文件 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<!-- 自动扫描entity目录, 省掉Configuration.xml里的手工配置 -->
		<property name="mapperLocations" value="classpath*:/com/cloudtech/web/mapper/*.xml" />
		<!-- 要映射类的包路径 -->
		<property name="typeAliasesPackage" value="com.cloudtech.web.entity" />
		<!-- 通用mapper配置 -->
		<property name="plugins">
			<array>
				<bean class="com.github.pagehelper.PageHelper">
					<property name="properties">
						<!-- 属性一行一个,具体属性参考mybatis-config.xml中的属性 -->
						<value>
							mapper=tk.mybatis.mapper.common.Mapper
							dialect=mysql
							<!-- 主键自增回写方法,默认值MYSQL, -->
							identity=mysql
							<!-- 该参数默认为false -->
							<!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 -->
							<!-- 和startPage中的pageNum效果一样 -->
							offsetAsPageNum=true
							<!-- 该参数默认为false -->
							<!-- 设置为true时,使用RowBounds分页会进行count查询 -->
							rowBoundsWithCount=true
						</value>
					</property>
				</bean>
				<bean class="tk.mybatis.mapper.mapperhelper.MapperInterceptor">
					<property name="properties">
						<!-- 属性一行一个,具体属性参考mybatis-config.xml中的属性 -->
						<value>
							mappers=tk.mybatis.mapper.common.Mapper
							identity=mysql
						</value>
					</property>
				</bean>
			</array>
		</property>
	</bean>

	<!-- 以下是Redis连接池配置 -->
	<!-- <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> 
		最大连接数 <property name="maxActive" value="${redis.pool.maxActive}" /> 最大空闲连接数 
		<property name="maxIdle" value="${redis.pool.maxIdle}" /> 最大等待时间 <property 
		name="maxWait" value="${redis.pool.maxWait}" /> 对拿到的connection进行validateObject校验 
		<property name="testOnBorrow" value="${redis.pool.testOnBorrow}" /> 在进行returnObject对返回的connection进行validateObject校验 
		<property name="testOnReturn" value="${redis.pool.testOnReturn}" /> </bean> 
		<bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool" 
		scope="singleton"> <constructor-arg index="0" ref="jedisPoolConfig" /> <constructor-arg 
		index="1"> <list> <bean class="redis.clients.jedis.JedisShardInfo"> <constructor-arg 
		name="host" value="${redis.host}" /> <constructor-arg name="port" value="${redis.port}" 
		/> <constructor-arg name="timeout" value="${redis.timeout}" /> <constructor-arg 
		name="weight" value="1" /> <property name="password" value="${redis.password}"/> 
		</bean> </list> </constructor-arg> </bean> -->

	<!-- 扫描指定包下的Mapper,自动创建mapper bean实例 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.cloudtech.web.dao" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
	</bean>

	<!-- 配置事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- 注解方式配置事物 -->
	<tx:annotation-driven transaction-manager="transactionManager" />
	<aop:aspectj-autoproxy />

	<!-- 注解方式配置定时任务 -->
	<task:annotation-driven />
	<!-- <task:scheduled-tasks scheduler="myScheduler"> 对账定时任务,每天十点半 cron="0 
		30 10 ? * *" <task:scheduled ref="taskHandler" method="recontTask" cron="${recont.cron}"/> 
		</task:scheduled-tasks> <task:scheduler id="myScheduler" pool-size="10"/> -->

	<!-- 注解方式配置缓存 -->
	<!-- <cache:annotation-driven cache-manager="cacheManager" proxy-target-class="false" 
		/> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> 
		<property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" 
		p:name="WXpayConfig" /> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" 
		p:name="AlipayConfig" /> </set> </property> </bean> -->
	<!-- <import resource="applicationContext-quartz.xml"/> -->
	<import resource="dubbo-provide.xml"/> 
</beans>

 导入aop命令空间和aop注解

package com.cloudtech.web.aop;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cloudtech.web.dao.AdminMapper;
import com.cloudtech.web.dao.AuthorityMapper;
import com.cloudtech.web.dao.OperationDetailLogsMapper;
import com.cloudtech.web.dao.OperationLogsMapper;
import com.cloudtech.web.dao.OperatorMapper;
import com.cloudtech.web.dao.RoleMapper;
import com.cloudtech.web.entity.Admin;
import com.cloudtech.web.entity.Authority;
import com.cloudtech.web.entity.OperationDetailLogs;
import com.cloudtech.web.entity.OperationLogs;
import com.cloudtech.web.entity.Operator;
import com.cloudtech.web.entity.Role;
import com.cloudtech.web.enums.ChildModuleType;
import com.cloudtech.web.enums.OperationType;
import com.cloudtech.web.enums.ParentModuleType;
import com.cloudtech.web.vo.Principal;

/**
 * 
* @ClassName: LogAspect  
* @Description:  日志操作记录 
* @author wude  
* @date 2018年7月19日  
*
 */
@Aspect
@Component
public class LogAspect {
	/**
	 * @serial 日志.
	 */
	private static final Logger LOGGER = LoggerFactory.getLogger(LogAspect.class);
	@Autowired
	private OperationLogsMapper logsMapper;
	@Autowired
	private OperationDetailLogsMapper detailLogsMapper;
	@Autowired
	private RoleMapper roleMapper;
	@Autowired
	private AuthorityMapper authorityMapper;
	@Autowired
	private OperatorMapper operatorMapper;
	@Autowired
	private AdminMapper adminMapper;

	/**
	 * 角色日志修改和新增操作日志记录
	 * @param point
	 * @throws Throwable
	 */
	@SuppressWarnings("null")
	@Around("execution(* com.cloudtech.web.service.impl.RoleServiceImpl.insertOrUpdate(..))")
	public Object processInsertRoleConfig(ProceedingJoinPoint point) throws Throwable {
		Object rvt = null;
		Role role = null;
		Principal principal = null;  //新增
		OperationType type = null;   //操作类型 
		String title = "";      //标题
		// 访问目标方法的参数:
		Object[] args = point.getArgs(); // point.getArgs() 获得执行参数
		//父模块id
		Integer module = ParentModuleType.ADMIN_MANGGER.getCode();
		//子模块id
		Integer subModule = ChildModuleType.ROLE_LIST.getCode();
		if (args != null && args.length > 0) {
			role = (Role) args[0];
			principal = (Principal) args[1];
			type = (OperationType) args[2];
			
			if(type == OperationType.ADD) {    //新增
				rvt = point.proceed();
				LOGGER.debug("新增角色操作日志记录: " + role.toString());
				if(role.getId() != null){
					//插入日志表
					title = "角色信息新增";
					OperationLogs logs = insertLog(title, principal, type,module,subModule);
					
					//插入日志详情表-----角色名称
					insertRoleDetailLog(logs, null, role, 1, type);
					
					//插入日志详情表-----角色描述
					insertRoleDetailLog(logs, null, role, 2, type);
				}
			}
			
			Role beforeRole = null;   //修改之前的role
			if(type == OperationType.UPDATE) {    //修改
				beforeRole = roleMapper.selectByPrimaryKey(role.getId());
				
				LOGGER.debug("修改角色操作日志记录: " + role.toString());
				rvt = point.proceed();
				
				boolean flag = false;
				boolean nameUpdate = false;    //名字修改
				boolean descUpdate = false;    //描述 修改
				if (!beforeRole.getName().equals(role.getName())) {
					flag = true;
					nameUpdate = true;
				}
				
				if (!beforeRole.getDescription().equals(role.getDescription())) {
					flag = true;
					descUpdate = true;
				}
				
				if(flag){   //修改过
					title = "角色信息修改";
					OperationLogs logs = insertLog(title, principal, type,module,subModule);
					
					if(nameUpdate){   //名字修改
						//插入日志详情表-----角色名称
						insertRoleDetailLog(logs, beforeRole, role, 1, type);
					}
					
					if(descUpdate){    //描述 修改
						//插入日志详情表-----角色描述
						insertRoleDetailLog(logs, beforeRole, role, 2, type);
					}
				}
			}
		}
		return rvt;
	}


    /**
	 * 角色模块删除操作日志
	 * 
	 * @param point
	 * @return
	 * @throws Throwable
	 */
	@Around("execution(* com.cloudtech.web.service.impl.RoleServiceImpl.delete(..))")
	public Object processDeleteRoleLog(ProceedingJoinPoint point) throws Throwable {
		Object[] args = point.getArgs();
		Integer id = null;
		Object rvt = null;
		Principal principal = null; // 新增
		OperationType type = null; // 操作类型
		String title = ""; // 标题
		Role beforeRole = null;
		// 父模块id
		Integer module = ParentModuleType.ADMIN_MANGGER.getCode();
		// 子模块id
		Integer subModule = ChildModuleType.ROLE_LIST.getCode();
		if (args != null && args.length > 0) {
			id = (Integer) args[0];
			principal = (Principal) args[1];
			type = (OperationType) args[2];
			beforeRole = roleMapper.selectByPrimaryKey(id);
			rvt = point.proceed();
			Role role = roleMapper.selectByPrimaryKey(id);
			if(role == null){
				LOGGER.debug("删除角色操作日志记录: 角色id为" + id);

				// 插入日志表
				title = "角色信息删除";
				OperationLogs logs = insertLog(title, principal, type, module, subModule);

				// 角色名称
				insertRoleDetailLog(logs, beforeRole, null, 1, type);
				// 角色描述
				insertRoleDetailLog(logs, beforeRole, null, 2, type);
			}
		}
		// 用改变后的参数执行目标方法
		return rvt;
	}
}

注意:因为我这里新增和修改使用的是同一个方法,所以,这里有一个难点,修改需要区别修改前和修改后的值,新增的时候,需要操作成功后才插入对应的值。通过    rvt = point.proceed();实现。通过调用该方法,通知配置切面的对应的方法先运行,假设为新增操作,因为是环绕增强,方法前方法后都会运行,所以,通过该代码,确保添加成功后,才记录对应的日志,也就是上文中的判断id不为空时,才新增。

删除场景:考虑到删除有报错的情况,所以需要判断是否删除成功后,才能记录日志,而,判断删除是否成功的前提,就是环绕增强,先走切面,记录修改前的角色对象,和id,通过    rvt = point.proceed();通过调用该方法,通知配置切面的对应的方法先运行,删除方法跑完后,会继续回调切面方法,这是再更加id查,看是否能查到数据,如果查不到数据,说明删除成功

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值