欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

利用spring AOP实现操作日志功能

程序员文章站 2022-07-12 14:50:30
...

首先需要在spring配置文件中配置aop支持,
 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:task="http://www.springframework.org/schema/task"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:websocket="http://www.springframework.org/schema/websocket"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/websocket
        http://www.springframework.org/schema/websocket/spring-websocket.xsd"
        >
        
    <aop:aspectj-autoproxy/>       <!-- aop支持 -->
    <mvc:annotation-driven conversion-service="conversionService"/>       <!-- mvc支持 -->
<!-- <mvc:resources mapping="/assets/**" location="/assets/"/>
<mvc:resources mapping="/404/**" location="/404/"/>
<mvc:resources mapping="/awxj/**" location="/awxj/"/>
<mvc:resources mapping="/CameraPhoto/**" location="/CameraPhoto/"/>
<mvc:resources mapping="/docs/**" location="/docs/"/>
<mvc:resources mapping="/html/**" location="/html/"/>
<mvc:resources mapping="/QrImages/**" location="/QrImages/"/>
<mvc:resources mapping="/uploadfile/**" location="/uploadfile/"/> -->

    <tx:annotation-driven transaction-manager="transactionManager"/>        <!-- 事务管理支持 -->
    <context:component-scan base-package="com.wxj233"/><!-- 注解支持,添加要扫描的包 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
    </bean>   <!-- 视图解析器 -->
    
    <!-- 定时任务注解支持 -->
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>

    <import resource="classpath:/hibernate_spring.cfg.xml"/><!-- 导入hibernate配置 -->
    <bean id="transactionManager"
            class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean><!-- 事务管理器 -->

    <bean id="conversionService"
            class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
            <property name="converters">
            <set>
                <ref bean="stringToEnumConverter"/>
                <ref bean="stringToIntegerLIstConverter"/>
            </set>
        </property>
    </bean><!-- 数据格式转换器 -->
<bean id="multipartResolver"
        class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
</bean><!-- 文件上传支持 -->

	<websocket:handlers>
        <websocket:mapping path="/socket/qr.do" handler="qrWebSocket"/>
    </websocket:handlers>

</beans>

其中

xmlns:aop="http://www.springframework.org/schema/aop"

http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd


<aop:aspectj-autoproxy/>       <!-- aop支持 -->

为aop配置部分,
声明注解,我使用的是利用注解的方式插入切面,我声明了两个注解如下:
@AfterOperation注解和@BeforeOperation注解

package com.wxj233.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 使用该标签会自动在函数执行完成之后执行日志记录
 * @author wxj233
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterOperation {

	/**
	 * 描述
	 * @return
	 */
	String value() default "";
}
package com.wxj233.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 使用该标签会自动在函数执行完成之前执行日志记录
 * @author wxj233
 *
 */
@Retention(RetentionPolicy.RUNTIME)  //注解声明周期为源文件、class文件及运行时三个时间段都存在
@Target(ElementType.METHOD)  //注解仅用于方法上
public @interface BeforeOperation {

	/**
	 * 描述
	 * @return
	 */
	String value() default "";
}

声明切面如下:
 

package com.wxj233.AOP;

import java.lang.reflect.Method;
import java.util.Date;

import javax.servlet.http.HttpSession;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.wxj233.annotations.AfterOperation;
import com.wxj233.annotations.BeforeOperation;
import com.wxj233.entity.OperationRecord;
import com.wxj233.entity.User;
import com.wxj233.service.OperationRecordService;

@Component
@Aspect
public class OperationRecords {
	
	@Autowired
	HttpSession httpsession;
	@Autowired
	OperationRecordService operationRecordService;

	@Before("@annotation(com.wxj233.annotations.BeforeOperation)")
	public void beforeOperation(JoinPoint jp) {
		MethodSignature methodSignature = (MethodSignature)jp.getSignature();
		Method method = methodSignature.getMethod();
		String operationContent = method.getAnnotation(BeforeOperation.class).value();
		
		User user = (User) httpsession.getAttribute("user");
		if(user != null) {
			OperationRecord operationRecord = new OperationRecord();
			operationRecord.setUser(user);
			operationRecord.setDate(new Date());
			operationRecord.setOperationContent(operationContent);
			operationRecordService.operationRecordSave(operationRecord);
		}
	}
	
	@After("@annotation(com.wxj233.annotations.AfterOperation)")
	public void afterOperation(JoinPoint jp) {
		MethodSignature methodSignature = (MethodSignature)jp.getSignature();
		Method method = methodSignature.getMethod();
		String operationContent = method.getAnnotation(AfterOperation.class).value();
		
		User user = (User) httpsession.getAttribute("user");
		if(user != null) {
			OperationRecord operationRecord = new OperationRecord();
			operationRecord.setUser(user);
			operationRecord.setDate(new Date());
			operationRecord.setOperationContent(operationContent);
			operationRecordService.operationRecordSave(operationRecord);
		}
		
		
		//System.out.println(operationRecord.getId());
	}
}

在control方法上插入如下:
 

package com.wxj233.control;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.wxj233.annotations.AfterOperation;
import com.wxj233.bean.RespResult;
import com.wxj233.dto.FiledPropertyDto;
import com.wxj233.entity.FiledProperty;
import com.wxj233.service.FiledService;

/**
 * 字段
 * @author wxj233
 *
 */
@Controller
@RequestMapping("/filed")
public class FiledControl {
	
	@Autowired
	FiledService filedService;

	/**
	 * 添加字段
	 * @return
	 */
	@RequestMapping("/add")
	@ResponseBody
	@AfterOperation("添加字段")
	RespResult filedAdd(FiledProperty filedProperty, Integer parentid) {
		
		FiledProperty filed = filedService.addFiled(filedProperty, parentid);
		RespResult resp = new RespResult();
		if(filed != null) {
			resp.setFlag(true);
			resp.getData().put("filed", filed);
		}else {
			resp.setFlag(false);
		}
		
		return resp;
	}
	
	@RequestMapping("/edit")
	@ResponseBody
	@AfterOperation("编辑字段")
	RespResult filedEdit(FiledProperty filedProperty) {
		FiledPropertyDto newfiled = filedService.geteditFiledDto(filedProperty);
		RespResult resp = new RespResult();
		
		if(newfiled != null) {
			resp.setFlag(true);
			resp.getData().put("filed", newfiled);
		}else {
			resp.setFlag(false);
		}
		return resp;
	}
	
	@RequestMapping("/delete")
	@ResponseBody
	@AfterOperation("删除字段")
	RespResult filedDelete(Integer[] filedIds) {
		RespResult resp = new RespResult();
		
		if(filedIds.length == 0) {
			resp.setFlag(false);
			return resp;
		}
		
		if(filedService.deleteFileds(filedIds)) {
			resp.setFlag(true);
		}else {
			resp.setFlag(false);
		}
		return resp;
	}
}

实现效果如下:
利用spring AOP实现操作日志功能
用户所有的操作都被记录了下来,仅需要在控制器上加入一个自定义注解就能实现。