Java整合mybatis實現(xiàn)過濾數(shù)據(jù)
更新時間:2023年01月14日 10:11:33 作者:我有一只肥螳螂
這篇文章主要介紹了Java整合mybatis實現(xiàn)過濾數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
場景
- 權限1:只能看到自己創(chuàng)建的數(shù)據(jù)
- 權限2:只能看到本部門的數(shù)據(jù)
- 權限3:查看全部數(shù)據(jù)
例子
小明有權限1:
{
"code": "200",
"msg": "查詢成功",
"data": [
{
"name": "name1",
"id": "1",
"creater": "xiaoming"
},
{
"name": "name2",
"id": "2",
"creater": "xiaoming"
}
]
}
大明具有權限2,小明相同部門
{
"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"
}
]
}
領導有權限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:初始化基礎配置,比如 MyBatis 的別名等,一些重要的類型對象,如插件,映射器,ObjectFactory 和 TypeHandler對象, MyBatis所有的配置信息都維持在 Configuration 對象之中。
- SqlSessionFactory:SqlSession工廠。
- SqlSession:作為MyBatis工作的主要頂層API,表示和數(shù)據(jù)庫交互的會話,完成必要的數(shù)據(jù)庫增刪改查功能。
- Executor:真正執(zhí)行sql語句的對象,調(diào)用 sqlSession 的方法時,本質(zhì)上都是調(diào)用 executor 的方法,還負責獲取 connection,創(chuàng)建 StatementHandler ,責調(diào)用 StatementHandler 操作數(shù)據(jù)庫 ,并把結果集通過 ResultSetHandler 進行自動映射,另外,它還處理二級緩存的操作。
- StatementHandler:可以理解為是一次語句的執(zhí)行,創(chuàng)建并持有 ParameterHandler 和 ResultSetHandler 對象,操作 dbc 的statement與進行數(shù)據(jù)庫操作,另外它也實現(xiàn)了MyBatis的一級緩存。
- ParameterHandler: 處理入?yún)?,將java方法上的參數(shù)設置到被執(zhí)行語句中
- ResultSetHandler:處理返回結果,處理jdbc的返回值,將其轉(zhuǎn)換為java的對象
- TypeHandler:負責Java數(shù)據(jù)類型和JDBC數(shù)據(jù)類型之間的映射和轉(zhuǎn)換,在 ParameterHandler 和 ResultsetHandler 中
- MappedStatement:MappedStatement維護了一條 <select|update|delete|insert> 節(jié)點的封裝。
- SqlSource:負責根據(jù)用戶傳遞的 parameterObject,動態(tài)地生成 SQL 語句,將信息封裝到 BoundSql 對象中,并返回。
- BoundSql:表示動態(tài)生成的 SQL 語句以及相應的參數(shù)信息。
配置切面
- Interceptor: 實現(xiàn) Interceptor 接口,mybatis 的攔截器
- @Intercepts:只有一個屬性,即value,其返回值類型是一個@Signature類型的數(shù)組,表示我們可以配置多個@Signature注解
- @Signature:一個方法簽名,其共有三個屬性,分別為:type、method、args
- type:攔截的四種類型:Executor - 執(zhí)行器方法 、StatementHandler - 攔截SQL語法構建處理、ParameterHandler - 攔截參數(shù)處理、ResultSetHandler - 攔截結果集處理
- method:對應接口中的某一個方法名,比如 Executor 的 query 方法
- args:對應接口中的某一個方法的參數(shù),比如 Executor 中 query 方法因為重載原因,有多個,args就是指明參數(shù)類型,從而確定是具體哪一個方法;
@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(); //被代理對象 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(); //被代理對象
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
通過 mybatis 的切面實現(xiàn)
在前面添加 select * from ( ,后面添加 where 條件
select * from ( select id, name, creater from tt ) tmp where creater = "daming"
實現(xià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 權限未開啟");
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;
}
/**
* 復制MappedStatement對象
*/
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();
}
}到此這篇關于Java整合mybatis實現(xiàn)過濾數(shù)據(jù)的文章就介紹到這了,更多相關Java mybatis過濾數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot項目使用yml文件鏈接數(shù)據(jù)庫異常問題解決方案
在使用SpringBoot時,利用yml進行數(shù)據(jù)庫連接配置需小心數(shù)據(jù)類型區(qū)分,如果用戶名或密碼是數(shù)字,必須用雙引號包裹以識別為字符串,避免連接錯誤,特殊字符密碼也應用引號包裹2024-10-10

