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

基于Mybatis-Plus攔截器實現(xiàn)MySQL數(shù)據(jù)加解密

這篇具有很好參考價值的文章主要介紹了基于Mybatis-Plus攔截器實現(xiàn)MySQL數(shù)據(jù)加解密。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、背景

用戶的一些敏感數(shù)據(jù),例如手機號、郵箱、身份證等信息,在數(shù)據(jù)庫以明文存儲時會存在數(shù)據(jù)泄露的風(fēng)險,因此需要進行加密, 但存儲數(shù)據(jù)再被取出時,需要進行解密,因此加密算法需要使用對稱加密算法。

常用的對稱加密算法有AES、DES、RC、BASE64等等,各算法的區(qū)別與優(yōu)劣請自行百度。

本案例采用AES算法對數(shù)據(jù)進行加密。

mybatisplus 加密,[拓維]云架構(gòu),Java基礎(chǔ),數(shù)據(jù)加密,Mybatis-Plus攔截器,對稱加密

?

???????

二、MybatisPlus攔截器介紹

本文基于SpringBoot+MybatisPlus(3.5.X)+MySQL8架構(gòu),Dao層與DB中間使用MP的攔截器機制,對數(shù)據(jù)存取過程進行攔截,實現(xiàn)數(shù)據(jù)的加解密操作。

三、使用方法

該加解密攔截器功能在wutong-base-dao包(公司內(nèi)部包)已經(jīng)實現(xiàn),如果您的項目已經(jīng)依賴了base-dao,就可以直接使用。

另外,在碼云上有Demo案例,見:?mybatis-plus加解密Demo

基于wutong-base-dao包的使用步驟如下。

1、添加wutong-base-dao依賴

<dependency>
    <groupId>com.talkweb</groupId>
    <artifactId>wutong-base-dao</artifactId>
    <version>請使用最新版本</version>
</dependency>

2、在yaml配置開關(guān),啟用加解密

mybatis-plus:
  wutong:
    encrypt:
      # 是否開啟敏感數(shù)據(jù)加解密,默認false
      enable: true
      # AES加密秘鑰,可以使用hutool的SecureUtil工具類生成
      secretKey: yourSecretKey

3、定義PO類

實體類上使用自定義注解,來標(biāo)記需要進行加解密

// 必須使用@EncryptedTable注解
@EncryptedTable
@TableName(value = "wsp_user")
public class UserEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    private String name;
    // 使用@EncryptedColumn注解
    @EncryptedColumn
    private String mobile;
    // 使用@EncryptedColumn注解
    @EncryptedColumn
    private String email;
}

4、定義API接口

通過MP自帶API、Lambda、自定義mapper接口三種方式進行測試

/**
 * 用戶表控制器
 *
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-01-11
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource(name = "userServiceImpl")
    private IUserService userService;
    @Resource(name = "userXmlServiceImpl")
    private IUserService userXmlService;

    /**
     * 測試解密
     */
    @GetMapping(name = "測試解密", value = "/detail")
    public UserEntity detail(Long id) {
        // 測試MP API
//        UserEntity entity = userService.getById(id);

        // 測試自定義Mapper接口
        UserEntity entity = userXmlService.getById(id);
        if (null == entity) {
            return new UserEntity();
        }
        return entity;
    }

    /**
     * 新增用戶表,測試加密
     */
    @GetMapping(name = "新增用戶表,測試加密", value = "/add")
    public UserEntity add(UserEntity entity) {
        // 測試MP API
//        userService.save(entity);

        // 測試自定義Mapper接口
        userXmlService.save(entity);
        return entity;
    }

    /**
     * 修改用戶表
     */
    @GetMapping(name = "修改用戶表", value = "/update")
    public UserEntity update(UserEntity entity) {
        // 測試MP API
//        userService.updateById(entity);

        // 測試Lambda
//        LambdaUpdateWrapper<UserEntity> wrapper = new LambdaUpdateWrapper<>();
//        wrapper.eq(UserEntity::getId, entity.getId());
//        wrapper.set(UserEntity::getMobile, entity.getMobile());
//        wrapper.set(UserEntity::getName, entity.getName());
//        wrapper.set(UserEntity::getEmail, entity.getEmail());
//        userService.update(wrapper);

        // 測試自定義Mapper接口
        userXmlService.updateById(entity);
        return entity;
    }
}

四、實現(xiàn)原理

1、自定義注解

根據(jù)注解進行數(shù)據(jù)攔截

