0、简介 mybatismate为mp企业级模块,支持分库分表,数据审计、数据敏感词过滤(AC算法),字段加密,字典回写(数据绑定),数据权限,表结构自动生成SQL维护等,旨在更敏捷优雅处理数据。1、主要功能字典绑定字段加密数据脱敏表结构动态维护数据审计记录数据范围(数据权限)数据库分库分表、动态数据源、读写分离、数据库健康检查自动切换。2、使用2。1依赖导入 SpringBoot引入自动依赖注解包dependencygroupIdcom。baomidougroupIdmybatismatestarterartifactIdversion1。0。8versiondependency 注解(实体分包使用)dependencygroupIdcom。baomidougroupIdmybatismateannotationartifactIdversion1。0。8versiondependency2。2字段数据绑定(字典回写) 例如usersex类型sex字典结果映射到sexText属性FieldDict(typeusersex,targetsexText)privateIprivateStringsexT 实现IDataDict接口提供字典数据源,注入到Spring容器即可。ComponentpublicclassDataDictimplementsIDataDict{从数据库或缓存中获取privateMapString,StringSEXMAPnewConcurrentHashMapString,String(){{put(0,女);put(1,男);}};OverridepublicStringgetNameByCode(FieldDictfieldDict,Stringcode){System。err。println(字段类型:fieldDict。type(),编码:code);returnSEXMAP。get(code);}}2。3字段加密 属性FieldEncrypt注解即可加密存储,会自动解密查询结果,支持全局配置加密密钥算法,及注解密钥算法,可以实现IEncryptor注入自定义算法。FieldEncrypt(algorithmAlgorithm。PBEWithMD5AndDES)privateS2。4字段脱敏 属性FieldSensitive注解即可自动按照预设策略对源数据进行脱敏处理,默认SensitiveType内置9种常用脱敏策略。 例如:中文名、银行卡账号、手机号码等脱敏策略。 也可以自定义策略如下:FieldSensitive(typetestStrategy)privateSFieldSensitive(typeSensitiveType。mobile)privateS 自定义脱敏策略testStrategy添加到默认策略中注入Spring容器即可。ConfigurationpublicclassSensitiveStrategyConfig{注入脱敏策略BeanpublicISensitiveStrategysensitiveStrategy(){自定义testStrategy类型脱敏处理returnnewSensitiveStrategy()。addStrategy(testStrategy,tttest);}} 例如文章敏感词过滤演示文章敏感词过滤RestControllerpublicclassArticleController{AutowiredprivateSensitiveWordsMappersensitiveWordsM测试访问下面地址观察请求地址、界面返回数据及控制台(普通参数)无敏感词http:localhost:8080info?contenttomsee1age18英文敏感词http:localhost:8080info?contentmy20content20is20tomcatsee1age18汉字敏感词http:localhost:8080info?contentE78E8BE5AE89E79FB3E59490E5AE8BE585ABE5A4A7E5AEB6see1多个敏感词http:localhost:8080info?contentE78E8BE5AE89E79FB3E69C89E4B880E58FAAE78CABtomcatE6B1A4E5A786E587AFE789B9see1size6插入一个字变成非敏感词http:localhost:8080info?contentE78E8BE78CABE5AE89E79FB3E69C89E4B880E58FAAE78CABtomcatE6B1A4E5A786E587AFE789B9see1size6GetMapping(info)publicStringinfo(Articlearticle)throwsException{returnParamsConfig。toJson(article);}添加一个敏感词然后再去观察是否生效http:localhost:8080add观察【猫】这个词被过滤了http:localhost:8080info?contentE78E8BE5AE89E79FB3E69C89E4B880E58FAAE78CABtomcatE6B1A4E5A786E587AFE789B9see1size6嵌套敏感词处理http:localhost:8080info?contentE78E8BE78CABE5AE89E79FB3E69C89E4B880E58FAAE78CABtomcatE6B1A4E5A786E587AFE789B9see1size6多层嵌套敏感词http:localhost:8080info?contentE78E8BE78E8BE78CABE5AE89E79FB3E5AE89E79FB3E69C89E4B880E58FAAE78CABtomcatE6B1A4E5A786E587AFE789B9see1size6GetMapping(add)publicStringadd()throwsException{Longid3L;if(nullsensitiveWordsMapper。selectById(id)){System。err。println(插入一个敏感词:sensitiveWordsMapper。insert(newSensitiveWords(id,猫)));插入一个敏感词,刷新算法引擎敏感词SensitiveWordsProcessor。reloadSensitiveWords();}}测试访问下面地址观察控制台(请求json参数)idea执行resources目录TestJson。http文件测试PostMapping(json)publicStringjson(RequestBodyArticlearticle)throwsException{returnParamsConfig。toJson(article);}}2。5DDL数据结构自动维护 解决升级表结构初始化,版本发布更新SQL维护问题,目前支持MySql、PostgreSQL。ComponentpublicclassPostgresDdlimplementsIDdl{执行SQL脚本方式OverridepublicListStringgetSqlFiles(){returnArrays。asList(内置包方式dbtagschema。sql,文件绝对路径方式D:dbtagdata。sql);}} 不仅仅可以固定执行,也可以动态执行!!ddlScript。run(newStringReader(DELETEFROMINSERTINTOuser(id,username,password,sex,email)VALUES(20,Duo,123456,0,Duobaomidou。com);)); 它还支持多种数据源执行!!!ComponentpublicclassMysqlDdlimplementsIDdl{Overridepublicvoidsharding(ConsumerIDdlconsumer){多数据源指定,主库初始化从库自动同步SShardingGroupPropertysgpShardingKey。getDbGroupProperty(group);if(null!sgp){主库sgp。getMasterKeys()。forEach(key{ShardingKey。change(groupkey);consumer。accept(this);});从库sgp。getSlaveKeys()。forEach(key{ShardingKey。change(groupkey);consumer。accept(this);});}}执行SQL脚本方式OverridepublicListStringgetSqlFiles(){returnArrays。asList(dbusermysql。sql);}}2。6动态多数据源主从自由切换 Sharding注解使数据源不限制随意使用切换,你可以在mapper层添加注解,按需求指哪打哪!!MapperSharding(mysql)publicinterfaceUserMapperextendsBaseMapperUser{Sharding(postgres)LongselectByUsername(Stringusername);} 你也可以自定义策略统一调兵遣将ComponentpublicclassMyShardingStrategyextendsRandomShardingStrategy{决定切换数据源key{linkShardingDatasource}paramgroup动态数据库组paraminvocation{linkInvocation}paramsqlCommandType{linkSqlCommandType}OverridepublicvoiddetermineDatasourceKey(Stringgroup,Invocationinvocation,SqlCommandTypesqlCommandType){数据源组group自定义选择即可,keys为数据源组内主从多节点,可随机选择或者自己控制this。changeDatabaseKey(group,sqlCommandType,keyschooseKey(keys,invocation));}} 可以开启主从策略,当然也是可以开启健康检查!!! 具体配置:mybatismate:sharding:health:trueahrefhttps:www。q578。coml160targetblankclassinfotextkey健康a检测primary:mysql默认选择数据源datasource:mysql:数据库组key:node1。。。key:node2cluster:slave从库读写分离时候负责sql查询操作,主库master默认可以不写。。。postgres:key:node1数据节点。。。2。7分布式事务日志打印 部分配置如下:p性能分析拦截器,用于输出每条SQL语句及其执行时间Slf4jComponentIntercepts({Signature(typeStatementHandler。class,methodquery,args{Statement。class,ResultHandler。class}),Signature(typeStatementHandler。class,methodupdate,args{Statement。class}),Signature(typeStatementHandler。class,methodbatch,args{Statement。class})})publicclassPerformanceInterceptorimplementsInterceptor{SQL执行最大时长,超过自动停止运行,有助于发现问题。privatelongmaxTime0;SQL是否格式化是否写入日志文件 true写入日志文件,不阻断程序执行! 超过设定的最大执行时长异常提示!privatebooleanwriteInLOverridepublicObjectintercept(Invocationinvocation)throwsThrowable{SObjectfirstArginvocation。getArgs()〔0〕;if(Proxy。isProxyClass(firstArg。getClass())){statement(Statement)SystemMetaObject。forObject(firstArg)。getValue(h。statement);}else{statement(Statement)firstA}MetaObjectstmtMetaObjSystemMetaObject。forObject(statement);try{statement(Statement)stmtMetaObj。getValue(stmt。statement);}catch(Exceptione){donothing}if(stmtMetaObj。hasGetter(delegate)){Hikaritry{statement(Statement)stmtMetaObj。getValue(delegate);}catch(Exceptione){}}StringoriginalSif(originalSqlnull){originalSqlstatement。toString();}originalSqloriginalSql。replaceAll(〔s〕,);intindexindexOfSqlStart(originalSql);if(index0){originalSqloriginalSql。substring(index);}计算执行SQL耗时longstartSystemClock。now();Objectresultinvocation。proceed();longtimingSystemClock。now()格式化SQL打印执行结果ObjecttargetPluginUtils。realTarget(invocation。getTarget());MetaObjectmetaObjectSystemMetaObject。forObject(target);MappedStatementms(MappedStatement)metaObject。getValue(delegate。mappedStatement);StringBuilderformatSqlnewStringBuilder();formatSql。append(Time:)。append(timing);formatSql。append(msID:)。append(ms。getId());formatSql。append(ExecuteSQL:)。append(sqlFormat(originalSql,format))。append();if(this。isWriteInLog()){if(this。getMaxTime()1timingthis。getMaxTime()){log。error(formatSql。toString());}else{log。debug(formatSql。toString());}}else{System。err。println(formatSql);if(this。getMaxTime()1timingthis。getMaxTime()){thrownewRuntimeException(TheSQLexecutiontimeistoolarge,pleaseoptimize!);}}}OverridepublicObjectplugin(Objecttarget){if(targetinstanceofStatementHandler){returnPlugin。wrap(target,this);}}OverridepublicvoidsetProperties(Propertiesprop){StringmaxTimeprop。getProperty(maxTime);Stringformatprop。getProperty(format);if(StringUtils。isNotEmpty(maxTime)){this。maxTimeLong。parseLong(maxTime);}if(StringUtils。isNotEmpty(format)){this。formatBoolean。valueOf(format);}}publiclonggetMaxTime(){returnmaxT}publicPerformanceInterceptorsetMaxTime(longmaxTime){this。maxTimemaxT}publicbooleanisFormat(){}publicPerformanceInterceptorsetFormat(booleanformat){this。}publicbooleanisWriteInLog(){returnwriteInL}publicPerformanceInterceptorsetWriteInLog(booleanwriteInLog){this。writeInLogwriteInL}publicMethodgetMethodRegular(C?clazz,StringmethodName){if(Object。class。equals(clazz)){}for(Methodmethod:clazz。getDeclaredMethods()){if(method。getName()。equals(methodName)){}}returngetMethodRegular(clazz。getSuperclass(),methodName);}获取sql语句开头部分paramsqlreturnprivateintindexOfSqlStart(Stringsql){StringupperCaseSqlsql。toUpperCase();SetIntegersetnewHashSet();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)){return1;}ListIntegerlistnewArrayList(set);Collections。sort(list,Integer::compareTo);returnlist。get(0);}privatefinalstaticSqlFormattersqlFormatternewSqlFormatter();格式sqlparamboundSqlparamformatreturnpublicstaticStringsqlFormat(StringboundSql,booleanformat){if(format){try{returnsqlFormatter。format(boundSql);}catch(Exceptionignored){}}returnboundS}} 使用:RestControllerAllArgsConstructorpublicclassTestController{privateBuyServicebuyS数据库test表torder在事务一致情况无法插入数据,能够插入说明多数据源事务无效测试访问http:localhost:8080test制造事务回滚http:localhost:8080test?errortrue也可通过修改表结构制造错误注释ShardingConfig注入dataSourceProvider可测试事务无效情况GetMapping(test)publicStringtest(Booleanerror){returnbuyService。buy(null!errorerror);}}2。8数据权限 mapper层添加注解:测试test类型数据权限范围,混合分页模式DataScope(typetest,value{关联表user别名u指定部门字段权限DataColumn(aliasu,namedepartmentid),关联表user别名u指定手机号字段(自己判断处理)DataColumn(aliasu,namemobile)})Select(selectu。fromuseru)ListUserselectTestList(IPageUserpage,Longid,Param(name)Stringusername); 模拟业务处理逻辑:BeanpublicIDataScopeProviderdataScopeProvider(){returnnewAbstractDataScopeProvider(){OverrideprotectedvoidsetWhere(PlainSelectplainSelect,Object〔〕args,DataScopePropertydataScopeProperty){args中包含mapper方法的请求参数,需要使用可以自行获取测试数据权限,最终执行SQL语句SELECTu。FROMuseruWHERE(u。departmentidIN(1,2,3,5))ANDu。mobileLIKE1533if(test。equals(dataScopeProperty。getType())){业务test类型ListDataColumnPropertydataColumnsdataScopeProperty。getColumns();for(DataColumnPropertydataColumn:dataColumns){if(departmentid。equals(dataColumn。getName())){追加部门字段IN条件,也可以是SQL语句SetStringdeptIdsnewHashSet();deptIds。add(1);deptIds。add(2);deptIds。add(3);deptIds。add(5);ItemsListitemsListnewExpressionList(deptIds。stream()。map(StringValue::new)。collect(Collectors。toList()));InExpressioninExpressionnewInExpression(newColumn(dataColumn。getAliasDotName()),itemsList);if(nullplainSelect。getWhere()){不存在where条件plainSelect。setWhere(newParenthesis(inExpression));}else{存在where条件and处理plainSelect。setWhere(newAndExpression(plainSelect。getWhere(),inExpression));}}elseif(mobile。equals(dataColumn。getName())){支持一个自定义条件LikeExpressionlikeExpressionnewLikeExpression();likeExpression。setLeftExpression(newColumn(dataColumn。getAliasDotName()));likeExpression。setRightExpression(newStringValue(1533));plainSelect。setWhere(newAndExpression(plainSelect。getWhere(),likeExpression));}}}}};} 最终执行SQL输出:SELECTu。FROMuseruWHERE(u。departmentidIN(1,2,3,5))ANDu。mobileLIKE1533LIMIT1,10 目前仅有付费版本,了解更多mybatismate使用示例详见: https:gitee。combaomidoumybatismateexamples 原文链接:https:mp。weixin。qq。comsygzsFpeT2jsjcAgUseHLQg