亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Mybatis-Plus 官方神器發(fā)布

 更新時間:2021年11月09日 15:40:25   投稿:mrr  
mybatis-mate 為 mp 企業(yè)級模塊,支持分庫分表,數(shù)據(jù)審計、數(shù)據(jù)敏感詞過濾(AC算法),字段加密,字典回寫(數(shù)據(jù)綁定),數(shù)據(jù)權限,表結構自動生成 SQL 維護等,旨在更敏捷優(yōu)雅處理數(shù)據(jù),今天介紹一個 MyBatis - Plus 官方發(fā)布的神器,感興趣的朋友一起看看吧

今天介紹一個 MyBatis - Plus 官方發(fā)布的神器:mybatis-mate 為 mp 企業(yè)級模塊,支持分庫分表,數(shù)據(jù)審計、數(shù)據(jù)敏感詞過濾(AC算法),字段加密,字典回寫(數(shù)據(jù)綁定),數(shù)據(jù)權限,表結構自動生成 SQL 維護等,旨在更敏捷優(yōu)雅處理數(shù)據(jù)。

1.主要功能

  • 字典綁定
  • 字段加密
  • 數(shù)據(jù)脫敏
  • 表結構動態(tài)維護
  • 數(shù)據(jù)審計記錄
  • 數(shù)據(jù)范圍(數(shù)據(jù)權限)
  • 數(shù)據(jù)庫分庫分表、動態(tài)據(jù)源、讀寫分離、數(shù)- - 據(jù)庫健康檢查自動切換。

2、使用

2.1 依賴導入

Spring Boot 引入自動依賴注解包

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-mate-starter</artifactId>
  <version>1.0.8</version>
</dependency>

注解(實體分包使用)

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-mate-annotation</artifactId>
  <version>1.0.8</version>
</dependency>

2.2 字段數(shù)據(jù)綁定(字典回寫)

例如 user_sex 類型 sex 字典結果映射到 sexText 屬性

@FieldDict(type = "user_sex", target = "sexText")
private Integer sex;

private String sexText;

實現(xiàn) IDataDict 接口提供字典數(shù)據(jù)源,注入到 Spring 容器即可。

@Component
public class DataDict implements IDataDict {

    /**
     * 從數(shù)據(jù)庫或緩存中獲取
     */
    private Map<String, String> SEX_MAP = new ConcurrentHashMap<String, String>() {{
        put("0", "女");
        put("1", "男");
    }};

    @Override
    public String getNameByCode(FieldDict fieldDict, String code) {
        System.err.println("字段類型:" + fieldDict.type() + ",編碼:" + code);
        return SEX_MAP.get(code);
    }
}

2.3 字段加密

屬性 @FieldEncrypt 注解即可加密存儲,會自動解密查詢結果,支持全局配置加密密鑰算法,及注解密鑰算法,可以實現(xiàn) IEncryptor 注入自定義算法。

@FieldEncrypt(algorithm = Algorithm.PBEWithMD5AndDES)
private String password;

2.4 字段脫敏

屬性 @FieldSensitive 注解即可自動按照預設策略對源數(shù)據(jù)進行脫敏處理,默認 SensitiveType 內(nèi)置 9 種常用脫敏策略。
例如:中文名、銀行卡賬號、手機號碼等 脫敏策略。也可以自定義策略如下:

@FieldSensitive(type = "testStrategy")
private String username;

@FieldSensitive(type = SensitiveType.mobile)
private String mobile;

自定義脫敏策略 testStrategy 添加到默認策略中注入 Spring 容器即可。

@Configuration
public class SensitiveStrategyConfig {

    /**
     * 注入脫敏策略
     */
    @Bean
    public ISensitiveStrategy sensitiveStrategy() {
        // 自定義 testStrategy 類型脫敏處理
        return new SensitiveStrategy().addStrategy("testStrategy", t -> t + "***test***");
    }
}

例如文章敏感詞過濾

/**
 * 演示文章敏感詞過濾
 */
@RestController
public class ArticleController {
    @Autowired
    private SensitiveWordsMapper sensitiveWordsMapper;

