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

spring boot 使用AOP+自定義注解+反射實現(xiàn)操作日志記錄修改前數(shù)據(jù)和修改后對比數(shù)據(jù),并保存至日志表

這篇具有很好參考價值的文章主要介紹了spring boot 使用AOP+自定義注解+反射實現(xiàn)操作日志記錄修改前數(shù)據(jù)和修改后對比數(shù)據(jù),并保存至日志表。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、添加aop starter依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

二:自定義字段翻譯注解。(修改功能時,需要顯示如某字段修改前為張三,修改后為李四,name字段對應(yīng)的中文注釋)

package com.test.common.annotation;

import java.lang.annotation.*;

/**
 * 寫入日志表時,字段對應(yīng)的中文注釋
 */
@Retention(RetentionPolicy.RUNTIME) // 注解會在class字節(jié)碼文件中存在,在運行時可以通過反射獲取到
@Target({ElementType.FIELD,ElementType.METHOD})//定義注解的作用目標(biāo)**作用范圍字段、枚舉的常量/方法
@Documented                 //說明該注解將被包含在javadoc中
public @interface FieldMeta {
    /**
     * 漢字全稱
     * @return
     */
    String value();
}

使用FieldMeta自定義注解,看個人業(yè)務(wù)自行覺得是否需要重新定義實體

package com.test.customer.domain;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.test.common.annotation.FieldMeta;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.test.common.core.domain.BaseEntity;


public class TestDangAnDetail extends BaseEntity {
    private static final long serialVersionUID = 1L;

    /**
     * 次數(shù)
     */
   
    @FieldMeta("總次數(shù)")
    private Long CountNum;
    
}

parseClass調(diào)用查詢方法的類(查詢數(shù)據(jù)工具類)

//抽象類
public interface ContentParser {
    
        /**
         * 獲取信息返回查詢出的對象
         *
         * @param joinPoint       查詢條件的參數(shù)
         * @param dbAccessLogger 注解
         * @return 獲得的結(jié)果
         */
        Object getOldResult(JoinPoint joinPoint, DBAccessLogger dbAccessLogger,String sqlSessionFactoryName);
    
        /**
         * 獲取信息返回查詢出的對象
         *
         * @param joinPoint       查詢條件的參數(shù)
         * @param dbAccessLogger 注解
         * @return 獲得的結(jié)果
         */
        Object getNewResult(JoinPoint joinPoint, DBAccessLogger dbAccessLogger,String sqlSessionFactoryName);
    
    }

