国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SpringBoot項目如何優(yōu)雅的實現(xiàn)操作日志記錄

這篇具有很好參考價值的文章主要介紹了SpringBoot項目如何優(yōu)雅的實現(xiàn)操作日志記錄。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

SpringBoot項目如何優(yōu)雅的實現(xiàn)操作日志記錄

前言

在實際開發(fā)當中,對于某些關鍵業(yè)務,我們通常需要記錄該操作的內(nèi)容,一個操作調一次記錄方法,每次還得去收集參數(shù)等等,會造成大量代碼重復。 我們希望代碼中只有業(yè)務相關的操作,在項目中使用注解來完成此項功能。

通常就是使用Spring中的AOP特性來實現(xiàn)的,那么在SpringBoot項目當中應該如何來實現(xiàn)呢?


一、AOP是什么?

AOP(Aspect-Oriented Programming:?向切?編程),說起AOP,幾乎學過Spring框架的人都知道,它是Spring的三大核心思想之一(IOC:控制反轉,DI:依賴注入,AOP:面向切面編程)。能夠將那些與業(yè)務?關,卻為業(yè)務模塊所共同調?的邏輯或責任(例如事務處理、?志管理、權限控制等)封裝起來,便于減少系統(tǒng)的重復代碼,降低模塊間的耦合度,并有利于未來的可拓展性和可維護性。

二、AOP做了什么?

簡單說來,AOP主要做三件事:

  • 1、在哪里切入,也就是日志記錄等非業(yè)務代碼在哪些業(yè)務代碼中執(zhí)行。
  • 2、在什么時候切入,是在業(yè)務代碼執(zhí)行前還是后。
  • 3、切入后做什么事情,比如權限校驗,日志記錄等。

可以用一張圖來理解: SpringBoot項目如何優(yōu)雅的實現(xiàn)操作日志記錄,spring boot,java,后端 圖上的一個核心術語的說明:

  • Pointcut切點,決定在何處切入業(yè)務代碼中(即織入切面)。切點分為execution方式和annotation方式。execution方式:可以用路徑表達式指定哪些類織入切面,annotation方式:可以指定被哪些注解修飾的代碼織入切面。
  • Advice處理,包括處理時機和處理內(nèi)容。處理內(nèi)容就是要做什么事,比如校驗權限和記錄日志。處理時機就是在什么時機執(zhí)行處理內(nèi)容,分為前置處理(即業(yè)務代碼執(zhí)行前)、后置處理(業(yè)務代碼執(zhí)行后)等。
  • Aspect切面,即Pointcut和Advice。
  • Joint point連接點,是程序執(zhí)行的一個點。例如,一個方法的執(zhí)行或者一個異常的處理。在 Spring AOP 中,一個連接點總是代表一個方法執(zhí)行。
  • Weaving織入,就是通過動態(tài)代理,在目標對象方法中執(zhí)行處理內(nèi)容的過程。

三、實現(xiàn)步驟

(1)自定義一個注解@Log (2)創(chuàng)建一個切面類,切點設置為攔截標注@Log的方法,截取傳參,進行日志記錄 (3)將@Log標注在接口上

具體的實現(xiàn)步驟如下:

1. 添加AOP依賴

代碼如下(示例):

java復制代碼 <dependency>
   	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 自定義一個日志注解

日志一般使用的是注解類型的切點表達式,我們先創(chuàng)建一個日志注解,當spring容器掃描到有此注解的方法就會進行增強。代碼如下(示例):

java復制代碼
@Target({ ElementType.PARAMETER, ElementType.METHOD }) // 注解放置的目標位置,PARAMETER: 可用在參數(shù)上  METHOD:可用在方法級別上
@Retention(RetentionPolicy.RUNTIME)    // 指明修飾的注解的生存周期  RUNTIME:運行級別保留
@Documented
public @interface Log {

    /**
     * 模塊
     */
    String title() default "";