    // 測試訪問下面地址觀察請求地址、界面返回數(shù)據(jù)及控制臺( 普通參數(shù) )
    // 無敏感詞 http://localhost:8080/info?content=tom&see=1&age=18
    // 英文敏感詞 http://localhost:8080/info?content=my%20content%20is%20tomcat&see=1&age=18
    // 漢字敏感詞 http://localhost:8080/info?content=%E7%8E%8B%E5%AE%89%E7%9F%B3%E5%94%90%E5%AE%8B%E5%85%AB%E5%A4%A7%E5%AE%B6&see=1
    // 多個敏感詞 http://localhost:8080/info?content=%E7%8E%8B%E5%AE%89%E7%9F%B3%E6%9C%89%E4%B8%80%E5%8F%AA%E7%8C%ABtomcat%E6%B1%A4%E5%A7%86%E5%87%AF%E7%89%B9&see=1&size=6
    // 插入一個字變成非敏感詞 http://localhost:8080/info?content=%E7%8E%8B%E7%8C%AB%E5%AE%89%E7%9F%B3%E6%9C%89%E4%B8%80%E5%8F%AA%E7%8C%ABtomcat%E6%B1%A4%E5%A7%86%E5%87%AF%E7%89%B9&see=1&size=6
    @GetMapping("/info")
    public String info(Article article) throws Exception {
        return ParamsConfig.toJson(article);
    }


    // 添加一個敏感詞然后再去觀察是否生效 http://localhost:8080/add
    // 觀察【貓】這個詞被過濾了 http://localhost:8080/info?content=%E7%8E%8B%E5%AE%89%E7%9F%B3%E6%9C%89%E4%B8%80%E5%8F%AA%E7%8C%ABtomcat%E6%B1%A4%E5%A7%86%E5%87%AF%E7%89%B9&see=1&size=6
    // 嵌套敏感詞處理 http://localhost:8080/info?content=%E7%8E%8B%E7%8C%AB%E5%AE%89%E7%9F%B3%E6%9C%89%E4%B8%80%E5%8F%AA%E7%8C%ABtomcat%E6%B1%A4%E5%A7%86%E5%87%AF%E7%89%B9&see=1&size=6
    // 多層嵌套敏感詞 http://localhost:8080/info?content=%E7%8E%8B%E7%8E%8B%E7%8C%AB%E5%AE%89%E7%9F%B3%E5%AE%89%E7%9F%B3%E6%9C%89%E4%B8%80%E5%8F%AA%E7%8C%ABtomcat%E6%B1%A4%E5%A7%86%E5%87%AF%E7%89%B9&see=1&size=6
    @GetMapping("/add")
    public String add() throws Exception {
        Long id = 3L;
        if (null == sensitiveWordsMapper.selectById(id)) {
            System.err.println("插入一個敏感詞:" + sensitiveWordsMapper.insert(new SensitiveWords(id, "貓")));
            // 插入一個敏感詞,刷新算法引擎敏感詞
            SensitiveWordsProcessor.reloadSensitiveWords();
        }
        return "ok";
    }

    // 測試訪問下面地址觀察控制臺( 請求json參數(shù) )
    // idea 執(zhí)行 resources 目錄 TestJson.http 文件測試
    @PostMapping("/json")
    public String json(@RequestBody Article article) throws Exception {
        return ParamsConfig.toJson(article);
    }
}

2.5 DDL 數(shù)據(jù)結構自動維護

解決升級表結構初始化,版本發(fā)布更新 SQL 維護問題,目前支持 MySql、PostgreSQL。

@Component
public class PostgresDdl implements IDdl {

    /**
     * 執(zhí)行 SQL 腳本方式
     */
    @Override
    public List<String> getSqlFiles() {
        return Arrays.asList(
                // 內(nèi)置包方式
                "db/tag-schema.sql",
                // 文件絕對路徑方式
                "D:\\db\\tag-data.sql"
        );
    }
}

不僅僅可以固定執(zhí)行,也可以動態(tài)執(zhí)行!!

ddlScript.run(new StringReader("DELETE FROM user;\n" +
                "INSERT INTO user (id, username, password, sex, email) VALUES\n" +
                "(20, 'Duo', '123456', 0, 'Duo@baomidou.com');"));

它還支持多數(shù)據(jù)源執(zhí)行?。?!

@Component
public class MysqlDdl implements IDdl {

    @Override
    public void sharding(Consumer<IDdl> consumer) {
        // 多數(shù)據(jù)源指定,主庫初始化從庫自動同步
        String group = "mysql";
        ShardingGroupProperty sgp = ShardingKey.getDbGroupProperty(group);
        if (null != sgp) {
            // 主庫
            sgp.getMasterKeys().forEach(key -> {
                ShardingKey.change(group + key);
                consumer.accept(this);
            });
            // 從庫
            sgp.getSlaveKeys().forEach(key -> {
                ShardingKey.change(group + key);
                consumer.accept(this);
            });
        }
    }

    /**
     * 執(zhí)行 SQL 腳本方式
     */
    @Override
    public List<String> getSqlFiles() {
        return Arrays.asList("db/user-mysql.sql");
    }
}