/**
 * 需要加解密的實體類用這個注解
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-05-31
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface EncryptedTable {
 
}

/**
 * 需要加解密的字段用這個注解
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-05-31
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface EncryptedColumn {

}

2、定義攔截器

加密攔截器EncryptInterceptor


/**
 * 加密攔截器
 *
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-05-31
 */
public class EncryptInterceptor extends JsqlParserSupport implements InnerInterceptor {
    /**
     * 變量占位符正則
     */
    private static final Pattern PARAM_PAIRS_RE = Pattern.compile("#\\{ew\\.paramNameValuePairs\\.(" + Constants.WRAPPER_PARAM + "\\d+)\\}");

    /**
     * 如果查詢條件是加密數(shù)據(jù)列,那么要將查詢條件進行數(shù)據(jù)加密。
     * 例如,手機號加密存儲后,按手機號查詢時,先把要查詢的手機號進行加密,再和數(shù)據(jù)庫存儲的加密數(shù)據(jù)進行匹配
     */
    @Override
    public void beforeQuery(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        if (Objects.isNull(parameterObject)) {
            return;
        }
        if (!(parameterObject instanceof Map)) {
            return;
        }
        Map paramMap = (Map) parameterObject;
        // 參數(shù)去重,否則多次加密會導(dǎo)致查詢失敗
        Set set = (Set) paramMap.values().stream().collect(Collectors.toSet());
        for (Object param : set) {
            /**
             *  僅支持類型是自定義Entity的參數(shù),不支持mapper的參數(shù)是QueryWrapper、String等,例如:
             *
             *  支持:findList(@Param(value = "query") UserEntity query);
             *  支持:findPage(@Param(value = "query") UserEntity query, Page<UserEntity> page);
             *
             *  不支持:findOne(@Param(value = "mobile") String mobile);
             *  不支持:findList(QueryWrapper wrapper);
             */
            if (param instanceof AbstractWrapper || param instanceof String) {
                // Wrapper、String類型查詢參數(shù),無法獲取參數(shù)變量上的注解,無法確認是否需要加密,因此不做判斷
                continue;
            }
            if (annotateWithEncrypt(param.getClass())) {
                encryptEntity(param);
            }
        }
    }

    /**
     * 新增、更新數(shù)據(jù)時,如果包含隱私數(shù)據(jù),則進行加密
     */
    @Override
    public void beforeUpdate(Executor executor, MappedStatement mappedStatement, Object parameterObject) throws SQLException {
        if (Objects.isNull(parameterObject)) {
            return;
        }
        // 通過MybatisPlus自帶API(save、insert等)新增數(shù)據(jù)庫時
        if (!(parameterObject instanceof Map)) {
            if (annotateWithEncrypt(parameterObject.getClass())) {
                encryptEntity(parameterObject);
            }
            return;
        }
        Map paramMap = (Map) parameterObject;
        Object param;
        // 通過MybatisPlus自帶API(update、updateById等)修改數(shù)據(jù)庫時
        if (paramMap.containsKey(Constants.ENTITY) && null != (param = paramMap.get(Constants.ENTITY))) {
            if (annotateWithEncrypt(param.getClass())) {
                encryptEntity(param);
            }
            return;
        }
        // 通過在mapper.xml中自定義API修改數(shù)據(jù)庫時
        if (paramMap.containsKey("entity") && null != (param = paramMap.get("entity"))) {
            if (annotateWithEncrypt(param.getClass())) {
                encryptEntity(param);
            }
            return;
        }
        // 通過UpdateWrapper、LambdaUpdateWrapper修改數(shù)據(jù)庫時
        if (paramMap.containsKey(Constants.WRAPPER) && null != (param = paramMap.get(Constants.WRAPPER))) {
            if (param instanceof Update && param instanceof AbstractWrapper) {
                Class<?> entityClass = mappedStatement.getParameterMap().getType();
                if (annotateWithEncrypt(entityClass)) {
                    encryptWrapper(entityClass, param);
                }
            }
            return;
        }
    }

    /**
     * 校驗該實例的類是否被@EncryptedTable所注解
     */
    private boolean annotateWithEncrypt(Class<?> objectClass) {
        EncryptedTable sensitiveData = AnnotationUtils.findAnnotation(objectClass, EncryptedTable.class);
        return Objects.nonNull(sensitiveData);
    }