    /**
     * 功能
     */
    public BusinessType businessType() default BusinessType.OTHER;

    /**
     * 是否保存請求的參數(shù)
     */
    public boolean isSaveRequestData() default true;

    /**
     * 是否保存響應的參數(shù)
     */
    public boolean isSaveResponseData() default true;
}

3. 切面聲明

申明一個切面類,并交給Spring容器管理。代碼如下(示例):

java復制代碼
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Autowired
    private IXlOperLogService operLogService;

    /**
     * 處理完請求后執(zhí)行
     * @param joinPoint 切點
     */
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doAfterReturnibng(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
        handleLog(joinPoint, controllerLog, null, jsonResult);
    }

    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
        try {
            // 獲取當前的用戶
            JwtUser loginUser = SecurityUtils.getLoginUser();

            // 日志記錄
            XlOperLog operLog = new XlOperLog();
            operLog.setStatus(0);
            // 請求的IP地址
            String iP = ServletUtil.getClientIP(ServletUtils.getRequest());
            if ("0:0:0:0:0:0:0:1".equals(iP)) {
                iP = "127.0.0.1";
            }
            operLog.setOperIp(iP);
            operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
            if (loginUser != null) {
                operLog.setOperName(loginUser.getUsername());
            }
            if (e != null) {
                operLog.setStatus(1);
                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
            }
            // 設置方法名稱
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            operLog.setMethod(className + "." + methodName + "()");
            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
            operLog.setOperTime(new Date());
            // 處理設置注解上的參數(shù)
            getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
            // 保存數(shù)據(jù)庫
            operLogService.save(operLog);

        } catch (Exception exp) {
            log.error("異常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }

    /**
     * 獲取注解中對方法的描述信息 用于Controller層注解
     * @param log 日志
     * @param operLog 操作日志
     * @throws Exception
     */
    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, XlOperLog operLog, Object jsonResult) throws Exception {
        // 設置操作業(yè)務類型
        operLog.setBusinessType(log.businessType().ordinal());
        // 設置標題
        operLog.setTitle(log.title());
        // 是否需要保存request,參數(shù)和值
        if (log.isSaveRequestData()) {
            // 設置參數(shù)的信息
            setRequestValue(joinPoint, operLog);
        }
        // 是否需要保存response,參數(shù)和值
        if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult)) {
            operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
        }
    }

    /**
     * 獲取請求的參數(shù),放到log中
     * @param operLog 操作日志
     * @throws Exception 異常
     */
    private void setRequestValue(JoinPoint joinPoint, XlOperLog operLog) throws Exception {
        String requsetMethod = operLog.getRequestMethod();
        if (HttpMethod.PUT.name().equals(requsetMethod) || HttpMethod.POST.name().equals(requsetMethod)) {
            String parsams = argsArrayToString(joinPoint.getArgs());
            operLog.setOperParam(StringUtils.substring(parsams,0,2000));
        } else {
            Map<?,?> paramsMap = (Map<?,?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            operLog.setOperParam(StringUtils.substring(paramsMap.toString(),0,2000));
        }
    }

    /**
     * 參數(shù)拼裝
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (Object object : paramsArray) {
                // 不為空 并且是不需要過濾的 對象
                if (StringUtils.isNotNull(object) && !isFilterObject(object)) {
                    Object jsonObj = JSON.toJSON(object);
                    params += jsonObj.toString() + " ";
                }
            }
        }
        return params.trim();
    }

    /**
     * 判斷是否需要過濾的對象。
     * @param object 對象信息。
     * @return 如果是需要過濾的對象,則返回true;否則返回false。
     */
    @SuppressWarnings("rawtypes")
    public boolean isFilterObject(final Object object) {
        Class<?> clazz = object.getClass();
        if (clazz.isArray()) {
            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection collection = (Collection) object;
            for (Object value : collection) {
                return value instanceof MultipartFile;
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) object;
            for (Object value : map.entrySet()) {
                Map.Entry entry = (Map.Entry) value;
                return entry.getValue() instanceof MultipartFile;
            }
        }
        return object instanceof MultipartFile || object instanceof HttpServletRequest
                || object instanceof HttpServletResponse || object instanceof BindingResult;
    }
}

