非存储字段搜索,适应灵活的搜索场景

1、非存储字段搜索

1.1 描述

通常根据本模型之外的信息作为搜索条件时,通常会把 这些字段放在代理模型上。这类场景我们称之为 非存储字段搜索

1.2 场景一

非存储字段为基本的String。
1.代码定义:非存储字段为基本的包装数据类型

    @Field(displayName = "确认密码", store = NullableBoolEnum.FALSE)
    private String confirmPassword;

2.设计器拖拽:列表中需要有退拽这个字段,字段是否隐藏的逻辑自身业务是否需要决定。
image.png
3.页面通过非存储字段为基本的包装数据类型进行搜索时。会拼在 queryWrapper 的属性queryData中,queryData为Map,key为字段名,value为搜索值。
image.png
4.后台逻辑处理代码示例:

        Map<String, Object> queryData = queryWrapper.getQueryData();
        if (null != queryData) {
            Object productIdObj = queryData.get(PRODUCT_ID);
            if (Objects.nonNull(productIdObj)) {
                String productId = productIdObj.toString();
                queryWrapper.lambda().eq(MesProduceOrderProxy::getProductId, productId);
            }
        }

1.3 场景二

非存储字段为非存储对象。

  1. 定义 为非存储的
    @Field(displayName = "款", store = NullableBoolEnum.FALSE)
    @Field.many2one
    @Field.Relation(store = false)
    private MesProduct product;

2.页面在搜索栏拖拽非存储字段作为搜索条件

image.png

3.后台逻辑处理代码示例:

      try {
            if (null != queryData && !queryData.isEmpty()) {
                List<Long> detailId = null;
                BasicSupplier supplier = JsonUtils.parseMap2Object((Map<String, Object>) queryData.get(supplierField), BasicSupplier.class);
                MesProduct product = JsonUtils.parseMap2Object((Map<String, Object>) queryData.get(productField), MesProduct.class);
                MesMaterial material = JsonUtils.parseMap2Object((Map<String, Object>) queryData.get(materialField), MesMaterial.class);
                if (supplier != null) {
                    detailId = bomService.queryBomDetailIdBySupplierId(supplier.getId());
                    if (CollectionUtils.isEmpty(detailId)) {
                        detailId.add(-1L);
                    }
                }

                if (product != null) {
                    List<Long> produceOrderId = produceOrderService.queryProductOrderIdByProductIds(product.getId());
                    if (CollectionUtils.isNotEmpty(produceOrderId)) {
                        queryWrapper.lambda().in(MesProduceBomSizes::getProduceOrderId, produceOrderId);
                    }
                }

                if (material != null) {
                    //找出两个bom列表的并集
                    List<Long> materBomDetailId = bomService.queryBomDetailIdByMaterialId(material.getId());
                    if (CollectionUtils.isNotEmpty(detailId)) {
                        detailId = detailId.stream().filter(materBomDetailId::contains).collect(Collectors.toList());
                    } else {
                        detailId = new ArrayList<>();
                        if (CollectionUtils.isEmpty(materBomDetailId)) {
                            detailId.add(-1L);
                        } else {
                            detailId.addAll(materBomDetailId);
                        }
                    }
                }
                if (CollectionUtils.isNotEmpty(detailId)) {
                    queryWrapper.lambda().in(MesProduceBomSizes::getProductBomId, detailId);
                }
            }
        } catch (Exception e) {
            log.error("queryData处理异常", e);
        }

注意: 如果这样定义

    @Field(displayName = "款",store = NullableBoolEnum.FALSE)
    @Field.Relation(relationFields = "produceId", referenceFields = "id",store = false)
    @Field.many2one
    private MesProduct product;

    @Field(displayName = "款Id",store = NullableBoolEnum.FALSE)
    private Long produceId;

搜索时 produceId 选择product 搜索是 produceId 会被拼接在QueryWrapper 的Rsql中

Rsql解析类

pro.shushi.pamirs.framework.gateways.rsql.RSQLHelper

Rsql参考代码