    /**
     * 通過API(save、updateById等)修改數(shù)據(jù)庫時
     *
     * @param parameter
     */
    private void encryptEntity(Object parameter) {
        //取出parameterType的類
        Class<?> resultClass = parameter.getClass();
        Field[] declaredFields = resultClass.getDeclaredFields();
        for (Field field : declaredFields) {
            //取出所有被EncryptedColumn注解的字段
            EncryptedColumn sensitiveField = field.getAnnotation(EncryptedColumn.class);
            if (!Objects.isNull(sensitiveField)) {
                field.setAccessible(true);
                Object object = null;
                try {
                    object = field.get(parameter);
                } catch (IllegalAccessException e) {
                    continue;
                }
                //只支持String的解密
                if (object instanceof String) {
                    String value = (String) object;
                    //對注解的字段進行逐一加密
                    try {
                        field.set(parameter, AESUtils.encrypt(value));
                    } catch (IllegalAccessException e) {
                        continue;
                    }
                }
            }
        }
    }

    /**
     * 通過UpdateWrapper、LambdaUpdateWrapper修改數(shù)據(jù)庫時
     *
     * @param entityClass
     * @param ewParam
     */
    private void encryptWrapper(Class<?> entityClass, Object ewParam) {
        AbstractWrapper updateWrapper = (AbstractWrapper) ewParam;
        String sqlSet = updateWrapper.getSqlSet();
        String[] elArr = sqlSet.split(",");
        Map<String, String> propMap = new HashMap<>(elArr.length);
        Arrays.stream(elArr).forEach(el -> {
            String[] elPart = el.split("=");
            propMap.put(elPart[0], elPart[1]);
        });

        //取出parameterType的類
        Field[] declaredFields = entityClass.getDeclaredFields();
        for (Field field : declaredFields) {
            //取出所有被EncryptedColumn注解的字段
            EncryptedColumn sensitiveField = field.getAnnotation(EncryptedColumn.class);
            if (Objects.isNull(sensitiveField)) {
                continue;
            }
            String el = propMap.get(field.getName());
            Matcher matcher = PARAM_PAIRS_RE.matcher(el);
            if (matcher.matches()) {
                String valueKey = matcher.group(1);
                Object value = updateWrapper.getParamNameValuePairs().get(valueKey);
                updateWrapper.getParamNameValuePairs().put(valueKey, AESUtils.encrypt(value.toString()));
            }
        }

        Method[] declaredMethods = entityClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            //取出所有被EncryptedColumn注解的字段
            EncryptedColumn sensitiveField = method.getAnnotation(EncryptedColumn.class);
            if (Objects.isNull(sensitiveField)) {
                continue;
            }
            String el = propMap.get(method.getName());
            Matcher matcher = PARAM_PAIRS_RE.matcher(el);
            if (matcher.matches()) {
                String valueKey = matcher.group(1);
                Object value = updateWrapper.getParamNameValuePairs().get(valueKey);
                updateWrapper.getParamNameValuePairs().put(valueKey, AESUtils.encrypt(value.toString()));
            }
        }
    }
}

解密攔截器

/**
 * 解密攔截器
 *
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-05-31
 */
@Intercepts({
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
@Component
public class DecryptInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object resultObject = invocation.proceed();
        if (Objects.isNull(resultObject)) {
            return null;
        }
        if (resultObject instanceof ArrayList) {
            //基于selectList
            ArrayList resultList = (ArrayList) resultObject;
            if (!resultList.isEmpty() && needToDecrypt(resultList.get(0))) {
                for (Object result : resultList) {
                    //逐一解密
                    decrypt(result);
                }
            }
        } else if (needToDecrypt(resultObject)) {
            //基于selectOne
            decrypt(resultObject);
        }
        return resultObject;
    }

    /**
     * 校驗該實例的類是否被@EncryptedTable所注解
     */
    private boolean needToDecrypt(Object object) {
        Class<?> objectClass = object.getClass();
        EncryptedTable sensitiveData = AnnotationUtils.findAnnotation(objectClass, EncryptedTable.class);
        return Objects.nonNull(sensitiveData);
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    private <T> T decrypt(T result) throws Exception {
        //取出resultType的類
        Class<?> resultClass = result.getClass();
        Field[] declaredFields = resultClass.getDeclaredFields();
        for (Field field : declaredFields) {
            //取出所有被EncryptedColumn注解的字段
            EncryptedColumn sensitiveField = field.getAnnotation(EncryptedColumn.class);
            if (!Objects.isNull(sensitiveField)) {
                field.setAccessible(true);
                Object object = field.get(result);
                //只支持String的解密
                if (object instanceof String) {
                    String value = (String) object;
                    //對注解的字段進行逐一解密
                    field.set(result, AESUtils.decrypt(value));
                }
            }
        }
        return result;
    }
}

四、其他實現(xiàn)方案

在技術(shù)調(diào)研過程中,還測試了另外兩種便宜實現(xiàn)方案,由于無法覆蓋MP自帶API、Lambda、自定義API等多種場景,因此未采用。

1、使用字段類型處理器

字段類型處理器的[官方文檔點這里],不能處理LambdaUpdateWrapper更新數(shù)據(jù)時加密的場景。

自定義類型處理器,實現(xiàn)加解密:


/**
 * @author wangshaopeng@talkweb.com.cn
 * @desccription 加密類型字段處理器
 * @date 2023/5/31
 */
public class EncryptTypeHandler extends BaseTypeHandler<String> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, AESUtils.encrypt(parameter));
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        final String value = rs.getString(columnName);
        return AESUtils.decrypt(value);
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        final String value = rs.getString(columnIndex);
        return AESUtils.decrypt(value);
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        final String value = cs.getString(columnIndex);
        return AESUtils.decrypt(value);
    }
}

