Spring?AOP利用切面實(shí)現(xiàn)日志保存的示例詳解
依賴引入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
創(chuàng)建表
DROP TABLE IF EXISTS `logger_record`; CREATE TABLE `logger_record` ( `id` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'id', `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述', `package_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作所在的包', `class_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作的類名', `method_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作的方法名', `request_params` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '操作方法的參數(shù)', `response_params` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '操作方法的出參', `running_time` bigint NULL DEFAULT NULL COMMENT '運(yùn)行時(shí)間', `created_by` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '創(chuàng)建人ID', `date_created` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;
對(duì)象實(shí)體類
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.**.app.common.util.TimeUtils;
import lombok.Data;
import org.springframework.data.annotation.Id;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;
/**
* Created by cb on 2022/11/15 10:07
*/
//@Entity
@Data
public class LoggerRecord implements Serializable {
@Id
@TableId(value = "id",type = IdType.ID_WORKER_STR)//可不引入注解,UUID生成
private String id;
/**
* 操作方法的描述
*/
private String description;//實(shí)際沒用上
/**
* 操作所在的包
*/
private String packageName;
/**
* 操作的類名
*/
private String className;
/**
* 操作的方法名
*/
private String methodName;
/**
* 操作方法的參數(shù)
*/
private String requestParams;
/**
* 操作方法的出參
*/
private String responseParams;
/**
* 運(yùn)行時(shí)間
*/
private Long runningTime;
/** 創(chuàng)建時(shí)間 */
@JsonFormat(pattern = TimeUtils.PATTERN2)
private LocalDateTime dateCreated;//可以用date
/** 創(chuàng)建人ID */
private String createdBy;//實(shí)際沒用上
}注解方法
package com.**.app.server.annotation;
import java.lang.annotation.*;
/**
* Created by cb on 2022/11/15 10:05
* 日志描述的注解
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LoggerManager {
}service方法
可根據(jù)自己項(xiàng)目去相應(yīng)改動(dòng)
/**
* 日志增刪改的接口
* Created by cb on 2022/11/15 10:11
*/
@Service
public class LoggerRecordRepository extends ServiceImpl<LoggerRecordMapper, LoggerRecord> {
}工具類
package com.**.app.server.util;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* Created by cb on 2022/11/15 10:24
*/
public class AopUtil {
/**
* 獲取切點(diǎn)處的方法
* @param joinPoint
* @return
*/
public static Method getMethod(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
return method;
}
/**
// * 將參數(shù)數(shù)組轉(zhuǎn)化為字符串
// * @param params 參數(shù)數(shù)組
// * @return 參數(shù)字符串
// */
public static String getStringOfParams(Object[] params) {
if (params.length <= 0 || params.length > 1024 || null == params) {
return "";
}
StringBuffer paramString = new StringBuffer("參數(shù): ");
for (Object param : params) {
//將參數(shù)轉(zhuǎn)換成字符串
String s = ToStringBuilder.reflectionToString(param);
paramString.append(s).append("||");
}
return paramString.toString();
}
/**
* 轉(zhuǎn)換request 請(qǐng)求參數(shù)
* @param paramMap request獲取的參數(shù)數(shù)組
*/
public static Map<String, String> converMap(Map<String, String[]> paramMap) {
Map<String, String> rtnMap = new HashMap<String, String>();
for (String key : paramMap.keySet()) {
rtnMap.put(key, paramMap.get(key)[0]);
}
return rtnMap;
}
}注解實(shí)現(xiàn)方法
package com.**.app.server.annotation;
import com.alibaba.fastjson.JSON;
import com.**.app.server.entity.log.LoggerRecord;
import com.**.app.server.service.LoggerRecordRepository;
import com.**.app.server.util.AopUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;
/**
* Created by cb on 2022/11/15 10:19
*/
@Aspect
@Service
@Slf4j
public class LoggerAdvice {
@Resource
private LoggerRecordRepository loggerRecordRepository;
/**
* 切點(diǎn),在注解處切入
*/
@Pointcut("@annotation(com.safety.app.server.annotation.LoggerManager)")
public void AroundPointCut(){
}
/**
* 環(huán)繞通知 @Around , 當(dāng)然也可以使用 @Before (前置通知) @After (后置通知)
* @param point
* @return
* @throws Throwable
*/
@Around("AroundPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
Object result = point.proceed();
long time = System.currentTimeMillis() - beginTime;
try {
LoggerRecord loggerRecord = saveLog(point, time);
loggerRecord.setResponseParams(JSON.toJSONString(result));
loggerRecordRepository.save(loggerRecord);
} catch (Exception e) {
}finally {
return result;
}
}
/**
* 保存日志
* @param joinPoint
* @param time
*/
private LoggerRecord saveLog(ProceedingJoinPoint joinPoint, long time) {
// 獲取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 從獲取RequestAttributes中獲取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
//獲取該切點(diǎn)處的方法
Method method = AopUtil.getMethod(joinPoint);
LoggerRecord loggerRecord = new LoggerRecord();
//獲取切點(diǎn)處的注解
LoggerManager loggerManager = method.getAnnotation(LoggerManager.class);
if (null == loggerManager) {
return loggerRecord;
}
//獲取請(qǐng)求的描述
// String description = loggerManager.
//獲取請(qǐng)求包名
Signature signature = joinPoint.getSignature();
//獲取請(qǐng)求的類名
String className = joinPoint.getTarget().getClass().getName();
//獲取請(qǐng)求的方法名
String methodName = method.getName();
//獲取請(qǐng)求的參數(shù)
Map<String, String[]> parameterMap = request.getParameterMap();
Map<String, String> stringStringMap = AopUtil.converMap(parameterMap);
log.info("執(zhí)行===" + methodName + "===開始");
//打印方法名
log.info("方法名:" + signature.toString());
//打印方法參數(shù)
log.info("方法參數(shù):" + JSON.toJSONString(stringStringMap));
log.info("執(zhí)行===" + methodName + "===結(jié)束");
//將日志保存
// loggerRecord.setDescription(description);
loggerRecord.setPackageName(signature.toString());
loggerRecord.setClassName(className);
loggerRecord.setMethodName(methodName);
loggerRecord.setRunningTime(time);
loggerRecord.setRequestParams(JSON.toJSONString(stringStringMap));
return loggerRecord;
}
}最后只需要在自己的接口上加注解@LoggerManager就可以實(shí)現(xiàn)此方法的入?yún)⒊鰠⑷罩颈4?/p>
/**
* 測(cè)試
*/
@GetMapping("/test")
@ResponseBody
@LoggerManager
public ResponseResult test(@RequestParam("userName") String userName) throws BusinessException {
Map<String, Object> verifyCodeMap = VerifyCodeUtils.verifyCode();
redisUtils.set(VERIFY_CODE + userName, verifyCodeMap, 60);
return new ResponseResult(verifyCodeMap);
}保存數(shù)據(jù)庫后的圖片:

注:所有‘**’的地方為自己項(xiàng)目的包名。 好了,下期會(huì)改版此日志保存方法,在數(shù)據(jù)庫配置接口名稱 就可以實(shí)現(xiàn)日志的打印保存。
到此這篇關(guān)于Spring AOP利用切面實(shí)現(xiàn)日志保存的示例詳解的文章就介紹到這了,更多相關(guān)Spring AOP切面實(shí)現(xiàn)日志保存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring實(shí)現(xiàn)IoC和DI的方法詳解
IoC全稱Inversion of Control (控制反轉(zhuǎn)) ,這里的控制其實(shí)是控制權(quán)的意思,可以理解為對(duì)象的獲取權(quán)力和方式發(fā)生了發(fā)轉(zhuǎn),DI依賴注?是?個(gè)過程,是指IoC容器在創(chuàng)建Bean時(shí), 去提供運(yùn)?時(shí)所依賴的資源,?資源指的就是對(duì)象,本文介紹了Spring實(shí)現(xiàn)IoC和DI的方法2024-08-08
新手小白入門必學(xué)JAVA面向?qū)ο笾鄳B(tài)
說到多態(tài),一定離不開其它兩大特性:封裝和繼承,下面這篇文章主要給大家介紹了關(guān)于新手小白入門必學(xué)JAVA面向?qū)ο笾鄳B(tài)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-02-02
Spring中Bean創(chuàng)建完后打印語句的兩種方法
這篇文章主要介紹了Spring中Bean創(chuàng)建完后打印語句的兩種方法,一個(gè)是實(shí)現(xiàn)InitializingBean接口,另一個(gè)使用@Bean注解和initMethod屬性,通過代碼示例介紹的非常詳細(xì),感興趣的小伙伴可以參考閱讀2023-07-07
mybatis typeAliases 給實(shí)體類起別名的方法
這篇文章主要介紹了mybatis typeAliases 給實(shí)體類起別名,本文給大家分享兩種用法,通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
如何將eclipse項(xiàng)目導(dǎo)入到idea的方法步驟(圖文)
這篇文章主要介紹了如何將eclipse項(xiàng)目導(dǎo)入到idea的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
springboot+redis+lua實(shí)現(xiàn)分布式鎖的腳本
本文介紹了如何使用Spring Boot、Redis和Lua腳本實(shí)現(xiàn)分布式鎖,包括實(shí)現(xiàn)原理、代碼實(shí)現(xiàn)和存在的問題,感興趣的朋友跟隨小編一起看看吧2024-11-11
SpringBoot集成POI導(dǎo)出Execl表格之統(tǒng)一工具類
這篇文章主要為大家詳細(xì)介紹了SpringBoot集成POI導(dǎo)出Execl表格之統(tǒng)一工具類,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09

