日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MyBatisPlus 又搞事情,发布权限神器!

發布時間:2023/12/16 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MyBatisPlus 又搞事情,发布权限神器! 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊關注公眾號:互聯網架構師,后臺回復?2T獲取2TB學習資源!

上一篇:Alibaba開源內網高并發編程手冊.pdf

MyBatis-Mate 為 mp 企業級模塊,支持分庫分表,數據審計、數據敏感詞過濾(AC算法),字段加密,字典回寫(數據綁定),數據權限,表結構自動生成 SQL 維護等,旨在更敏捷優雅處理數據。

主要功能

  • 字典綁定

  • 字段加密

  • 數據脫敏

  • 表結構動態維護

  • 數據審計記錄

  • 數據范圍(數據權限)

  • 數據庫分庫分表、動態據源、讀寫分離、數- - 據庫健康檢查自動切換。

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 字段數據綁定(字典回寫)

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

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

實現IDataDict 接口提供字典數據源,注入到 Spring 容器即可。

@Component public?class?DataDict?implements?IDataDict?{/***?從數據庫或緩存中獲取*/private?Map<String,?String>?SEX_MAP?=?new?ConcurrentHashMap<String,?String>()?{{put("0",?"女");put("1",?"男");}};@Overridepublic?String?getNameByCode(FieldDict?fieldDict,?String?code)?{System.err.println("字段類型:"?+?fieldDict.type()?+?",編碼:"?+?code);return?SEX_MAP.get(code);} }

2.3 字段加密

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

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

2.4 字段脫敏

屬性@FieldSensitive 注解即可自動按照預設策略對源數據進行脫敏處理,默認 SensitiveType 內置 9 種常用脫敏策略。

例如:中文名、銀行卡賬號、手機號碼等 脫敏策略。

也可以自定義策略如下:

@FieldSensitive(type?=?"testStrategy") private?String?username;@FieldSensitive(type?=?SensitiveType.mobile) private?String?mobile;

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

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

例如文章敏感詞過濾

/***?演示文章敏感詞過濾*/ @RestController public?class?ArticleController?{@Autowiredprivate?SensitiveWordsMapper?sensitiveWordsMapper;//?測試訪問下面地址觀察請求地址、界面返回數據及控制臺(?普通參數?)//?無敏感詞?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參數?)//?idea?執行?resources?目錄?TestJson.http?文件測試@PostMapping("/json")public?String?json(@RequestBody?Article?article)?throws?Exception?{return?ParamsConfig.toJson(article);} }

2.5 DDL 數據結構自動維護

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

@Component public?class?PostgresDdl?implements?IDdl?{/***?執行?SQL?腳本方式*/@Overridepublic?List<String>?getSqlFiles()?{return?Arrays.asList(//?內置包方式"db/tag-schema.sql",//?文件絕對路徑方式"D:\\db\\tag-data.sql");} }

不僅僅可以固定執行,也可以動態執行!!

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');"));

它還支持多數據源執行!!!

@Component public?class?MysqlDdl?implements?IDdl?{@Overridepublic?void?sharding(Consumer<IDdl>?consumer)?{//?多數據源指定,主庫初始化從庫自動同步,公眾?號Java精選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);});}}/***?執行?SQL?腳本方式*/@Overridepublic?List<String>?getSqlFiles()?{return?Arrays.asList("db/user-mysql.sql");} }

2.6 動態多數據源主從自由切換

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

@Mapper @Sharding("mysql") public?interface?UserMapper?extends?BaseMapper<User>?{@Sharding("postgres")Long?selectByUsername(String?username); }

你也可以自定義策略統一調兵遣將

@Component public?class?MyShardingStrategy?extends?RandomShardingStrategy?{/***?決定切換數據源?key?{@link?ShardingDatasource}**?@param?group??????????動態數據庫組*?@param?invocation?????{@link?Invocation}*?@param?sqlCommandType?{@link?SqlCommandType}*/@Overridepublic?void?determineDatasourceKey(String?group,?Invocation?invocation,?SqlCommandType?sqlCommandType)?{//?數據源組?group?自定義選擇即可,?keys?為數據源組內主從多節點,可隨機選擇或者自己控制this.changeDatabaseKey(group,?sqlCommandType,?keys?->?chooseKey(keys,?invocation));} }

可以開啟主從策略,當然也是可以開啟健康檢查!!!

具體配置:

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

2.7 分布式事務日志打印

部分配置如下:

/***?<p>*?性能分析攔截器,用于輸出每條?SQL?語句及其執行時間*?</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 執行最大時長,超過自動停止運行,有助于發現問題。*/private?long?maxTime?=?0;/***?SQL?是否格式化*/private?boolean?format?=?false;/***?是否寫入日志文件<br>* true 寫入日志文件,不阻斷程序執行!<br>*?超過設定的最大執行時長異常提示!*/private?boolean?writeInLog?=?false;@Overridepublic?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"))?{//Hikaritry?{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);}//?計算執行?SQL?耗時long?start?=?SystemClock.now();Object?result?=?invocation.proceed();long?timing?=?SystemClock.now()?-?start;//?格式化?SQL?打印執行結果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;}@Overridepublic?Object?plugin(Object?target)?{if?(target?instanceof?StatementHandler)?{return?Plugin.wrap(target,?this);}return?target;}@Overridepublic?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;//?數據庫?test?表?t_order?在事務一致情況無法插入數據,能夠插入說明多數據源事務無效//?測試訪問?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 數據權限

mapper 層添加注解:

//?測試?test?類型數據權限范圍,混合分頁模式 @DataScope(type?=?"test",?value?=?{//?關聯表?user?別名?u?指定部門字段權限@DataColumn(alias?=?"u",?name?=?"department_id"),//?關聯表?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);

模擬業務處理邏輯:

@Bean public?IDataScopeProvider?dataScopeProvider()?{return?new?AbstractDataScopeProvider()?{@Overrideprotected?void?setWhere(PlainSelect?plainSelect,?Object[]?args,?DataScopeProperty?dataScopeProperty)?{//?args?中包含?mapper?方法的請求參數,需要使用可以自行獲取/*//?測試數據權限,最終執行?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()))?{//?業務?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));}}}}}; }

最終執行 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

-End-

最后,關注公眾號互聯網架構師,在后臺回復:2T,可以獲取我整理的 Java 系列面試題和答案,非常齊全。

正文結束

推薦閱讀 ↓↓↓

1.全新 IDEA 2022.2 正式發布,新特性真香!

2.從零開始搭建創業公司后臺技術棧

3.程序員一般可以從什么平臺接私活?

4.Spring中毒太深,離開Spring我連最基本的CRUD都不會寫了...

5.為什么國內 996 干不過國外的 955呢?

6.中國的鐵路訂票系統在世界上屬于什么水平?? ? ? ? ? ? ? ? ? ? ? ??

7.15張圖看懂瞎忙和高效的區別!

總結

以上是生活随笔為你收集整理的MyBatisPlus 又搞事情,发布权限神器!的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。