在實體屬性上進行指定

// @TableName注解必須指定autoResultMap = true
@EncryptedTable
@TableName(value = "wsp_user", autoResultMap = true)
public class UserEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    private String name;
    @TableField(typeHandler = EncryptTypeHandler.class)
    private String mobile;
    @TableField(typeHandler = EncryptTypeHandler.class)
    private String email;
}

2、自動填充功能

自動填充功能的[官方文檔點這里],不能處理LambdaUpdateWrapper、自定義mapper接口更新數(shù)據(jù)時加密的場景,不支持解密的需求。

自定義類型處理器,實現(xiàn)加解密:


/**
 * Mybatis元數(shù)據(jù)填充處理類,僅能處理MP的函數(shù),不能處理mapper.xml中自定義的insert、update
 *
 * @author wangshaopeng@talkweb.com.cn
 * @Date 2023-01-11
 */
public class DBMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        String mobile = (String) metaObject.getValue("mobile");
        this.strictInsertFill(metaObject, "mobile", String.class, AESUtils.encrypt(mobile));
        String email = (String) metaObject.getValue("email");
        this.strictInsertFill(metaObject, "email", String.class, AESUtils.encrypt(email));
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        String mobile = (String) metaObject.getValue("mobile");
        this.strictUpdateFill(metaObject, "mobile", String.class, AESUtils.encrypt(mobile));
        String email = (String) metaObject.getValue("email");
        this.strictUpdateFill(metaObject, "email", String.class, AESUtils.encrypt(email));
    }
}

在實體類上指定自動填充策略文章來源地址http://www.zghlxwxcb.cn/news/detail-600957.html

@EncryptedTable
@TableName(value = "wsp_user")
public class UserEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    private String name;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String mobile;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private String email;
}