/**
     * Rsql解析 将属性字段值从QueryWrapper中originRsql属性值的Rsql解出来
     * 将原有条件替换成 ’1‘==’1‘
     *
     * @param queryWrapper 查询Wrapper
     * @param fields       需要解析出来的属性字段列表
     * @param valeMap      属性对应值的Map
     * @return 返回生产单Id列表
     */

    public static QueryWrapper convertWrapper(QueryWrapper queryWrapper, List<String> fields, Map<String, Object> valeMap) {
        if (StringUtils.isNotBlank(queryWrapper.getOriginRsql())) {
            String rsql = RSQLHelper.toTargetString(RSQLHelper.parse(queryWrapper.getModel(), queryWrapper.getOriginRsql()), new RSQLNodeConnector() {
                @Override
                public String comparisonConnector(RSQLNodeInfo nodeInfo) {
                    //判断字段为unStore,则进行替换
                    String field = nodeInfo.getField();
                    if (fields.contains(field)) {
                        valeMap.put(field, nodeInfo.getArguments().get(0));
                        RSQLNodeInfo newNode = new RSQLNodeInfo(nodeInfo.getType());
                        //设置查询字段为name
                        newNode.setField("1");
                        newNode.setOperator(RsqlSearchOperation.EQUAL.getOperator());
                        newNode.setArguments(Collections.singletonList("1"));
                        return super.comparisonConnector(newNode);
                    }
                    return super.comparisonConnector(nodeInfo);
                }
            });
            queryWrapper = Pops.f(Pops.query().from(queryWrapper.getModel())).get();
            //把RSQL转换成SQL
            String sql = RsqlParseHelper.parseRsql2Sql(queryWrapper.getModel(), rsql);
            if (StringUtils.isNotBlank(sql)) {
                queryWrapper.apply(sql);
            }
            return queryWrapper;
        }
        return queryWrapper;
    }

Oinone社区 作者:shao原创文章,如若转载,请注明出处:https://doc.oinone.top/dai-ma-shi-jian/5592.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

Like (0)
shao's avatarshao数式管理员
Previous 2024年2月20日 pm6:46
Next 2024年2月20日 pm6:52