4. 標注在接口上

將自定義注解標注在需要記錄操作日志的接口上,代碼如下(示例):

java復制代碼	@Log(title = "代碼生成", businessType = BusinessType.GENCODE)
    @ApiOperation(value = "批量生成代碼")
    @GetMapping("/download/batch")
    public void batchGenCode(HttpServletResponse response, String tables) throws IOException {
        String[] tableNames = Convert.toStrArray(tables);
        byte[] data = genTableService.downloadCode(tableNames);
        genCode(response, data);
    }

5. 實現(xiàn)的效果

執(zhí)行相關操作就會記錄日志,記錄了一些基礎信息存在數(shù)據(jù)表里。 SpringBoot項目如何優(yōu)雅的實現(xiàn)操作日志記錄,spring boot,java,后端


總結

好了,以上就是本篇文章的主要內(nèi)容了,本文主要講述了使用SpringAOP來實現(xiàn)操作日志的記錄,歡迎評論區(qū)留言,說說你們的項目中是如何實現(xiàn)操作日志的。

若覺得本文對您有幫助的話,還不忘點贊評論關注,支持一波喲~文章來源地址http://www.zghlxwxcb.cn/news/detail-800439.html

到了這里,關于SpringBoot項目如何優(yōu)雅的實現(xiàn)操作日志記錄的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • SpringBoot 項目優(yōu)雅實現(xiàn)讀寫分離

    當使用Spring Boot開發(fā)數(shù)據(jù)庫應用時,讀寫分離是一種常見的優(yōu)化策略。讀寫分離將讀操作和寫操作分別分配給不同的數(shù)據(jù)庫實例,以提高系統(tǒng)的吞吐量和性能。 讀寫分離實現(xiàn)主要是通過動態(tài)數(shù)據(jù)源功能實現(xiàn)的,動態(tài)數(shù)據(jù)源是一種通過在運行時動態(tài)切換數(shù)據(jù)庫連接的機制。它允

    2024年02月05日
    瀏覽(15)
  • 如何在 MySQL 中開啟日志記錄并排查操作記錄

    如何在 MySQL 中開啟日志記錄并排查操作記錄

    在數(shù)據(jù)庫管理中,能夠追蹤和審查操作記錄是至關重要的。這不僅有助于識別和分析正常的數(shù)據(jù)庫活動,還可以在數(shù)據(jù)泄露或未經(jīng)授權的更改發(fā)生時進行調查和響應。本文將介紹如何在 MySQL 中開啟通用日志記錄,并如何排查操作記錄。 通用日志記錄了發(fā)往 MySQL 服務器的每一

    2024年04月12日
    瀏覽(40)
  • P02項目診斷報警組件(學習操作日志記錄、單元測試開發(fā))

    P02項目診斷報警組件(學習操作日志記錄、單元測試開發(fā))

    ★ P02項目診斷報警組件 診斷報警組件的主要功能有: 接收、記錄硬件設備上報的報警信息。 從預先設定的錯誤碼對照表中找到對應的聲光報警和蜂鳴器報警策略,結合當前的報警情況對設備下發(fā)報警指示。 將報警消息發(fā)送到消息隊列,由其它組件發(fā)送給前端。 從消息隊列

    2024年02月04日
    瀏覽(21)
  • Springboot項目怎么設計業(yè)務操作日志功能?

    Springboot項目怎么設計業(yè)務操作日志功能?

    ? 很久以前都想寫這篇文章,一直沒有空,但直到現(xiàn)在我對當時的情景還有印象,之所以有印象是因為需求很簡單,業(yè)務操作日志的記錄與查詢的功能,但是具體實現(xiàn)真的很爛,具體的爛法會在反面示例里細說,領導以及客戶層面很認可,一系列迷之操作,讓我印象深刻。

    2023年04月16日
    瀏覽(26)
  • 實現(xiàn)用戶操作日志記錄

    實現(xiàn)用戶操作日志記錄

    java自帶的日志框架是java.util.logging(JUL),從JDK1.4(2002)開始捆綁在JDK中。可以使用JUL來記錄操作日志。以下是使用JUL記錄事務的示例: 系統(tǒng)日志 :統(tǒng)日志主要是為開發(fā)排查問題提供依據(jù),一般打印在日志文件中;系統(tǒng)日志的可讀性要求沒那么高,日志中會包含代碼的信息

    2024年02月15日
    瀏覽(19)
  • SpringBoot實現(xiàn)文件記錄日志,日志文件自動歸檔和壓縮

    SpringBoot實現(xiàn)文件記錄日志,日志文件自動歸檔和壓縮

    ?? @ 作者: Eric ?? @ 主頁: https://blog.csdn.net/weixin_47316183?type=blog ?? @ 主題: SpringBoot實現(xiàn)文件記錄日志,日志文件自動歸檔和壓縮 ?? @ 創(chuàng)作時間: 2023年08月06日 Logback 是一個Java日志框架,它是 log4j 的后繼者,被廣泛用于應用程序中記錄日志。 Logger(日志記錄器): L

    2024年02月14日
    瀏覽(21)
  • SpringBoot如何優(yōu)雅的實現(xiàn)異步調用?

    Spring Boot 提供了多種方式來實現(xiàn)異步任務,這里介紹三種主要實現(xiàn)方式。 Spring Boot 提供了多種方式來實現(xiàn)異步任務,這里介紹三種實現(xiàn)方式。 @Async 注解是 Spring 提供的一種輕量級異步方法實現(xiàn)方式,它可以標記在方法上,用來告訴 Spring 這個方法是一個異步方法,Spring 會將

    2024年02月07日
    瀏覽(15)
  • 【SpringBoot系列】如何優(yōu)雅地實現(xiàn)異步調用

    【SpringBoot系列】如何優(yōu)雅地實現(xiàn)異步調用

    1.前言 在現(xiàn)代的應用程序開發(fā)中,異步調用是提高系統(tǒng)性能和響應能力的重要手段之一。 Spring Boot作為一個快速開發(fā)框架,提供了多種方式來實現(xiàn)異步調用,使得開發(fā)者能夠更加優(yōu)雅地處理并發(fā)和異步任務。 本文將介紹如何在Spring Boot中實現(xiàn)異步調用的方法和技巧,幫助開發(fā)

    2024年02月07日
    瀏覽(25)
  • SpringBoot如何優(yōu)雅的實現(xiàn)重試功能

    在有些特定場景,如和第三方對接。 我們調用接口時需要支持重試功能,第一次調用沒成功,我們需要等待x秒后再次調用。 通常會設置重試次數(shù),避免業(yè)務。 一般我們會這樣寫 這樣寫本身,沒什么問題。 但是如果多個接口都需要重試的話,代碼就不優(yōu)雅了。 spring系列的

    2024年02月08日
    瀏覽(22)
  • 三步實現(xiàn)SpringBoot全局日志記錄,整合Echarts實現(xiàn)數(shù)據(jù)大屏

    三步實現(xiàn)SpringBoot全局日志記錄,整合Echarts實現(xiàn)數(shù)據(jù)大屏

    ?? 注重版權,轉載請注明原作者和原文鏈接 小袁博客:https://boke.open-yuan.com/ 小袁博客后臺:https://boke.open-yuan.com/back-manager/ 更多項目內(nèi)容關注小紅書??OpenYuan開袁 http://xhslink.com/I9zNaC 有需求可以在小袁博客首頁加我微信或者QQ 建表 POJO實體 Mapper接口 自定義注解 案例: 攔截

    2024年03月08日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包