阿里云网站建设的实训报告,沈阳住房和城乡建设厅网站,住房城乡建设证书查询,网站是如何做的功能实现
规则转换为 SQL 片段
规则解析
首先我们来构造一个典型的规则#xff0c;包括两个条件组#xff0c;每个组由两个条件组成#xff0c;由且与或两种逻辑关系#xff0c;如下图#xff1a; 然后看看生成的规则#xff0c;如下#xff1a;
{filt…功能实现
规则转换为 SQL 片段
规则解析
首先我们来构造一个典型的规则包括两个条件组每个组由两个条件组成由且与或两种逻辑关系如下图 然后看看生成的规则如下
{filters: [{conditions: [{property: paramName,value: 1},{operator: contains,property: paramKey,value: password}],logicalOperator: and},{conditions: [{property: paramValue,value: 1},{operator: empty,property: orderNo}],logicalOperator: or}],logicalOperator: and
}最后分析其数据结构可以分成三层。
最外层是一个对象由两个属性组成一是 filters条件组集合二是 logicalOperator逻辑关系and或者or。filter 对象自身同样由两个属性组成一是 conditions条件集合二是 logicalOperator逻辑关系。condition 对象由三个属性组成一是 property属性二是 operator操作符三是 value值。若为相等操作则操作符属性可省略。
同时对于数值类日期类可能进行区间查询筛选器生成的规则中condition 对象仍有三个属性组成不变只是 value 值变成了一个两元素的数组如
{operator:between,property:age,value:[18,60]}对象构建
我们在视图对象层 vo 中创建规则对应的数据对象遵循由内到外的方式来构建。 首先是最内层的筛选条件属性和操作符是固化的值可能是单元素也可能为数组类型可能是字符串也可能是数值。对于前端 js属于非强类型语言可以灵活设置但对于后端强类型的 java需要将其设置为 Object 类型进行二次解析。
package tech.abc.platform.entityconfig.vo;import lombok.Data;/*** 数据筛选条件** author wqliu* date 2024-08-06*/
Data
public class DataFilterConditionVO {/*** 属性*/private String property;/*** 操作*/private String operator;/*** 值*/private Object value;}
然后是中间层数据筛选组如下
package tech.abc.platform.entityconfig.vo;import lombok.Data;import java.util.List;/*** 数据筛选组** author wqliu* date 2024-08-06*/
Data
public class DataFilterGroupVO {/*** 数据筛选条件集合*/private ListDataFilterConditionVO conditions;/*** 逻辑操作*/private String logicalOperator;
}
最后是最外层的规则如下
package tech.abc.platform.entityconfig.vo;import lombok.Data;import java.util.List;/*** 数据筛选规则** author wqliu* date 2024-08-06*/
Data
public class DataFilterRuleVO {/*** 数据筛选组集合*/private ListDataFilterGroupVO filters;/*** 逻辑操作*/private String logicalOperator;
}
数据传递
在规则配置页面再加一个按钮将规则传给后端如下 前端代码如下 // 生成SQL片段generateSqlPart() {// 先调用一次生成规则避免配置调整了规则未同步this.generateRule()// 调用后端服务转换this.api.generateSqlPart(this.entityData.modelId, this.entityData.rule).then((res) {this.entityData.sqlPart res.data})}// 实体模型数据权限
export const entityModelDataPermission Object.assign({}, COMMON_METHOD, {serveUrl: / moduleName / entityModelDataPermission /,// 获取实体模型完整属性列表getOrInit(modelId) {return request.get({ url: this.serveUrl getOrInit, params: { modelId } })},// 生成sql片段generateSqlPart(entityModelId, rule) {return request.post({ url: this.serveUrl entityModelId /generateSqlPart, data: rule })}
})
后端控制器如下 /*** 生成SQL片段*/PostMapping(/{id}/generateSqlPart)SystemLog(value 实体模型数据权限-生成SQL片段)PreAuthorize(hasPermission(null,entityconfig:entityModelDataPermission:generateSqlPart))public ResponseEntityResult generateSqlPart(PathVariable(id) String id, RequestBody String rule) {String sqlPart entityModelDataPermissionService.generateSqlPart(id, rule);return ResultUtil.success(sqlPart);}我们尝试使用 FastJson将字符串解析成对象后端服务如下 Overridepublic String generateSqlPart(String id, String rule) {DataFilterRuleVO dataFilterRule JSON.parseObject(rule, DataFilterRuleVO.class);return ;}
进入调试模式查看数据已完成解析工作如下
转换处理
接下来我们开始最复杂的转换处理同样遵循由简单到复杂的情况。 首先最简单的只有一个逻辑组组中只有一个条件如下 转换方法如下 Overridepublic String generateSqlPart(String id, String rule) {String result ;// 转换数据DataFilterRuleVO dataFilterRule JSON.parseObject(rule, DataFilterRuleVO.class);// 获取组集合ListDataFilterGroupVO dataFilterGroupList dataFilterRule.getFilters();// 遍历组集合for (DataFilterGroupVO dataFilterGroup : dataFilterGroupList) {// 获取条件集合ListDataFilterConditionVO conditionList dataFilterGroup.getConditions();// 遍历条件集合for (DataFilterConditionVO condition : conditionList) {// 获取字段名,命名风格驼峰转换成下划线String fieldName CommonUtil.camelToUnderline(condition.getProperty());// 获取操作String operator condition.getOperator();if (StringUtils.isEmpty(operator)) {operator ;}Object value condition.getValue();result fieldName operator value ;}}return result;}转换结果 可以看到输出了预期的 sql 片段。
启用数据权限组件
调整 Mybatisplus 的插件配置增加数据权限插件如下图所示 注意数据权限插件是后期新增的功能要求 mybatisplus 的版本不能太低建议 mybatis-plus-boot-starter 的版本使用 3.5.4。 其中数据权限处理器需要自行实现如下
package tech.abc.platform.framework.extension;import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Table;
import org.apache.commons.lang3.StringUtils;
import tech.abc.platform.common.exception.SessionExpiredException;
import tech.abc.platform.common.utils.SpringUtil;
import tech.abc.platform.common.utils.UserUtil;
import tech.abc.platform.entityconfig.service.EntityModelDataPermissionService;/*** 数据权限处理器** author wqliu* date 2024-08-03*/
Slf4j
public class MyDataPermissionHandler implements MultiDataPermissionHandler {/*** 数据权限配置表名称*/public static final String DATA_PERMISSION_CONFIG_TABLE_NAME cfg_entity_model_data_permission;Overridepublic Expression getSqlSegment(Table table, Expression where, String mappedStatementId) {// 数据权限相关的 SQL 片段String tableName table.getName();// 排除数据权限配置表否则会导致死循环if (tableName.equals(DATA_PERMISSION_CONFIG_TABLE_NAME)) {return null;}// 获取数据权限 SQL 片段EntityModelDataPermissionService entityModelDataPermissionService SpringUtil.getBean(EntityModelDataPermissionService.class);String sqlSegment entityModelDataPermissionService.getDataPermissionSqlPart(tableName);if (sqlSegment ! null) {String userId ;// 登录阶段获取不到当前用户信息视为不做数据权限过滤try {userId UserUtil.getId();} catch (SessionExpiredException e) {return null;}sqlSegment StringUtils.replace(sqlSegment, {CurrentUserId}, userId);try {return CCJSqlParserUtil.parseCondExpression(sqlSegment);} catch (JSQLParserException e) {log.error(数据权限 SQL 片段解析失败, e);return null;}} else {return null;}}
}这里有几个需要特别注意的点
需要将数据权限配置表排除否则会导致死循环引发堆栈溢出。通过平台的工具类 UserUtil 来获取到当前用户信息但在系统登录环节尚未完成认证会抛出会话超时异常同样需要忽略否则会影响正常系统登录。在本环节中可以将平台约定预置的运行期变量如当前用户标识、当前用户所在部门等替换为真实的运行数据如 sqlSegment StringUtils.replace(sqlSegment, “{CurrentUserId}”, userId);
查看效果
访问平台的系统参数菜单执行查询操作如下图 可以看到数据权限过滤已经发挥了作用控制台打印输出的 sql无论是获取分页的 sql还是最终执行的 sql都自动追加了数据权限过滤的 SQL 片段如下 Preparing: SELECT COUNT(*) AS total FROM sys_param WHERE delete_flag NO AND param_value 10Parameters: Columns: totalRow: 2Total: 1Preparing: SELECT id, param_name, param_key, param_value, order_no, delete_flag, create_id, create_time, update_id, update_time, version FROM sys_param WHERE delete_flag NO AND param_value 10 ORDER BY order_no ASC LIMIT ?Parameters: 10(Long)Columns: id, param_name, param_key, param_value, order_no, delete_flag, create_id, create_time, update_id, update_time, versionRow: 1158917826028863489, 用户登录最多输错次数, PASSWORD_INPUT_ERROR_TIMES, 10, 004, NO, 1, 2019-08-07 09:48:36, 1, 2020-08-26 03:21:29, 5Row: 1158917976734400513, 账号锁定自动解锁时间间隔分, ACCOUNT_UNLOCK_INTERVAL, 10, 005, NO, 1, 2019-08-07 09:49:12, , 2023-03-24 10:47:21, 3Total: 2
小结
至此已完成了数据权限的整体框架开发但也只是框架各环节还有大量的工作需要完善主要包括以下几点
配置规则时需要增加用户、部门、角色等维度将数据筛选器生成的各种场景下的复杂规则转换为 SQL 片段读取平台运行时变量替换掉预置的用户、部门等占位符
开源平台资料
平台名称一二三开发平台 简介 企业级通用开发平台 设计资料[csdn专栏] 开源地址[Gitee] 开源协议MIT 如果您在阅读本文时获得了帮助或受到了启发希望您能够喜欢并收藏这篇文章为它点赞~ 请在评论区与我分享您的想法和心得一起交流学习不断进步遇见更加优秀的自己