springboot-aop面向切面程式設計
阿新 • • 發佈:2019-01-03
需求:
專案中需要記錄使用者操作資訊,例如使用者登陸系統後做了那些操作,需要有具體的日誌記錄。
解決辦法:
1、編寫操作記錄日誌業務類,在使用的方法中呼叫(一般記錄方式)。
2、使用面向切面方式記錄日誌,例如針對某些業務處理方法進行日誌記錄。
3、通過註解方式,在呼叫的業務方法上增加日誌類註解。
推薦使用第二、第三中方式,使用靈活,如果不需要日誌記錄,將切面取消即可,第一種不夠靈活。一些介紹使用註解方式編寫日誌記錄。
專案結構如下:
在pom.xml匯入依賴包
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"在application.properties配置檔案中增加資料庫連線xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example.springboot</groupId> <artifactId>springboot-aop</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot-aop</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.12.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.7</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- log4j 日誌記錄 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> <version>1.3.5.RELEASE</version> </dependency> <!--aop依賴包--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- 引入mybatis 資料庫操作包 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- 引入mybatis 分頁外掛 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>4.1.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
#server.port=8090 #標示使用的是mysql/oracle/sqlserver datasource.type=mysql #mysql資料連線 spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.username=root spring.datasource.password=root #spring.datasource.max-active=20 #spring.datasource.max-idle=8 #spring.datasource.min-idle=8 #spring.datasource.initial-size=20 #mybatis 配置 # 配置對映檔案載入 mybatis.mapper-locations=classpath*:mapper/**/*.xml # 實體類通過別名使用 #mybatis.type-aliases-package=
自定義註解類
package com.example.springboot.aop.annotation; import java.lang.annotation.*; /** *自定義註解 攔截Controller */ @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface SystemControllerLog { String LogAction() default ""; String LogContent() default ""; int ModuleID() default 0; }
實體類
package com.example.springboot.aop.entity; public class SystemLogModel { private String LogAction; private String LogContent; private String FlagID; private String FlagName; private String LogIP; private String TimeFlag; private int ModuleID;
自定義切面類
package com.example.springboot.aop.aspect; import com.example.springboot.aop.annotation.SystemControllerLog; import com.example.springboot.aop.dao.SystemLogMapper; import com.example.springboot.aop.entity.SystemLogModel; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date; /** * 切點類 */ @Aspect @Component public class SystemLogAspect { // 本地異常日誌記錄物件 private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class); @Autowired private SystemLogMapper systemLogMapper; // Controller層切點,針對在業務模組標註SystemControllerLog註解記錄日誌 @Pointcut("@annotation( com.example.springboot.aop.annotation.SystemControllerLog )") public void controllerAspect() { } /** * 前置通知 用於攔截Controller層記錄使用者的操作 * * @param joinPoint 切點 */ @Before("controllerAspect()") public void doBefore(JoinPoint joinPoint) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); try { // 請求的IP String logIP = request.getHeader("X-Real-IP"); // if (StringUtils.isEmpty(logIP)) { // logIP = request.getRemoteAddr(); // } String userID = request.getParameter("UserID"); String userName = request.getParameter("UserName"); // if (StringUtils.isEmpty(userID) || StringUtils.isEmpty(userName)) { // logger.debug("操作日誌-->日誌新增:使用者名稱或使用者ID為空,返回不新增日誌!"); // return; // } SystemLogModel slm = getControllerMethodDescription(joinPoint); slm.setLogIP(logIP); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss"); String date = dateFormat.format(new Date()); slm.setTimeFlag(date); slm.setFlagID(userID); slm.setFlagName(userName); // *========控制檯輸出=========*// logger.debug("=====註解引數獲取開始====="); logger.debug("請求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")); logger.debug("操作模組:" + slm.getModuleID()); logger.debug("操作方法:" + slm.getLogAction()); logger.debug("操作內容:" + slm.getLogContent()); logger.debug("請求IP:" + slm.getLogIP()); logger.debug("FlagID:" + slm.getFlagID()); logger.debug("FlagName:" + slm.getFlagName()); // *========資料庫日誌=========*// int res = systemLogMapper.saveOrUpdate(slm); if (res > 0) { logger.info(">>>>>>>>儲存日誌成功"); } } catch (Exception e) { // 記錄本地異常日誌 logger.error("前置通知異常,儲存日誌異常資訊:{}", e.getMessage()); } } /** * 獲取註解中對方法的描述資訊 用於Controller層註解 * * @param joinPoint 切點 * @return 方法描述 * @throws Exception */ public static SystemLogModel getControllerMethodDescription( JoinPoint joinPoint) throws Exception { String targetName = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); Class targetClass = Class.forName(targetName); Method[] methods = targetClass.getMethods(); String description = ""; SystemControllerLog log; SystemLogModel logM = new SystemLogModel(); for (Method method : methods) { if (method.getName().equals(methodName)) { Class[] clazzs = method.getParameterTypes(); if (clazzs.length == arguments.length) { log = method.getAnnotation(SystemControllerLog.class); logM.setModuleID(log.ModuleID()); logM.setLogAction(log.LogAction()); logM.setLogContent(log.LogContent()); break; } } } return logM; } }
mapper介面
package com.example.springboot.aop.dao; import com.example.springboot.aop.entity.SystemLogModel; import org.apache.ibatis.annotations.Mapper; @Mapper public interface SystemLogMapper { //儲存日誌 public int saveOrUpdate(SystemLogModel systemLogModel); }mapper配置檔案
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.springboot.aop.dao.SystemLogMapper"> <insert id="saveOrUpdate" parameterType="com.example.springboot.aop.entity.SystemLogModel"> insert into test_system_Operation_log(FlagID,FlagName,LogAction,LogContent,LogIP,ModuleID,TimeFlag) values(#{FlagID},#{FlagName},#{LogAction},#{LogContent},#{LogIP},#{ModuleID},#{TimeFlag}) </insert> </mapper>
建立controller類
package com.example.springboot.aop.controller; import com.example.springboot.aop.annotation.SystemControllerLog; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; /** * @desc aop測試日誌記錄 * @Author wangsh * @date 2018/5/7 20:57 */ @RestController @RequestMapping("/aop") public class AopController { @SystemControllerLog(LogAction = "查詢", ModuleID = 12, LogContent = "測試aop示例") @ResponseBody @RequestMapping("/hello") public String hello() { return "hello"; } }
建立啟動服務類
package com.example.springboot.aop; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; //配置掃描指定的包及包下的所以子集 @ComponentScan("com.example.springboot.aop") @SpringBootApplication public class SpringbootAopApplication { public static void main(String[] args) { SpringApplication.run(SpringbootAopApplication.class, args); } }啟動服務測試
瀏覽器訪問: http://localhost:8080//aop/hello
檢視資料庫記錄:
以上就是aop切面及註解的使用。