2.6 動態(tài)多數(shù)據(jù)源主從自由切換

@Sharding 注解使數(shù)據(jù)源不限制隨意使用切換,你可以在 mapper 層添加注解,按需求指哪打哪??!

@Mapper
@Sharding("mysql")
public interface UserMapper extends BaseMapper<User> {

    @Sharding("postgres")
    Long selectByUsername(String username);
}

你也可以自定義策略統(tǒng)一調(diào)兵遣將

@Component
public class MyShardingStrategy extends RandomShardingStrategy {

    /**
     * 決定切換數(shù)據(jù)源 key {@link ShardingDatasource}
     *
     * @param group 動態(tài)數(shù)據(jù)庫組
     * @param invocation {@link Invocation}
     * @param sqlCommandType {@link SqlCommandType}
     */
    @Override
    public void determineDatasourceKey(String group, Invocation invocation, SqlCommandType sqlCommandType) {
        // 數(shù)據(jù)源組 group 自定義選擇即可, keys 為數(shù)據(jù)源組內(nèi)主從多節(jié)點,可隨機選擇或者自己控制
        this.changeDatabaseKey(group, sqlCommandType, keys -> chooseKey(keys, invocation));
    }
}

可以開啟主從策略,當然也是可以開啟健康檢查!具體配置:

mybatis-mate:
  sharding:
    health: true # 健康檢測
    primary: mysql # 默認選擇數(shù)據(jù)源
    datasource:
      mysql: # 數(shù)據(jù)庫組
        - key: node1
          ...
        - key: node2
          cluster: slave # 從庫讀寫分離時候負責 sql 查詢操作,主庫 master 默認可以不寫
          ...
      postgres:
        - key: node1 # 數(shù)據(jù)節(jié)點
          ...

2.7 分布式事務日志打印

部分配置如下:

/**
 * <p>
 * 性能分析攔截器,用于輸出每條 SQL 語句及其執(zhí)行時間
 * </p>
 */
@Slf4j
@Component
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
        @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
        @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})})
public class PerformanceInterceptor implements Interceptor {
    /**
     * SQL 執(zhí)行最大時長,超過自動停止運行,有助于發(fā)現(xiàn)問題。
     */
    private long maxTime = 0;
    /**
     * SQL 是否格式化
     */
    private boolean format = false;
    /**
     * 是否寫入日志文件<br>
     * true 寫入日志文件,不阻斷程序執(zhí)行!<br>
     * 超過設定的最大執(zhí)行時長異常提示!
     */
    private boolean writeInLog = false;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Statement statement;
        Object firstArg = invocation.getArgs()[0];
        if (Proxy.isProxyClass(firstArg.getClass())) {
            statement = (Statement) SystemMetaObject.forObject(firstArg).getValue("h.statement");
        } else {
            statement = (Statement) firstArg;
        }
        MetaObject stmtMetaObj = SystemMetaObject.forObject(statement);
        try {
            statement = (Statement) stmtMetaObj.getValue("stmt.statement");
        } catch (Exception e) {
            // do nothing
        }
        if (stmtMetaObj.hasGetter("delegate")) {//Hikari
            try {
                statement = (Statement) stmtMetaObj.getValue("delegate");
            } catch (Exception e) {

            }
        }

        String originalSql = null;
        if (originalSql == null) {
            originalSql = statement.toString();
        }
        originalSql = originalSql.replaceAll("[\\s]+", " ");
        int index = indexOfSqlStart(originalSql);
        if (index > 0) {
            originalSql = originalSql.substring(index);
        }

        // 計算執(zhí)行 SQL 耗時
        long start = SystemClock.now();
        Object result = invocation.proceed();
        long timing = SystemClock.now() - start;

