Spring?AOP利用切面實現(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 '運行時間', `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)建時間', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;
對象實體類
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;//實際沒用上 /** * 操作所在的包 */ private String packageName; /** * 操作的類名 */ private String className; /** * 操作的方法名 */ private String methodName; /** * 操作方法的參數(shù) */ private String requestParams; /** * 操作方法的出參 */ private String responseParams; /** * 運行時間 */ private Long runningTime; /** 創(chuàng)建時間 */ @JsonFormat(pattern = TimeUtils.PATTERN2) private LocalDateTime dateCreated;//可以用date /** 創(chuàng)建人ID */ private String createdBy;//實際沒用上 }
注解方法
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ù)自己項目去相應(yī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 { /** * 獲取切點處的方法 * @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 請求參數(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; } }
注解實現(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; /** * 切點,在注解處切入 */ @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); //獲取該切點處的方法 Method method = AopUtil.getMethod(joinPoint); LoggerRecord loggerRecord = new LoggerRecord(); //獲取切點處的注解 LoggerManager loggerManager = method.getAnnotation(LoggerManager.class); if (null == loggerManager) { return loggerRecord; } //獲取請求的描述 // String description = loggerManager. //獲取請求包名 Signature signature = joinPoint.getSignature(); //獲取請求的類名 String className = joinPoint.getTarget().getClass().getName(); //獲取請求的方法名 String methodName = method.getName(); //獲取請求的參數(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就可以實現(xiàn)此方法的入?yún)⒊鰠⑷罩颈4?/p>
/** * 測試 */ @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ù)庫后的圖片:
注:所有‘**’的地方為自己項目的包名。 好了,下期會改版此日志保存方法,在數(shù)據(jù)庫配置接口名稱 就可以實現(xiàn)日志的打印保存。
到此這篇關(guān)于Spring AOP利用切面實現(xiàn)日志保存的示例詳解的文章就介紹到這了,更多相關(guān)Spring AOP切面實現(xiàn)日志保存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis3中方法返回生成的主鍵:XML,@SelectKey,@Options詳解
這篇文章主要介紹了Mybatis3中方法返回生成的主鍵:XML,@SelectKey,@Options,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01文件上傳SpringBoot后端MultipartFile參數(shù)報空問題的解決辦法
這篇文章主要介紹了文件上傳SpringBoot后端MultipartFile參數(shù)報空問題的解決辦法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11mybatis調(diào)用存儲過程,帶in、out參數(shù)問題
這篇文章主要介紹了mybatis調(diào)用存儲過程,帶in、out參數(shù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01使用Java開發(fā)實現(xiàn)OAuth安全認(rèn)證的應(yīng)用
這篇文章主要介紹了使用Java開發(fā)實現(xiàn)OAuth安全認(rèn)證的應(yīng)用的方法,OAuth安全認(rèn)證經(jīng)常出現(xiàn)于社交網(wǎng)絡(luò)API應(yīng)用的相關(guān)開發(fā)中,需要的朋友可以參考下2015-11-11Java數(shù)據(jù)結(jié)構(gòu)之隊列與OJ題
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之隊列與OJ題,本文章先是對隊列進行介紹,后又介紹了四道OJ相關(guān)的題目,來使其深入理解,需要的朋友可以參考下2023-01-01