Java整合mybatis實(shí)現(xiàn)過(guò)濾數(shù)據(jù)
場(chǎng)景
- 權(quán)限1:只能看到自己創(chuàng)建的數(shù)據(jù)
- 權(quán)限2:只能看到本部門(mén)的數(shù)據(jù)
- 權(quán)限3:查看全部數(shù)據(jù)
例子
小明有權(quán)限1:
{ "code": "200", "msg": "查詢成功", "data": [ { "name": "name1", "id": "1", "creater": "xiaoming" }, { "name": "name2", "id": "2", "creater": "xiaoming" } ] }
大明具有權(quán)限2,小明相同部門(mén)
{ "code": "200", "msg": "查詢成功", "data": [ { "name": "name1", "id": "1", "creater": "xiaoming" }, { "name": "name2", "id": "2", "creater": "xiaoming" }, { "name": "name3", "id": "3", "creater": "daming" }, { "name": "name4", "id": "4", "creater": "daming" } ] }
領(lǐng)導(dǎo)有權(quán)限3,可以看到全部
{ "code": "200", "msg": "查詢成功", "data": [ { "name": "name1", "id": "1", "creater": "xiaoming" }, { "name": "name2", "id": "2", "creater": "xiaoming" }, { "name": "name3", "id": "3", "creater": "daming" }, { "name": "name4", "id": "4", "creater": "daming" }, { "name": "name5", "id": "5", "creater": "mingming" } ] }
執(zhí)行流程
- Configuration:初始化基礎(chǔ)配置,比如 MyBatis 的別名等,一些重要的類型對(duì)象,如插件,映射器,ObjectFactory 和 TypeHandler對(duì)象, MyBatis所有的配置信息都維持在 Configuration 對(duì)象之中。
- SqlSessionFactory:SqlSession工廠。
- SqlSession:作為MyBatis工作的主要頂層API,表示和數(shù)據(jù)庫(kù)交互的會(huì)話,完成必要的數(shù)據(jù)庫(kù)增刪改查功能。
- Executor:真正執(zhí)行sql語(yǔ)句的對(duì)象,調(diào)用 sqlSession 的方法時(shí),本質(zhì)上都是調(diào)用 executor 的方法,還負(fù)責(zé)獲取 connection,創(chuàng)建 StatementHandler ,責(zé)調(diào)用 StatementHandler 操作數(shù)據(jù)庫(kù) ,并把結(jié)果集通過(guò) ResultSetHandler 進(jìn)行自動(dòng)映射,另外,它還處理二級(jí)緩存的操作。
- StatementHandler:可以理解為是一次語(yǔ)句的執(zhí)行,創(chuàng)建并持有 ParameterHandler 和 ResultSetHandler 對(duì)象,操作 dbc 的statement與進(jìn)行數(shù)據(jù)庫(kù)操作,另外它也實(shí)現(xiàn)了MyBatis的一級(jí)緩存。
- ParameterHandler: 處理入?yún)ⅲ瑢ava方法上的參數(shù)設(shè)置到被執(zhí)行語(yǔ)句中
- ResultSetHandler:處理返回結(jié)果,處理jdbc的返回值,將其轉(zhuǎn)換為java的對(duì)象
- TypeHandler:負(fù)責(zé)Java數(shù)據(jù)類型和JDBC數(shù)據(jù)類型之間的映射和轉(zhuǎn)換,在 ParameterHandler 和 ResultsetHandler 中
- MappedStatement:MappedStatement維護(hù)了一條 <select|update|delete|insert> 節(jié)點(diǎn)的封裝。
- SqlSource:負(fù)責(zé)根據(jù)用戶傳遞的 parameterObject,動(dòng)態(tài)地生成 SQL 語(yǔ)句,將信息封裝到 BoundSql 對(duì)象中,并返回。
- BoundSql:表示動(dòng)態(tài)生成的 SQL 語(yǔ)句以及相應(yīng)的參數(shù)信息。
配置切面
- Interceptor: 實(shí)現(xiàn) Interceptor 接口,mybatis 的攔截器
- @Intercepts:只有一個(gè)屬性,即value,其返回值類型是一個(gè)@Signature類型的數(shù)組,表示我們可以配置多個(gè)@Signature注解
- @Signature:一個(gè)方法簽名,其共有三個(gè)屬性,分別為:type、method、args
- type:攔截的四種類型:Executor - 執(zhí)行器方法 、StatementHandler - 攔截SQL語(yǔ)法構(gòu)建處理、ParameterHandler - 攔截參數(shù)處理、ResultSetHandler - 攔截結(jié)果集處理
- method:對(duì)應(yīng)接口中的某一個(gè)方法名,比如 Executor 的 query 方法
- args:對(duì)應(yīng)接口中的某一個(gè)方法的參數(shù),比如 Executor 中 query 方法因?yàn)橹剌d原因,有多個(gè),args就是指明參數(shù)類型,從而確定是具體哪一個(gè)方法;
@Intercepts({<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->@Signature(type = org.apache.ibatis.executor.Executor.class, method = "query", args = {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})@Slf4jpublic class MapperPermissionInterceptor implements Interceptor {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E--> @Override public Object intercept(Invocation invocation) throws Throwable {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E--> Object target = invocation.getTarget(); //被代理對(duì)象 Method method = invocation.getMethod(); //代理方法 Object[] args = invocation.getArgs(); //方法參數(shù)MappedStatement mappedStatement = (MappedStatement) args[0]; Object parameterObject = args[1]; // do something ...方法攔截前執(zhí)行代碼塊 Object result = invocation.proceed(); // do something ...方法攔截后執(zhí)行代碼塊 return result; } }@Intercepts({@Signature(type = org.apache.ibatis.executor.Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) @Slf4j public class MapperPermissionInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { Object target = invocation.getTarget(); //被代理對(duì)象 Method method = invocation.getMethod(); //代理方法 Object[] args = invocation.getArgs(); //方法參數(shù) MappedStatement mappedStatement = (MappedStatement) args[0]; Object parameterObject = args[1]; // do something ...方法攔截前執(zhí)行代碼塊 Object result = invocation.proceed(); // do something ...方法攔截后執(zhí)行代碼塊 return result; } }
方案
原 originalSql
select id, name, creater from tt
通過(guò) mybatis 的切面實(shí)現(xiàn)
在前面添加 select * from ( ,后面添加 where 條件
select * from ( select id, name, creater from tt ) tmp where creater = "daming"
實(shí)現(xiàn)
- 配置權(quán)限開(kāi)關(guān)
- 判斷方法名是否包含 list 或者 page
- 添加 where 條件
@Intercepts({@Signature(type = org.apache.ibatis.executor.Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) @Slf4j public class MapperPermissionInterceptor implements Interceptor { @Autowired PermissionProperty permissionProperty; public static final String PACK_START_SQL = "select * from ( "; public static final String PACK_END_SQL = ") tmp "; public static final String PERMISSION_Y = "y"; @Override public Object intercept(Invocation invocation) throws Throwable { if(!PERMISSION_Y.toLowerCase().equals(permissionProperty.getMapper().toLowerCase())){ log.info("mapper 權(quán)限未開(kāi)啟"); return invocation.proceed(); } MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; Object parameter = invocation.getArgs()[1]; BoundSql boundSql = mappedStatement.getBoundSql(parameter); String originalSql = boundSql.getSql().trim(); String id = mappedStatement.getId(); log.info("originalSql: {} ", originalSql); log.info("id: {}", id); String name = getMapperName(id); String method = getMapperMethod(id); log.info("name: {}, method: {} ", name, method); String joinSql = dataPermissionSqlProvider().getJoinSql(name, method); log.info("joinSql: {} ", joinSql); if (Optional.ofNullable(joinSql).isPresent()) { BoundSql newBoundSql = copyFromBoundSql(mappedStatement, boundSql, this.joinSql(originalSql, joinSql)); ParameterMap map = mappedStatement.getParameterMap(); MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql), map); invocation.getArgs()[0] = newMs; } return invocation.proceed(); } /** * 獲取 Mapper 名稱 * @param id * @return */ private String getMapperName(String id) { String name = id.substring(0, id.lastIndexOf(".")); return name.substring(name.lastIndexOf(".") + 1); } /** * 獲取 Mapper 方法 * @param id * @return */ private String getMapperMethod(String id) { String method = id.substring(id.lastIndexOf(".") + 1); return method; } private DataPermissionProvider dataPermissionSqlProvider() { return (DataPermissionProvider) ApplicationContextUtil.getBean("dataPermissionProvider"); } private String joinSql(String sql, String selectSql) { sql = PACK_START_SQL + sql + PACK_END_SQL + selectSql; log.info("packSql: {}", sql); return sql; } public static class BoundSqlSqlSource implements SqlSource { BoundSql boundSql; public BoundSqlSqlSource(BoundSql boundSql) { this.boundSql = boundSql; } @Override public BoundSql getBoundSql(Object parameterObject) { return boundSql; } } private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql) { BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject()); for (ParameterMapping mapping : boundSql.getParameterMappings()) { String prop = mapping.getProperty(); if (boundSql.hasAdditionalParameter(prop)) { newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop)); } } return newBoundSql; } /** * 復(fù)制MappedStatement對(duì)象 */ private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource, ParameterMap parameterMap) { MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType()); builder.resource(ms.getResource()); builder.fetchSize(ms.getFetchSize()); builder.statementType(ms.getStatementType()); builder.keyGenerator(ms.getKeyGenerator()); builder.timeout(ms.getTimeout()); builder.parameterMap(parameterMap); builder.resultMaps(ms.getResultMaps()); builder.resultSetType(ms.getResultSetType()); builder.cache(ms.getCache()); builder.flushCacheRequired(ms.isFlushCacheRequired()); builder.useCache(ms.isUseCache()); return builder.build(); } }
到此這篇關(guān)于Java整合mybatis實(shí)現(xiàn)過(guò)濾數(shù)據(jù)的文章就介紹到這了,更多相關(guān)Java mybatis過(guò)濾數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
簡(jiǎn)單了解Java方法的定義和使用實(shí)現(xiàn)詳解
這篇文章主要介紹了簡(jiǎn)單了解Java方法的定義和使用實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12java反射之通過(guò)反射了解集合泛型的本質(zhì)(詳解)
下面小編就為大家?guī)?lái)一篇java反射之通過(guò)反射了解集合泛型的本質(zhì)(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06SpringCloud?Ribbon負(fù)載均衡流程分析
在Eureka注冊(cè)中心中我們?cè)谔砑油闌LoadBalanced注解,即可實(shí)現(xiàn)負(fù)載均衡功能,現(xiàn)在一起探索一下負(fù)載均衡的原理(Ribbon),感興趣的朋友一起看看吧2024-03-03SpringBoot項(xiàng)目使用yml文件鏈接數(shù)據(jù)庫(kù)異常問(wèn)題解決方案
在使用SpringBoot時(shí),利用yml進(jìn)行數(shù)據(jù)庫(kù)連接配置需小心數(shù)據(jù)類型區(qū)分,如果用戶名或密碼是數(shù)字,必須用雙引號(hào)包裹以識(shí)別為字符串,避免連接錯(cuò)誤,特殊字符密碼也應(yīng)用引號(hào)包裹2024-10-10