到了這里,關(guān)于基于Mybatis-Plus攔截器實現(xiàn)MySQL數(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)文章

  • Springboot 自定義 Mybatis攔截器,實現(xiàn) 動態(tài)查詢條件SQL自動組裝拼接(玩具)

    Springboot 自定義 Mybatis攔截器,實現(xiàn) 動態(tài)查詢條件SQL自動組裝拼接(玩具)

    ps:最近在參與3100保衛(wèi)戰(zhàn),戰(zhàn)況很激烈,剛剛打完仗,來更新一下之前寫了一半的博客。 該篇針對日常寫查詢的時候,那些動態(tài)條件sql 做個簡單的封裝,自動生成(拋磚引玉,搞個小玩具,不喜勿噴)。 來看看我們平時寫那些查詢,基本上都要寫的一些動態(tài)sql: ? 一個字段

    2024年02月12日
    瀏覽(30)
  • MyBatis 攔截器介紹

    MyBatis 提供了一種插件 (plugin) 的功能,雖然叫做插件,但其實這是攔截器功能。那么攔截器攔截 MyBatis 中的哪些內(nèi)容呢? 我們進入官網(wǎng)看一看: MyBatis 允許你在已映射語句執(zhí)行過程中的某一點進行攔截調(diào)用。默認情況下,MyBatis 允許使用插件來攔截的方法調(diào)用包括: Executor

    2024年02月15日
    瀏覽(21)
  • 自定義MyBatis攔截器更改表名

    by emanjusaka from ? https://www.emanjusaka.top/2023/10/mybatis-interceptor-update-tableName 彼岸花開可奈何 本文歡迎分享與聚合,全文轉(zhuǎn)載請留下原文地址。 自定義MyBatis攔截器可以在方法執(zhí)行前后插入自己的邏輯,這非常有利于擴展和定制 MyBatis 的功能。本篇文章實現(xiàn)自定義一個攔截器去改

    2024年02月08日
    瀏覽(25)
  • Mybatis攔截器注解@Intercepts與@Signature注解屬性說明

    可能有些新手使用mybatis攔截器的時候可能沒太懂@Signature注解中type,method,args的用法 首先mybatis攔截器可以攔截如下4中類型 Executor sql的內(nèi)部執(zhí)行器 ParameterHandler 攔截參數(shù)的處理 StatementHandler 攔截sql的構(gòu)建 ResultSetHandler 攔截結(jié)果的處理 type:就是指定攔截器類型(ParameterHandl

    2024年02月05日
    瀏覽(27)
  • 基于MybatisPlus攔截器實現(xiàn)數(shù)據(jù)庫關(guān)鍵字處理及官方做法

    有些老的數(shù)據(jù)庫當(dāng)中可能會有些字段和數(shù)據(jù)庫沖突,使用mybatisPlus執(zhí)行Sql的時候有時候會執(zhí)行失敗,前段時間和群友討論的時候他說遇到了這個問題,當(dāng)時我提議讓他用我以前寫的一個自定義注解+mybatis攔截器實現(xiàn)權(quán)限控制里邊的工具類改造一下。 他說不能實現(xiàn),然后

    2024年04月25日
    瀏覽(28)
  • MyBatis攔截器-打印出真正執(zhí)行的sql語句和執(zhí)行結(jié)果

    MyBatis攔截器-打印出真正執(zhí)行的sql語句和執(zhí)行結(jié)果

    目錄 廣而告之 背景 先看成品 實現(xiàn)步驟 第一步,實現(xiàn)Interceptor接口 ?編輯 第二步,給攔截器指定要攔截的方法簽名 第三步,實現(xiàn)攔截器的intercept方法。 第四步,在mybatis-config.xml里配置上這個攔截器插件 第五步,禁用mybatis打印日志 給大家推薦一個好用的在線工具網(wǎng)站: 常

    2023年04月25日
    瀏覽(32)
  • 關(guān)于MyBatis攔截器失效問題的解決(多數(shù)據(jù)源、分頁插件)

    最近做了一個備份被delete語句刪除的數(shù)據(jù)的小插件,是用MyBatis的攔截器去做的。 但是發(fā)現(xiàn)在一個項目中會失效,沒有去備份刪除的數(shù)據(jù),查看日志發(fā)現(xiàn)請求并沒有進入到攔截器中,換句話說就是攔截器失效了。 百度了一下(哎,百度)發(fā)現(xiàn)說的最多的就是分頁插件導(dǎo)致的,

    2024年02月14日
    瀏覽(23)
  • 自定義注解與攔截器實現(xiàn)不規(guī)范sql攔截(攔截器實現(xiàn)篇)

    自定義注解與攔截器實現(xiàn)不規(guī)范sql攔截(攔截器實現(xiàn)篇)

    最近考慮myBatis中sql語句使用規(guī)范的問題,如果漏下條件或者寫一些不規(guī)范語句會對程序性能造成很大影響。最好的方法就是利用代碼進行限制,通過攔截器進行sql格式的判斷在自測環(huán)節(jié)就能找到問題。寫了個簡單情景下的demo,并通過idea插件來將myBatis的mapper方法都打上攔截器

    2024年01月22日
    瀏覽(29)
  • SpringBoot加入攔截器——登錄攔截器的實現(xiàn)

    SpringBoot加入攔截器——登錄攔截器的實現(xiàn)

    ? ? ? ? 攔截器 Interceptor 在 Spring MVC 中的地位等同于 Servlet 規(guī)范中的過濾器 Filter,攔截的是處理器的執(zhí)行,由于是全局行為,因此常用于做一些通用的功能,如請求日志打印、權(quán)限控制等。 ? ? ? ? 核心原理:AOP思想 preHandle:? 預(yù)先處理,在目標(biāo)的controller方法執(zhí)行之前,進行

    2024年02月15日
    瀏覽(19)
  • springboot實現(xiàn)攔截器

    內(nèi)容:繼承 HandlerInterceptorAdapter 并實現(xiàn) WebMvcConfigurer , 攔截器中的方法將preHandle-Controller-postHandle-affterCompletion的順序執(zhí)行。 注意:只有preHandle方法返回true時后面的方法才會執(zhí)行。當(dāng)攔截器鏈存在多個攔截器時,postHandle在所有攔截器內(nèi)的所有攔截器返回成功時才會調(diào)用,而

    2024年02月02日
    瀏覽(15)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包