實現(xiàn)類 :通過該實現(xiàn)類獲取更新前后的數(shù)據(jù)。
該實現(xiàn)類的實現(xiàn)原理為:獲取入?yún)⒊鋈氲膇d值,獲取sqlSessionFactory,通過sqlSessionFactory獲取selectByPrimaryKey()該方法,執(zhí)行該方法可獲取id對應(yīng)數(shù)據(jù)更新操作前后的數(shù)據(jù)。

    @Component
    public class DefaultContentParse implements ContentParser {
        /**
         * 獲取更新方法的第一個參數(shù)解析其id
         * @param joinPoint       查詢條件的參數(shù)
         * @param enableModifyLog 注解類容
         * @return
         */
        @Override
        public Object getOldResult(JoinPoint joinPoint, DBAccessLogger enableModifyLog,String sqlSessionFactoryName) {
            Object info = joinPoint.getArgs()[0];
            Object id = ReflectionUtils.getFieldValue(info, "id");
            Assert.notNull(id,"未解析到id值,請檢查入?yún)⑹欠裾_");
            Class<?> aClass = enableModifyLog.serviceClass();
            Object result = null;
            try {
                SqlSessionFactory sqlSessionFactory = SpringUtil.getBean(sqlSessionFactoryName);
                Object instance = Proxy.newProxyInstance(
                        aClass.getClassLoader(),
                        new Class[]{aClass},
                        new MyInvocationHandler(sqlSessionFactory.openSession().getMapper(aClass))
                );
                Method selectByPrimaryKey = aClass.getDeclaredMethod("selectByPrimaryKey", Long.class);
                //調(diào)用查詢方法
                result = selectByPrimaryKey.invoke(instance, id);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return  result;
        }
    
        @Override
        public Object getNewResult(JoinPoint joinPoint, DBAccessLogger enableModifyLog,String sqlSessionFactoryName) {
            return getOldResult(joinPoint,enableModifyLog,sqlSessionFactoryName);
        }
    
    }

三:定義AOP切面

注意:如不返回操作是否成功狀態(tài)可能會導(dǎo)致前端出現(xiàn)警告,JSON為空不能被解析

import com.test.common.annotation.FieldMeta;
import com.test.common.core.domain.entity.SysUser;
import com.test.common.enums.BusinessStatus;
import com.test.common.enums.OperatorType;
import com.test.common.utils.*;
import com.test.customer.domain.UserDataOperationLogs;
import com.test.customer.service.IUserDataOperationLogsService;
import com.test.framework.service.OperateLog;
import com.test.common.enums.BusinessType;
import com.test.framework.service.ContentParser;
import com.test.system.domain.SysOperLog;
import com.test.system.service.ISysOperLogService;
import lombok.extern.slf4j.Slf4j;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 攔截@EnableGameleyLog注解的方法
 * 將具體修改存儲到數(shù)據(jù)庫中
 */
@Aspect
@Component
@Slf4j
public class OperateAspect {

    @Autowired
    private IUserDataOperationLogsService iUserDataOperationLogsService;

    @Autowired
    private DefaultContentParse defaultContentParse;

    @Autowired
    private ApplicationContext applicationContext;


    // 環(huán)繞通知
    @Around("@annotation(operateLog)")
    public Object around(ProceedingJoinPoint joinPoint, OperateLog operateLog) throws Throwable{
        Map<String, Object> oldMap=new HashMap<>();
        UserDataOperationLogs lg = new UserDataOperationLogs();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 當(dāng)不傳默認(rèn)operateType時 根據(jù)Method類型自動匹配
        setAnnotationType(request, operateLog);

        // fixme 1.0.9開始不再提供自動存入username功能,請在存儲實現(xiàn)類中自行存儲
        // 從切面織入點處通過反射機制獲取織入點處的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        Object[] args=joinPoint.getArgs(); // 請求參數(shù)

        // 獲取當(dāng)前的用戶
        SysUser currentUser = ShiroUtils.getSysUser();

        lg.setCreateBy(currentUser.getLoginName());
        lg.setStatus(0l);
        lg.setUpdateTime(new Date());
        if (OperateType.UPDATE.equals(operateLog.operateType())) {
            try {
               ContentParser contentParser=(ContentParser) applicationContext.getBean(operateLog.parseclass());
                Object oldObject = contentParser.getResult(joinPoint, operateLog);
                if (operateLog.needDefaultCompare()) {
                    oldMap = (Map<String, Object>) objectToMap(oldObject); // 存儲修改前的對象
                    lg.setStoreId((Long) oldMap.get("storeId"));
                    lg.setItemId((Long) oldMap.get("itemId"));
                }
            } catch (Exception e) {
               e.printStackTrace();
                log.error("service加載失敗:", e);
            }
        }
        // joinPoint.proceed()執(zhí)行前是前置通知,執(zhí)行后是后置通知
        Object object=joinPoint.proceed();
        if (OperateType.UPDATE.equals(operateLog.operateType())) {
            ContentParser contentParser;
            try {
               String responseParams=JSON.toJSONString(object);
               contentParser=(ContentParser) applicationContext.getBean(operateLog.parseclass());
                object = contentParser.getResult(joinPoint, operateLog);
            } catch (Exception e) {
               log.error("service加載失敗:", e);
            }
            // 默認(rèn)不進行比較,可以自己在logService中自定義實現(xiàn),降低對性能的影響
            if (operateLog.needDefaultCompare()) {
               lg.setContent(defaultDealUpdate(object, oldMap));
            }
            // 如果使用默認(rèn)緩存 則需要更新到最新的數(shù)據(jù)
            if(operateLog.defaultCache()
                  && operateLog.parseclass().equals(DefaultContentParse.class)){
                defaultContentParse.updateCache(joinPoint, operateLog,object);
            }
        } else{
           String responseParams=JSON.toJSONString(object);
        }
        //保存當(dāng)前日志到數(shù)據(jù)庫中
        int logs = iUserDataOperationLogsService.insertUserDataOperationLogs(lg);
        log.info("新增用戶操作數(shù)據(jù)日志成功");
        //返回用戶的操作是否成功
        AjaxResult ajaxResult = logs > 0 ? success() : error();
        return ajaxResult;
    }

    private String defaultDealUpdate(Object newObject, Map<String, Object> oldMap){
        try {
            Map<String, Object> newMap = (Map<String, Object>) objectToMap(newObject);
            StringBuilder str = new StringBuilder();
            Object finalNewObject = newObject;
            oldMap.forEach((k, v) -> {
                Object newResult = newMap.get(k);
                if (null!=v && !v.equals(newResult)) {
                    Field field = ReflectionUtils.getAccessibleField(finalNewObject, k);
                    FieldMeta dataName = field.getAnnotation(FieldMeta.class);
                    SysUser currentUser = ShiroUtils.getSysUser();
                    if (null!=dataName) {
                        str.append("【"+currentUser.getLoginName()+"】").append("修改了【").append(dataName.value() +"】").append("將【").append(v).append("】").append(" 改為:【").append(newResult).append("】。\n");
                    }
                }
            });
            return str.toString();
        } catch (Exception e) {
            log.error("比較異常", e);
            throw new RuntimeException("比較異常",e);
        }
    }

    private Map<?, ?> objectToMap(Object obj) {
        if (obj == null) {
            return null;
        }
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 如果使用JPA請自己打開這條配置
        // mapper.addMixIn(Object.class, IgnoreHibernatePropertiesInJackson.class);
        Map<?, ?> mappedObject = mapper.convertValue(obj, Map.class);
        return mappedObject;
    }

    private void setAnnotationType(HttpServletRequest request,OperateLog modifyLog){
        if(!modifyLog.operateType().equals(OperateType.NONE)){
            return;
        }
        String method=request.getMethod();
        if(RequestMethod.GET.name().equalsIgnoreCase(method)){
            ReflectAnnotationUtil.updateValue(modifyLog, "operateType", OperateType.SELECT);
        } else if(RequestMethod.POST.name().equalsIgnoreCase(method)){
            ReflectAnnotationUtil.updateValue(modifyLog, "operateType", OperateType.ADD);
        } else if(RequestMethod.PUT.name().equalsIgnoreCase(method)){
            ReflectAnnotationUtil.updateValue(modifyLog, "operateType", OperateType.UPDATE);
        } else if(RequestMethod.DELETE.name().equalsIgnoreCase(method)){
            ReflectAnnotationUtil.updateValue(modifyLog, "operateType", OperateType.DELETE);
        }
    }
}

或者寫成


	//環(huán)繞通知切面,切點:DBAccessLogger 更新攔截數(shù)據(jù)
	@Aspect
    @Component
    @Order(1)
    public class DBAccessLoggerAspect {
    
        // 注入Service用于把日志保存數(shù)據(jù)庫
        @Autowired
        private LogService logService;
        
        @Around("@annotation(com.****.log.DBAccessLogger)") // 環(huán)繞通知
        public Object execute(ProceedingJoinPoint pjp) throws Exception {
            // 獲得當(dāng)前訪問的class
            Class<?> className = pjp.getTarget().getClass();
            // 獲得訪問的方法名
            String methodName = pjp.getSignature().getName();
            @SuppressWarnings("rawtypes")
            Class[] argClass = ((MethodSignature) pjp.getSignature()).getParameterTypes();
            // 操作結(jié)果,默認(rèn)為成功
            Long operResult = DictLogConstant.LOGS_OPER_SUCCESS;
            //返回值
            Object rvt = null;
            Method method = className.getMethod(methodName, argClass);
            DBAccessLogger dbAcessLoggerannotation = method.getAnnotation(DBAccessLogger.class);
            String accessTable = dbAcessLoggerannotation.accessTable();
            DBOperationType accessType = dbAcessLoggerannotation.accessType();
            DatabaseEnum databaseEnum = dbAcessLoggerannotation.accessDatasource();
            String accessDatasource = databaseEnum.constName;
            //crd操作直接執(zhí)行方法
            if (accessType == DBOperationType.DELETE || accessType == DBOperationType.SELECT || accessType == DBOperationType.CREATE) {
                try {
                    rvt = pjp.proceed();
                } catch (Throwable e) {
                    e.printStackTrace();
                    throw new RuntimeException(e.getMessage());
                }
                // 如果沒有返回結(jié)果,則不將該日志操作寫入數(shù)據(jù)庫。
                if (rvt == null) return rvt;
            }
            if ((accessType == DBOperationType.DELETE)
                    && ((CUDResult) rvt).getReturnVal() == 0) {
                operResult = DictLogConstant.LOGS_OPER_FAILURE;
            }
            if (accessTable != null) {
                if (accessType == DBOperationType.SELECT) {
                    Log sysLog = new Log();
					/**
					設(shè)置要存放的日志信息
					**/
                    logService.createLog(sysLog);
    
                }
                else if (accessType == DBOperationType.DELETE || accessType == DBOperationType.CREATE) {
                    for (Long recordId : ((CUDResult) rvt).getRecordIds()) {
                        Log sysLog = new Log();
                      	/**
						設(shè)置要存放的日志信息
						**/
                        logService.createLog(sysLog);
                    }
                }
                else {
                    //更新操作
                    Log sysLog = new Log();
                    /**
                   設(shè)置日志信息
                   **/
                    //獲取更行前的數(shù)據(jù)
                    Map<String, Object> oldMap = null;
                    Object oldObject;
                    try {
                        ContentParser contentParser = SpringUtil.getBean(dbAcessLoggerannotation.parseClass());
                        //獲取更行前的數(shù)據(jù)
                        oldObject = contentParser.getOldResult(pjp, dbAcessLoggerannotation, databaseEnum.sqlsessionName);
                        oldMap = (Map<String, Object>) objectToMap(oldObject);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    //執(zhí)行service
                    Object serviceReturn;
                    try {
                        serviceReturn = pjp.proceed();
                    } catch (Throwable throwable) {
                        throwable.printStackTrace();
                        throw new RuntimeException(throwable.getMessage());
                    }
                    CUDResult crudResult = (CUDResult) serviceReturn;
                    Object afterResult = null;
                    try {
                        ContentParser contentParser = SpringUtil.getBean(dbAcessLoggerannotation.parseClass());
                        //更新后的數(shù)據(jù)
                        afterResult = contentParser.getNewResult(pjp, dbAcessLoggerannotation, databaseEnum.sqlsessionName);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    //修改前后的變化
                    sysLog.setOperation(accessType.getValue());
                    try {
                        String updatedefrent = defaultDealUpdate(afterResult, oldMap);
                        sysLog.setParams(updatedefrent);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                   /**
                   設(shè)置日志信息
                   **/
                    logService.createLog(sysLog);
                    return serviceReturn;
                }
            }
    
            if (operResult.longValue() == DictLogConstant.LOGS_OPER_FAILURE) {
                // 當(dāng)數(shù)據(jù)庫的UPDATE 和 DELETE操作沒有對應(yīng)的數(shù)據(jù)記錄存在時,拋出異常
                throw new DBAccessException(accessType.getValue() + "的數(shù)據(jù)記錄不存在!");
            }
            return rvt;
        }
        private Map<?, ?> objectToMap(Object obj) {
            if (obj == null) {
                return null;
            }
            ObjectMapper mapper = new ObjectMapper();
            mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            //如果使用JPA請自己打開這條配置
            //mapper.addMixIn(Object.class, IgnoreHibernatePropertiesInJackson.class);
            Map<?, ?> mappedObject = mapper.convertValue(obj, Map.class);
            return mappedObject;
        }
    
        /**
         *
         * @param newObject 更新過后的結(jié)果
         * @param oldMap 更新前的結(jié)果
         * @return
         */
        private String defaultDealUpdate(Object newObject, Map<String, Object> oldMap) {
            try {
                Map<String, Object> newMap = (Map<String, Object>) objectToMap(newObject);
                StringBuilder str = new StringBuilder();
                Object finalNewObject = newObject;
                oldMap.forEach((k, v) -> {
                    Object newResult = newMap.get(k);
                    if (v != null && !v.equals(newResult)) {
                        Field field = ReflectionUtils.getAccessibleField(finalNewObject, k);
                        //獲取類上的注解
                        DataName dataName = field.getAnnotation(DataName.class);
                        if (field.getType().getName().equals("java.util.Date")) {
                            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            if (dataName != null) {
                                str.append("【").append(dataName.name()).append("】從【")
                                        .append(format.format(v)).append("】改為了【").append(format.format(newResult)).append("】;\n");
                            } else {
                                str.append("【").append(field.getName()).append("】從【")
                                        .append(format.format(v)).append("】改為了【").append(format.format(newResult)).append("】;\n");
                            }
                        } else {
                            if (dataName != null) {
                                str.append("【").append(dataName.name()).append("】從【")
                                        .append(v).append("】改為了【").append(newResult).append("】;\n");
                            } else {
                                str.append("【").append(field.getName()).append("】從【")
                                        .append(v).append("】改為了【").append(newResult).append("】;\n");
                            }
                        }
                    }
                });
                return str.toString();
            } catch (Exception e) {
                throw new RuntimeException("比較異常", e);
            }
        }
    }

四:自定義日志注解

package com.test.framework.service;

import com.test.common.utils.IService;
import com.test.common.utils.OperateType;
import com.test.framework.service.impl.DefaultContentParse;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 記錄編輯詳細(xì)信息的標(biāo)注
 * @author 
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface OperateLog {

   // 模塊名稱
   String moduleCode() default "";

   // 操作的類型 可以直接調(diào)用OperateType 不傳時根據(jù)METHOD自動確定
   OperateType operateType() default OperateType.NONE;

   // 獲取編輯信息的解析類,目前為使用id獲取,復(fù)雜的解析需要自己實現(xiàn),默認(rèn)不填寫則使用默認(rèn)解析類
    Class parseclass() default DefaultContentParse.class;

    // 查詢數(shù)據(jù)庫所調(diào)用的class文件
    Class serviceclass() default IService.class;

    // 具體業(yè)務(wù)操作名稱
    String handleName() default "";

    // 是否需要默認(rèn)的改動比較
    boolean needDefaultCompare() default false;

    // id的類型
    Class idType() default Long.class;

    // 是否使用默認(rèn)本地緩存
    boolean defaultCache() default false;


}

五、@OperateLog注解使用

/**
 * 修改記錄詳情
 * @OperateLog:AOP自定義日志注解
 */
@PostMapping("/editSave")
@OperateLog(moduleCode="editSave", operateType= OperateType.UPDATE, handleName="修改檔案信息", needDefaultCompare=true)
@ResponseBody
public AjaxResult editSave(TCustomerItemRecDetail tCustomerItemRecDetail){
    return toAjax(testDangAnDetailService.updateTestDangAnDetail(tCustomerItemRecDetail));
}

修改功能時,需要實現(xiàn)我們自定義的IService接口,并重寫 selectById 方法,在修改前我們需要根據(jù)主鍵id去數(shù)據(jù)庫查詢對應(yīng)的信息,然后在和修改后的值進行比較。

springboot記錄數(shù)據(jù)修改前后內(nèi)容,spring,架構(gòu),spring boot,java,后端文章來源地址http://www.zghlxwxcb.cn/news/detail-818246.html

六:IService接口

/**
 * 修改時需要記錄修改前后的值時,需要根據(jù)主鍵id去查詢修改前的值時需要
 * @author zhang
 */
public interface IService<T, S> {
    T selectById(S id);
}

到了這里,關(guān)于spring boot 使用AOP+自定義注解+反射實現(xiàn)操作日志記錄修改前數(shù)據(jù)和修改后對比數(shù)據(jù),并保存至日志表的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • Spring Boot入門(23):記錄接口日志再也不難!用AOP和自定義注解給Spring Boot加上日志攔截器!

    Spring Boot入門(23):記錄接口日志再也不難!用AOP和自定義注解給Spring Boot加上日志攔截器!

    ? ? ? ? 在上兩期中,我們著重介紹了如何集成使用 Logback?與?log4j2?日志框架的使用,今天我們講解的主題依舊跟日志有關(guān),不過不是使用何種開源框架,而是自己動手造。 ? ? ? ? Spring的核心之一AOP;AOP翻譯過來叫面向切面編程, 核心就是這個切面. 切面表示從業(yè)務(wù)邏輯中

    2024年02月11日
    瀏覽(25)
  • 對接第三方接口鑒權(quán)(Spring Boot+Aop+注解實現(xiàn)Api接口簽名驗證)

    對接第三方接口鑒權(quán)(Spring Boot+Aop+注解實現(xiàn)Api接口簽名驗證)

    一個web系統(tǒng),從接口的使用范圍也可以分為對內(nèi)和對外兩種,對內(nèi)的接口主要限于一些我們內(nèi)部系統(tǒng)的調(diào)用,多是通過內(nèi)網(wǎng)進行調(diào)用,往往不用考慮太復(fù)雜的鑒權(quán)操作。但是,對于對外的接口,我們就不得不重視這個問題,外部接口沒有做鑒權(quán)的操作就直接發(fā)布到互聯(lián)網(wǎng),而

    2024年04月29日
    瀏覽(133)
  • 【Spring AOP + 自定義注解 + 動態(tài)數(shù)據(jù)源 實現(xiàn)主從庫切換&讀寫分離】—— 案例實戰(zhàn)

    【Spring AOP + 自定義注解 + 動態(tài)數(shù)據(jù)源 實現(xiàn)主從庫切換&讀寫分離】—— 案例實戰(zhàn)

    ???????????????????????????????????????????? ?? S p r i n g A O P + 主從數(shù)據(jù)源切換 + 讀寫分離 + 自定義注解案例實戰(zhàn)! color{#FF1493}{Spring AOP + 主從數(shù)據(jù)源切換 + 讀寫分離 + 自定義注解 案例實戰(zhàn)!} Sp r in g A OP + 主從數(shù)據(jù)源切換 + 讀寫分離 + 自定義注解案例

    2024年02月15日
    瀏覽(21)
  • Spring5框架——AOP操作:通過Aspectj注解方式和配置文件方式來實現(xiàn)

    Spring5框架——AOP操作:通過Aspectj注解方式和配置文件方式來實現(xiàn)

    o((⊙﹏⊙))o. ** 之前的博客介紹了什么是AOP,以及AOP的底層原理,AOP主要是在原本的基礎(chǔ)上添加一些之外的功能但是添加的功能是不會修改原定的代碼,接下來為你介紹的是Aspectj注解,Spring 框架一般都是基于 AspectJ 實現(xiàn) AOP 操作。AspectJ 不是 Spring 組成部分,獨立 AOP 框架,一

    2024年02月16日
    瀏覽(20)
  • Java實戰(zhàn):Spring Boot實現(xiàn)AOP記錄操作日志

    本文將詳細(xì)介紹如何在Spring Boot應(yīng)用程序中使用Aspect Oriented Programming(AOP)來實現(xiàn)記錄操作日志的功能。我們將探討Spring Boot集成AOP的基本概念,以及如何使用Spring Boot實現(xiàn)AOP記錄操作日志。最后,我們將通過一個具體示例來演示整個實現(xiàn)過程。本文適合已經(jīng)具備Spring Boot基礎(chǔ)

    2024年02月22日
    瀏覽(21)
  • spring自定義注解+aop+@BindingParam

    2.1 聲明切面注解 ?2.1.1切面對應(yīng)枚舉 ?2.2 聲明綁定參數(shù)注解 4.1 ThreadLocalUtil? 4.2? 自定義異常

    2024年02月14日
    瀏覽(19)
  • springboot3使用自定義注解+AOP+redis優(yōu)雅實現(xiàn)防重復(fù)提交

    springboot3使用自定義注解+AOP+redis優(yōu)雅實現(xiàn)防重復(fù)提交

    ? ??個人主頁:? ? ?蒾酒 ?? 系列專欄 :《spring boot實戰(zhàn)》 ?? 山高路遠(yuǎn),行路漫漫,終有歸途 目錄 寫在前面 實現(xiàn)思路 實現(xiàn)步驟 1.定義防重復(fù)提交注解 2.編寫一個切面去發(fā)現(xiàn)該注解然后執(zhí)行防重復(fù)提交邏輯 3.測試 依賴條件 1.接口上標(biāo)記防重復(fù)提交注解 2.接口測試 寫在最

    2024年04月11日
    瀏覽(23)
  • 使用Spring Boot AOP實現(xiàn)日志記錄

    使用Spring Boot AOP實現(xiàn)日志記錄

    目錄 介紹 1.1 什么是AOP 1.2 AOP體系與概念 AOP簡單實現(xiàn) 2.1 新建一個SpringBoot項目,無需選擇依賴 2.2 設(shè)置好本地Maven配置后,在pom.xml文件里添加添加maven依賴 2.3 創(chuàng)建一個業(yè)務(wù)類接口 2.4 在實體類實現(xiàn)接口業(yè)務(wù)? 2.5 在單元測試運行結(jié)果 2.6?創(chuàng)建切面類 2.7?再次運行測試 ?總結(jié) 1.

    2024年02月14日
    瀏覽(27)
  • Spring Boot 3自定義注解+攔截器+Redis實現(xiàn)高并發(fā)接口限流

    在當(dāng)今互聯(lián)網(wǎng)應(yīng)用開發(fā)中,高并發(fā)訪問是一個常見的挑戰(zhàn)。為了保障系統(tǒng)的穩(wěn)定性和可靠性,我們需要對接口進行限流,防止因過多的請求導(dǎo)致系統(tǒng)崩潰。 本文將介紹如何利用Spring Boot 3中的自定義注解、攔截器和Redis實現(xiàn)高并發(fā)接口限流,幫助程序員解決這一挑戰(zhàn)。 1. 自定

    2024年04月28日
    瀏覽(25)
  • Spring Boot入門(14):使用Mybatis-Plus輕松實現(xiàn)高效自定義SQL操作!

    ? ? ? ? 在上幾期,我們既講了如何整合Mybatis-Plus進行數(shù)據(jù)庫的增刪改查,也講解了如何使用MP的 Wrapper 構(gòu)造器,但若是遇到復(fù)雜業(yè)務(wù)邏輯,如多表聯(lián)查、動態(tài)拼接條件等,這些操作往往會讓代碼變得冗長且難以維護。但是,有了Mybatis-Plus這個優(yōu)秀的框架,我們可以輕松實現(xiàn)

    2024年02月10日
    瀏覽(25)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包