SpringBoot中使用AOP實現(xiàn)日志記錄功能
AOP簡介
AOP的全稱是Aspect-Oriented Programming,即面向切面編程(也稱面向方面編程)。它是面向對象編程(OOP)的一種補充,目前已成為一種比較成熟的編程方式。
在傳統(tǒng)的業(yè)務處理代碼中,通常都會進行事務處理、日志記錄等操作。雖然使用OOP可以通過組合或者繼承的方式來達到代碼的重用,但如果要實現(xiàn)某個功能(如日志記錄),同樣的代碼仍然會分散到各個方法中。這樣,如果想要關閉某個功能,或者對其進行修改,就必須要修改所有的相關方法。這不但增加了開發(fā)人員的工作量,而且提高了代碼的出錯率。
為了解決這一問題,AOP思想隨之產生。AOP采取橫向抽取機制,將分散在各個方法中的重復代碼提取出來,然后在程序編譯或運行時,再將這些提取出來的代碼應用到需要執(zhí)行的地方。這種采用橫向抽取機制的方式,采用傳統(tǒng)的OOP思想顯然是無法辦到的,因為OOP只能實現(xiàn)父子關系的縱向的重用。雖然AOP是一種新的編程思想,但卻不是OOP的替代品,它只是OOP的延伸和補充。
創(chuàng)建日志數據庫
創(chuàng)建日志記錄表
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for sys_oper_log -- ---------------------------- DROP TABLE IF EXISTS `sys_oper_log`; CREATE TABLE `sys_oper_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主鍵', `operation` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '操作', `business_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '業(yè)務類型', `method` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '方法名稱', `create_time` datetime(0) NULL DEFAULT NULL COMMENT '操作時間', `oper_name` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '操作用戶', `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '參數', `ip` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '請求的ip地址', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2058 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '操作日志記錄' ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;
創(chuàng)建用戶表
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID', `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名 ', `age` int(11) NULL DEFAULT NULL COMMENT '年齡 ', `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '郵箱 ', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES (2, 'Jack', 20, 'test2@baomidou.com'); INSERT INTO `user` VALUES (3, 'Tom', 28, 'test3@baomidou.com'); INSERT INTO `user` VALUES (4, 'Sandy', 21, 'test4@baomidou.com'); INSERT INTO `user` VALUES (5, 'Billie', 24, 'test5@baomidou.com'); INSERT INTO `user` VALUES (6, 'sss', 18, '123@qq.com'); INSERT INTO `user` VALUES (8, 'sss', 18, '123@qq.com'); SET FOREIGN_KEY_CHECKS = 1;
簡單看一下表格的結構,我這里的數據就不給大家展示了。
SpringBoot使用AOP
一、導入依賴
下邊的三個依賴是我們的核心依賴。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
二、創(chuàng)建我們的項目結構
- 創(chuàng)建UserMapper
@Mapper public interface UserMapper extends BaseMapper<User> { }
- 創(chuàng)建UserService
public interface UserService extends IService<User> { }
- 創(chuàng)建UserServiceImpl
@Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { }
- 創(chuàng)建UserController
@RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @Log(operation = "查找用戶",businessType = BusinessType.LIST) @RequestMapping("/find-user") public String findUser(){ return userService.list().toString(); } }
創(chuàng)建兩個實體
- 創(chuàng)建User
@Data public class User { @TableId(type = IdType.ASSIGN_ID) private Long id; private String name; private Integer age; private String email; }
- 創(chuàng)建SysOperLog
@Data @TableName("sys_oper_log") public class SysOperLog { @TableId(type = IdType.AUTO) private Long id; private String operation; private String businessType; private String method; @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; private String operName; private String params; private String ip; }
三、使用AOP
1.創(chuàng)建枚舉類
這個枚舉類的作用就是記錄我們調用的接口是什么樣的一個類型的,是查找、刪除還是其他。
public enum BusinessType { /** * 其它 */ OTHER, /** * 新增 */ INSERT, /** * 修改 */ UPDATE, /** * 刪除 */ DELETE, /** * 瀏覽 */ LIST }
2..創(chuàng)建Log注解
默認的操作為空,默認的操作類型是OTHER。
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Log { /** * 操作名稱 * @return */ String operation() default ""; /** * 操作的類型 * @return */ BusinessType businessType() default BusinessType.OTHER; }
3.創(chuàng)建切面類
@Aspect @Component public class LogAspect { @Pointcut("@annotation(com.qcby.annotation.Log)") public void pointCut(){} @Autowired HttpServletRequest request; @Autowired SysOperLogMapper sysOperLogMapper; @After(value = "pointCut()") public void afterLogWrite(JoinPoint joinPoint){ // 創(chuàng)建日志對象 SysOperLog sysOperLog = new SysOperLog(); // 獲取我們調用的方法 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); // 獲取方法上的Log注解,因為我們要獲取注解中的一些信息 Log log = method.getAnnotation(Log.class); // 獲取我們調用的類的名稱 String className = joinPoint.getTarget().getClass().getName(); // 獲取調用的方法的名稱 String methodName = method.getName(); // 重新修改一下我們調用的方法 是全路徑的 methodName = className + methodName; // 獲取方法的參數 Object[] args = joinPoint.getArgs(); ObjectMapper objectMapper = new ObjectMapper(); String params = ""; try { params = objectMapper.writeValueAsString(args); } catch (JsonProcessingException e) { e.printStackTrace(); } // 獲取注解中的操作名稱 String operation = log.operation(); // 獲取注解中的操作類型 String businessType = log.businessType().toString(); // 這里的操作人員僅靠后端是寫不了的 需要前端的token認證 我直接把操作人員改為admin String username = "admin"; // 獲取ip地址 String ipAddress = IpUtil.getIpAddr(request); sysOperLog.setBusinessType(businessType); sysOperLog.setOperation(operation); sysOperLog.setMethod(methodName); sysOperLog.setParams(params); sysOperLog.setIp(ipAddress); sysOperLog.setOperName(username); sysOperLog.setCreateTime(LocalDateTime.now()); sysOperLogMapper.insert(sysOperLog); } }
4.IpUtil
public class IpUtil { private static final String UNKNOWN = "unknown"; private static final String LOCALHOST = "127.0.0.1"; private static final String SEPARATOR = ","; public static String getIpAddr(HttpServletRequest request) { System.out.println(request); String ipAddress; try { ipAddress = request.getHeader("x-forwarded-for"); if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) { ipAddress = request.getHeader("WL-Proxy-Client-IP"); } if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) { ipAddress = request.getRemoteAddr(); if (LOCALHOST.equals(ipAddress)) { InetAddress inet = null; try { inet = InetAddress.getLocalHost(); } catch (UnknownHostException e) { e.printStackTrace(); } ipAddress = inet.getHostAddress(); } } // 對于通過多個代理的情況,第一個IP為客戶端真實IP,多個IP按照','分割 // "***.***.***.***".length() if (ipAddress != null && ipAddress.length() > 15) { if (ipAddress.indexOf(SEPARATOR) > 0) { ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); } } } catch (Exception e) { ipAddress = ""; } return ipAddress; } }
5.進行測試
我們在瀏覽器上輸入網址:
127.0.0.1:8080/user/find-user
數據是沒問題的,接下來我們只需要查看數據的日志文件是否插入了日志就好了。
這里我查找了兩次,一次使用的localhost,另一次使用的127.0.0.1。日志可以成功記錄。
以上就是SpringBoot中使用AOP實現(xiàn)日志記錄功能的詳細內容,更多關于SpringBoot AOP日志記錄的資料請關注腳本之家其它相關文章!
- SpringBoot使用TraceId進行日志鏈路追蹤的實現(xiàn)步驟
- SpringBoot使用@Slf4j注解實現(xiàn)日志輸出的示例代碼
- Springboot日志配置的實現(xiàn)示例
- springboot項目配置logback-spring.xml實現(xiàn)按日期歸檔日志的方法
- 在SpringBoot框架中實現(xiàn)打印響應的日志
- SpringBoot項目實現(xiàn)日志打印SQL的常用方法(包括SQL語句和參數)
- Springboot MDC+logback實現(xiàn)日志追蹤的方法
- SpringBoot集成logback打印彩色日志的代碼實現(xiàn)
- springboot 日志實現(xiàn)過程
相關文章
Java?循環(huán)隊列/環(huán)形隊列的實現(xiàn)流程
循環(huán)隊列又叫環(huán)形隊列,是一種特殊的隊列。循環(huán)隊列解決了隊列出隊時需要將所有數據前移一位的問題。本文將帶大家詳細了解循環(huán)隊列如何實現(xiàn),需要的朋友可以參考一下2022-02-02spring mvc 實現(xiàn)獲取后端傳遞的值操作示例
這篇文章主要介紹了spring mvc 實現(xiàn)獲取后端傳遞的值操作,結合實例形式詳細分析了spring mvc使用JSTL 方法獲取后端傳遞的值相關操作技巧2019-11-11解決SpringBoot ClassPathResource的大坑(FileNotFoundException)
這篇文章主要介紹了解決SpringBoot ClassPathResource的大坑(FileNotFoundException),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06