        // 格式化 SQL 打印執(zhí)行結果
        Object target = PluginUtils.realTarget(invocation.getTarget());
        MetaObject metaObject = SystemMetaObject.forObject(target);
        MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        StringBuilder formatSql = new StringBuilder();
        formatSql.append(" Time:").append(timing);
        formatSql.append(" ms - ID:").append(ms.getId());
        formatSql.append("\n Execute SQL:").append(sqlFormat(originalSql, format)).append("\n");
        if (this.isWriteInLog()) {
            if (this.getMaxTime() >= 1 && timing > this.getMaxTime()) {
                log.error(formatSql.toString());
            } else {
                log.debug(formatSql.toString());
            }
        } else {
            System.err.println(formatSql);
            if (this.getMaxTime() >= 1 && timing > this.getMaxTime()) {
                throw new RuntimeException(" The SQL execution time is too large, please optimize ! ");
            }
        }
        return result;
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties prop) {
        String maxTime = prop.getProperty("maxTime");
        String format = prop.getProperty("format");
        if (StringUtils.isNotEmpty(maxTime)) {
            this.maxTime = Long.parseLong(maxTime);
        }
        if (StringUtils.isNotEmpty(format)) {
            this.format = Boolean.valueOf(format);
        }
    }

    public long getMaxTime() {
        return maxTime;
    }

    public PerformanceInterceptor setMaxTime(long maxTime) {
        this.maxTime = maxTime;
        return this;
    }

    public boolean isFormat() {
        return format;
    }

    public PerformanceInterceptor setFormat(boolean format) {
        this.format = format;
        return this;
    }

    public boolean isWriteInLog() {
        return writeInLog;
    }

    public PerformanceInterceptor setWriteInLog(boolean writeInLog) {
        this.writeInLog = writeInLog;
        return this;
    }

    public Method getMethodRegular(Class<?> clazz, String methodName) {
        if (Object.class.equals(clazz)) {
            return null;
        }
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.getName().equals(methodName)) {
                return method;
            }
        }
        return getMethodRegular(clazz.getSuperclass(), methodName);
    }

    /**
     * 獲取sql語句開頭部分
     *
     * @param sql
     * @return
     */
    private int indexOfSqlStart(String sql) {
        String upperCaseSql = sql.toUpperCase();
        Set<Integer> set = new HashSet<>();
        set.add(upperCaseSql.indexOf("SELECT "));
        set.add(upperCaseSql.indexOf("UPDATE "));
        set.add(upperCaseSql.indexOf("INSERT "));
        set.add(upperCaseSql.indexOf("DELETE "));
        set.remove(-1);
        if (CollectionUtils.isEmpty(set)) {
            return -1;
        }
        List<Integer> list = new ArrayList<>(set);
        Collections.sort(list, Integer::compareTo);
        return list.get(0);
    }

    private final static SqlFormatter sqlFormatter = new SqlFormatter();

    /**
     * 格式sql
     *
     * @param boundSql
     * @param format
     * @return
     */
    public static String sqlFormat(String boundSql, boolean format) {
        if (format) {
            try {
                return sqlFormatter.format(boundSql);
            } catch (Exception ignored) {
            }
        }
        return boundSql;
    }
}

使用:

@RestController
@AllArgsConstructor
public class TestController {
    private BuyService buyService;

    // 數(shù)據(jù)庫 test 表 t_order 在事務一致情況無法插入數(shù)據(jù),能夠插入說明多數(shù)據(jù)源事務無效
    // 測試訪問 http://localhost:8080/test
    // 制造事務回滾 http://localhost:8080/test?error=true 也可通過修改表結構制造錯誤
    // 注釋 ShardingConfig 注入 dataSourceProvider 可測試事務無效情況
    @GetMapping("/test")
    public String test(Boolean error) {
        return buyService.buy(null != error && error);
    }
}

2.8 數(shù)據(jù)權限

mapper 層添加注解:

// 測試 test 類型數(shù)據(jù)權限范圍,混合分頁模式
@DataScope(type = "test", value = {
        // 關聯(lián)表 user 別名 u 指定部門字段權限
        @DataColumn(alias = "u", name = "department_id"),
        // 關聯(lián)表 user 別名 u 指定手機號字段(自己判斷處理)
        @DataColumn(alias = "u", name = "mobile")
})
@Select("select u.* from user u")
List<User> selectTestList(IPage<User> page, Long id, @Param("name") String username);

模擬業(yè)務處理邏輯:

@Bean
public IDataScopeProvider dataScopeProvider() {
    return new AbstractDataScopeProvider() {
        @Override
        protected void setWhere(PlainSelect plainSelect, Object[] args, DataScopeProperty dataScopeProperty) {
            // args 中包含 mapper 方法的請求參數(shù),需要使用可以自行獲取
            /*
                // 測試數(shù)據(jù)權限,最終執(zhí)行 SQL 語句
                SELECT u.* FROM user u WHERE (u.department_id IN ('1', '2', '3', '5'))
                AND u.mobile LIKE '%1533%'
             */
            if ("test".equals(dataScopeProperty.getType())) {
                // 業(yè)務 test 類型
                List<DataColumnProperty> dataColumns = dataScopeProperty.getColumns();
                for (DataColumnProperty dataColumn : dataColumns) {
                    if ("department_id".equals(dataColumn.getName())) {
                        // 追加部門字段 IN 條件,也可以是 SQL 語句
                        Set<String> deptIds = new HashSet<>();
                        deptIds.add("1");
                        deptIds.add("2");
                        deptIds.add("3");
                        deptIds.add("5");
                        ItemsList itemsList = new ExpressionList(deptIds.stream().map(StringValue::new).collect(Collectors.toList()));
                        InExpression inExpression = new InExpression(new Column(dataColumn.getAliasDotName()), itemsList);
                        if (null == plainSelect.getWhere()) {
                            // 不存在 where 條件
                            plainSelect.setWhere(new Parenthesis(inExpression));
                        } else {
                            // 存在 where 條件 and 處理
                            plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), inExpression));
                        }
                    } else if ("mobile".equals(dataColumn.getName())) {
                        // 支持一個自定義條件
                        LikeExpression likeExpression = new LikeExpression();
                        likeExpression.setLeftExpression(new Column(dataColumn.getAliasDotName()));
                        likeExpression.setRightExpression(new StringValue("%1533%"));
                        plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), likeExpression));
                    }
                }
            }
        }
    };
}