相关推荐

  • 如何删除系统权限中默认的首页节点

    场景: 并没有设置过首页的配置,为什么在系统权限这里的配置菜单中却有首页的配置。而且显示当前资源未完成初始化设置,无法配置。这个文章将帮助你删除这个节点。 注意:如果添加了以下代码,后续如果需要使用首页的配置,则需要删除该代码。 扩展权限加载节点: 遍历权限加载的节点,找到需要删除的模块首页节点。删除节点。 @Component @Order(88) @SPI.Service public class MyTestNodeLoadExtend implements PermissionNodeLoadExtendApi { @Override public List<PermissionNode> buildRootPermissions(PermissionLoadContext loadContext, List<PermissionNode> nodes) { //删除 TopModule.MODULE_MODULE 的首页节点。 String homepage = TranslateUtils.translateValues(PermissionNodeLoaderConstants.HOMEPAGE_DISPLAY_VALUE); for (PermissionNode node : nodes) { //如果需要删除多个模块的首页,在这里多加一个逻辑与条件即可。 if (!(node instanceof ModulePermissionNode) || !TopModule.MODULE_MODULE.equals(((ModulePermissionNode) node).getModule())) { continue; } List<PermissionNode> permissionNodes = node.getNodes(); Iterator<PermissionNode> iterator = permissionNodes.iterator(); while (iterator.hasNext()) { PermissionNode permissionNode = iterator.next(); if (ResourcePermissionSubtypeEnum.HOMEPAGE.equals(permissionNode.getNodeType()) && homepage.equals(permissionNode.getDisplayValue())) { iterator.remove(); //如果是删除多个模块首页,这里的return改为break; return nodes; } } } return nodes; } } 看效果:首页节点成功删除。

    2024年12月31日
    1.7K00
  • 如何给角色增加菜单权限

    对接第三方的权限时,第三方传过来菜单项,需要拿着这些菜单在平台这边进行授权,可以使用代码的方式给指定菜单创建权限代码示例: public class demo { @Autowired private PermissionNodeLoader permissionNodeLoader; @Autowired private AuthRbacRolePermissionServiceImpl authRbacRolePermissionService; public void roleAuthorization() { ArrayList<Menu> menus = new ArrayList<>(); menus.add(new Menu().queryOneByWrapper(Pops.<Menu>lambdaQuery() .from(Menu.MODEL_MODEL) .eq(Menu::getName, "uiMenu90dd10ae7cc4459bacd2845754b658a8") .eq(Menu::getModule, TopModule.MODULE_MODULE))); menus.add(new Menu().queryOneByWrapper(Pops.<Menu>lambdaQuery() .from(Menu.MODEL_MODEL) .eq(Menu::getName, "TopMenus_shoppMenu_Shop3Menu_ShopSayHello52eMenu") .eq(Menu::getModule, TopModule.MODULE_MODULE))); //加载指定角色的全部资源权限项 ResourcePermissionNodeLoader loader = permissionNodeLoader.getManagementLoader(); List<PermissionNode> nodes = loader.buildRootPermissions(); List<AuthRbacResourcePermissionItem> authRbacRolePermissionProxies = new ArrayList<>(); //给指定角色创建权限,如果需要多个角色,可以for循环依次执行authRbacRolePermissionService.update(authRbacRolePermissionProxy) AuthRole authRole = new AuthRole().queryOneByWrapper(Pops.<AuthRole>lambdaQuery() .from(AuthRole.MODEL_MODEL) .eq(AuthRole::getCode, "R003") .eq(AuthRole::getName, "R003")); AuthRbacRolePermissionProxy authRbacRolePermissionProxy = new AuthRbacRolePermissionProxy(); AuthRole.transfer(authRole, authRbacRolePermissionProxy); for (PermissionNode node : nodes) { traverse(node, authRbacRolePermissionProxies, menus); } authRbacRolePermissionProxy.setResourcePermissions(authRbacRolePermissionProxies); authRbacRolePermissionService.update(authRbacRolePermissionProxy); } private void traverse(PermissionNode node, List<AuthRbacResourcePermissionItem> authRbacRolePermissionProxies, ArrayList<Menu> menus) { if (node == null) { return; } //按照指定菜单进行过滤,如果不是指定菜单,则设置菜单项不可访问,如果是指定菜单,则设置可访问 Set<Long> menuIds = new HashSet<>(); for (Menu menu : menus) { menuIds.add(menu.getId()); } if (node instanceof MenuPermissionNode) { AuthRbacResourcePermissionItem item = new AuthRbacResourcePermissionItem(); if (menuIds.contains(Long.parseLong(node.getId()))) { item.setCanAccess(Boolean.TRUE); } else { item.setCanAccess(Boolean.FALSE); } item.setCanManagement(node.getCanManagement()); item.setPath(node.getPath()); item.setSubtype(node.getNodeType()); item.setType(AuthEnumerationHelper.getResourceType(node.getNodeType())); item.setDisplayName(node.getDisplayValue()); item.setResourceId(node.getResourceId()); authRbacRolePermissionProxies.add(item); } List<PermissionNode> childNodes = node.getNodes(); if (CollectionUtils.isNotEmpty(childNodes)) { for (PermissionNode child : childNodes) { traverse(child, authRbacRolePermissionProxies, menus); } } } } 执行看效果

    2024年11月14日
    1.2K00
  • 左树右表,支撑不同场景的树表结构

    左树右表俩种情况 假设存在 A模型 B模型 1: 左树为A模型,右表为B模型 举例 A模型为类目 B模型为类目属性模型代码实例: @Model.model(AriesPlatformCategory.MODEL_MODEL) @Model(displayName = "平台后台类目", labelFields = "name") @Model.Advanced(type = ModelTypeEnum.PROXY) public class AriesPlatformCategory extends AriesCategory { public static final String MODEL_MODEL = "aries.item.AriesPlatformCategory"; @Field.many2one @Field.Relation(relationFields = {"parentCateCode"}, referenceFields = {"code"},store = true) @Field(displayName = "平台父类目") private AriesPlatformCategory platformCategory; @Field.one2many @Field(displayName = "类目属性") @Field.Relation(relationFields = "code", referenceFields = "categoryCode", store = true) private List<AriesPlatformCategoryAttr> platformCategoryAttrs; } @Model.model(AriesPlatformCategoryAttr.MODEL_MODEL) @Model(displayName = "Aries_平台类目属性", labelFields = "name") @Model.Advanced(type = ModelTypeEnum.PROXY) public class AriesPlatformCategoryAttr extends CategoryAttr { public static final String MODEL_MODEL = "aries.item.AriesPlatformCategoryAttr"; @Field.many2one @Field(displayName = "平台后台类目") @Field.Relation(relationFields = "categoryCode", referenceFields = "code", store = true) private AriesPlatformCategory platformCategory; } 在设计器设计左树右表之前,需要在模型 中配置好关联关系 。如下部分代码 配置好类目与父类目的关联关系。 @Field.many2one @Field.Relation(relationFields = {"parentCateCode"}, referenceFields = {"code"},store = true) @Field(displayName = "平台父类目") private AriesPlatformCategory platformCategory; 配置好 类目与类目属性的关联关系。一个类目可以有多个类目属性,一对多one2many @Field.one2many @Field(displayName = "类目属性") @Field.Relation(relationFields = "code", referenceFields = "categoryCode", store = true) private List<AriesPlatformCategoryAttr> platformCategoryAttrs; 在类目属性模型中,配置好属性与类目的关联关系,一个类目属性只属于一个类目,一个类目可以有多个类目属性。类目属性对类目多对一many2one @Field.many2one @Field(displayName = "平台后台类目") @Field.Relation(relationFields = "categoryCode", referenceFields = "code", store = true) private AriesPlatformCategory platformCategory; 设计器实例:1.需要选择 平台类目属性 做为主模型创建树表页面2.构建关联关系 选择平台后台类目 第一级的筛选条件 上级编码为空 表格关联关系字段 选择 平台类目属性。 3.表格拖拽好需要的属性字段 2: 左树为A模型,右表也为A模型 举例 左A模型 组织结构管理 右A模型 组织结构管理模型代码实例: @Model.model(BasicOrg.MODEL_MODEL) @Model(displayName = "组织结构管理", summary…

    2024年2月20日
    3.7K00
  • 如何跳过固定path路径下面所有的按钮权限

    场景: 业务上需要跳过弹窗打开里面的所有按钮权限。 实践: 实现AuthFilterService权限接口。 package pro.shushi.pamirs.top.api.spi; import org.apache.commons.lang3.StringUtils; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import pro.shushi.pamirs.auth.api.spi.AuthFilterService; import pro.shushi.pamirs.boot.web.session.AccessResourceInfoSession; import pro.shushi.pamirs.meta.common.spi.SPI; /** * @author Yexiu at 09:04 on 2024/9/27 */ @Order(88) @Component @SPI.Service public class CustomAuthFilterService implements AuthFilterService { public static final String skipPath = "/top_demo/uiMenuc6238c29bca44250a041691565056a63/ACTION#top.Teacher#uiView2b60cc6daa334c7280cb78207d41addc"; @Override public Boolean isAccessAction(String model, String name) { String path = AccessResourceInfoSession.getInfo().getOriginPath(); if (StringUtils.isNotEmpty(path) && path.startsWith(skipPath)) { //返回true就代表通过验证 return true; } return null; } @Override public Boolean isAccessAction(String path) { if (StringUtils.isNotEmpty(path) && path.startsWith(skipPath)) { //返回true就代表通过验证 return true; } return null; } } 可以看到弹窗下面的按钮都不需要权限控制了。

    2025年3月11日
    1.1K00
  • 如何在代码中使用自增ID和获取序列

    在使用继承IDModel或CodeModel时,id和code是系统默认自动生成, 默认值规则:ID–>分布式ID; CODE–>根据定义的SequenceConfig规则自动生成。 在特定情况下需要落库前先生成ID或者Code,这些场景下可参照如下代码示例 一、使用自增ID 单个字段设置方式 // 主键字段,可以使用mysql的自增能力 @Field.Integer @Field.PrimaryKey(keyGenerator = KeyGeneratorEnum.AUTO_INCREMENT) @Field.Advanced(batchStrategy = FieldStrategyEnum.NEVER) @Field(displayName = "id", summary = "Id字段,⾃增") private Long id; @Field.Integer @Field(displayName = "自增版本") @Field.Sequence(sequence = "SEQ", initial = 1) private Long version; 全局设置方式 该方式会作用到每一个存储模型的id字段,在application.yml配置文件中修改id的生成规则,查找配置项关键字key-generator,默认为DISTRIBUTION(分布式id),可修改为 AUTO_INCREMENT(自增id) 二、手动方式获取序列 获取方式示例1 /** * 在特定场景下需要手动生成Id或者code时,可参照这个示例 */ public void manualSetIdCode(){ DemoItem demoItem = new DemoItem(); //手动生成ID和code Object idObj = Spider.getDefaultExtension(IdGenerator.class).generate(PamirsTableInfo.fetchKeyGenerator(DemoItem.MODEL_MODEL)); demoItem.setId(TypeUtils.createLong(idObj)); Object codeObj = CommonApiFactory.getSequenceGenerator().generate("SEQ",DemoItem.MODEL_MODEL); String code = TypeUtils.stringValueOf(codeObj); demoItem.setCode(code); //…… } 获取方式示例2 1、在系统启动的时候初始化SequenceConfig package pro.shushi.pamirs.demo.core.init; import org.springframework.stereotype.Component; import pro.shushi.pamirs.boot.common.api.command.AppLifecycleCommand; import pro.shushi.pamirs.boot.common.extend.MetaDataEditor; import pro.shushi.pamirs.core.common.InitializationUtil; import pro.shushi.pamirs.demo.api.DemoModule; import pro.shushi.pamirs.demo.core.constant.SeqConstants; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.meta.Meta; import pro.shushi.pamirs.meta.enmu.SequenceEnum; import java.util.Map; /** * DemoMetadataEditor */ @Slf4j @Component public class DemoMetadataEditor implements MetaDataEditor { @Override public void edit(AppLifecycleCommand command, Map<String, Meta> metaMap) { InitializationUtil util = InitializationUtil.get(metaMap, DemoModule.MODULE_MODULE, DemoModule.MODULE_NAME); if (util == null) { log.error("获取初始化序列失败"); return; } bizSequence(util); } private void bizSequence(InitializationUtil util) { util.createSequenceConfig("申请单编码生成", SeqConstants.NABEL_SAMPLE_APPLY_SEQ, SequenceEnum.ORDERLY_SEQ, 8) .setStep(1) .setInitial(80000000L) .setIsRandomStep(false); util.createSequenceConfig("订单编码生成", SeqConstants.NABEL_SAMPLE_ORDER_SEQ_YP, SequenceEnum.ORDERLY_SEQ, 8) .setPrefix("YP") .setStep(1) .setInitial(80000000L) .setIsRandomStep(false); } } 2、在代码中使用序列 public static String getSaleOrderCode() { Object sequence = CommonApiFactory.getSequenceGenerator().generate(SequenceEnum.ORDERLY_SEQ.value(), SeqConstants.NABEL_SAMPLE_STRUCTURE_SEQ); return TypeUtils.stringValueOf(sequence); } public static String getApplyOrderCode(String prefix) { Object sequence = CommonApiFactory.getSequenceGenerator().generate(SequenceEnum.ORDERLY_SEQ.value(), SeqConstants.NABEL_SAMPLE_APPLY_SEQ); return…

    2024年5月25日
    2.2K00

Leave a Reply

Please Login to Comment