最終執(zhí)行 SQL 輸出:

SELECT u.* FROM user u
  WHERE (u.department_id IN ('1', '2', '3', '5'))
  AND u.mobile LIKE '%1533%' LIMIT 1, 10

目前僅有付費版本,了解更多 mybatis-mate 使用示例詳見:

https://gitee.com/baomidou/mybatis-mate-examples

到此這篇關于Mybatis-Plus 官方神器發(fā)布的文章就介紹到這了,更多相關Mybatis-Plus 官方神器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java常用工具類 Date日期、Mail郵件工具類

    java常用工具類 Date日期、Mail郵件工具類

    這篇文章主要為大家詳細介紹了java常用工具類,包括Date日期、Mail郵件工具類,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • Java 實現(xiàn)完整功能的學生管理系統(tǒng)實例

    Java 實現(xiàn)完整功能的學生管理系統(tǒng)實例

    讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Java實現(xiàn)一個完整版學生管理系統(tǒng),大家可以在過程中查缺補漏,提升水平
    2021-11-11
  • 如何在java 8 map中使用stream

    如何在java 8 map中使用stream

    這篇文章主要介紹了如何在java 8 map中使用stream,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • MyBatis開發(fā)Dao層的兩種方式實現(xiàn)(原始Dao層開發(fā))

    MyBatis開發(fā)Dao層的兩種方式實現(xiàn)(原始Dao層開發(fā))

    這篇文章主要介紹了MyBatis開發(fā)Dao層的兩種方式實現(xiàn)(原始Dao層開發(fā)),并對數(shù)據(jù)庫進行增刪查改,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • SpringBoot深入分析運行原理與功能實現(xiàn)

    SpringBoot深入分析運行原理與功能實現(xiàn)

    我們發(fā)現(xiàn)springBoot程序開發(fā)比spring程序編寫起來容易的多。配置簡潔,依賴關系簡單,啟動運行容易。那么結下了我們我們就要思考一下入門程序中的這些功能是怎么實現(xiàn)的
    2022-09-09
  • 一文弄懂Java中ThreadPoolExecutor

    一文弄懂Java中ThreadPoolExecutor

    ThreadPoolExecutor是Java中的一個線程池實現(xiàn),它可以管理和控制多個 Worker Threads,本文就詳細的介紹一下Java中ThreadPoolExecutor,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • SpringMVC的自定義攔截器詳解

    SpringMVC的自定義攔截器詳解

    這篇文章主要介紹了SpringMVC的自定義攔截器詳解,攔截器只會攔截訪問的控制器方法, 如果訪問的是jsp/html/css/image/js是不會進行攔截的,需要的朋友可以參考下
    2023-07-07
  • java讀取word-excel-ppt文件代碼

    java讀取word-excel-ppt文件代碼

    OFFICE文檔使用POI控件,PDF可以使用PDFBOX0.7.3控件,完全支持中文,用XPDF也行,不過感覺PDFBOX比較好,而且作者也在更新。水平有限,萬望各位指正
    2009-04-04
  • Java?Spring?Boot請求方式與請求映射過程分析

    Java?Spring?Boot請求方式與請求映射過程分析

    這篇文章主要介紹了Java?Spring?Boot請求方式與請求映射過程分析,Spring?Boot支持Rest風格:使用HTTP請求方式的動詞來表示對資源的操作
    2022-06-06
  • JVM角度調(diào)試優(yōu)化MyEclipse

    JVM角度調(diào)試優(yōu)化MyEclipse

    這篇文章主要介紹了從JVM角度對MyEclipse進行調(diào)試優(yōu)化,為大家分析調(diào)試優(yōu)化MyEclipse的步驟,感興趣的小伙伴們可以參考一下
    2016-05-05

最新評論