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

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低代码应用平台体验

(0)
shao的头像shao数式管理员
上一篇 2024年2月20日 pm6:46
下一篇 2024年2月20日 pm6:52

相关推荐

  • 对字段进行加密存储

    需求: 模型字段上使用 pro.shushi.pamirs.user.api.crypto.annotation.EncryptField 注解模型动作上使用 pro.shushi.pamirs.user.api.crypto.annotation.NeedDecrypt 注解 示例: 对需要加密的字段添加@EncryptField注解 @Model.model(Student.MODEL_MODEL) @Model(displayName = "学生", summary = "学生") public class Student extends IdModel { public static final String MODEL_MODEL = "top.Student"; @Field(displayName = "学生名字") @Field.String private String studentName; @Field(displayName = "学生ID") @Field.Integer private Long studentId; @Field(displayName = "学生卡号") @Field.String @EncryptField private String studentCard; } 对函数添加@NeedDecrypt注解 @Action.Advanced(name = FunctionConstants.create, managed = true)//默认取的是方法名 @Action(displayName = "确定", summary = "添加", bindingType = ViewTypeEnum.FORM) @Function(name = FunctionConstants.create)//默认取的是方法名 @Function.fun(FunctionConstants.create)//默认取的是方法名 @NeedDecrypt public Student create(Student data) { String studentCard = data.getStudentCard(); if (studentCard != null) { //自定义加密方法 data.setStudentCard(StudentEncoder.encode(studentCard)); } return data.create(); }

    2024年10月10日
    1.2K00
  • IWrapper、QueryWrapper和LambdaQueryWrapper使用

    条件更新updateByWrapper 通常我们在更新的时候new一个对象出来在去更新,减少更新的字段 Integer update = new DemoUser().updateByWrapper(new DemoUser().setFirstLogin(Boolean.FALSE), Pops.<DemoUser>lambdaUpdate().from(DemoUser.MODEL_MODEL).eq(IdModel::getId, userId) 使用基础模型的updateById方法更新指定字段的方法: new 一下update对象出来,更新这个对象。 WorkflowUserTask userTaskUp = new WorkflowUserTask(); userTaskUp.setId(userTask.getId()); userTaskUp.setNodeContext(json); userTaskUp.updateById(); 条件删除updateByWrapper public List<T> delete(List<T> data) { List<Long> petTypeIdList = new ArrayList(); for(T item:data){ petTypeIdList.add(item.getId()); } Models.data().deleteByWrapper(Pops.<PetType>lambdaQuery().from(PetType.MODEL_MODEL).in(PetType::getId,petTypeIdList)); return data; } 构造条件查询数据 示例1: LambdaQueryWrapper拼接查询条件 private void queryPetShops() { LambdaQueryWrapper<PetShop> query = Pops.<PetShop>lambdaQuery(); query.from(PetShop.MODEL_MODEL); query.setSortable(Boolean.FALSE); query.orderBy(true, true, PetShop::getId); List<PetShop> petShops2 = new PetShop().queryList(query); System.out.printf(petShops2.size() + ""); } 示例2: IWrapper拼接查询条件 private void queryPetShops() { IWrapper<PetShop> wrapper = Pops.<PetShop>lambdaQuery() .from(PetShop.MODEL_MODEL).eq(PetShop::getId,1L); List<PetShop> petShops4 = new PetShop().queryList(wrapper); System.out.printf(petShops4.size() + ""); } 示例3: QueryWrapper拼接查询条件 private void queryPetShops() { //使用Lambda获取字段名,防止后面改字段名漏改 String nameField = LambdaUtil.fetchFieldName(PetTalent::getName); //使用Lambda获取Clumon名,防止后面改字段名漏改 String nameColumn = PStringUtils.fieldName2Column(nameField); QueryWrapper<PetShop> wrapper2 = new QueryWrapper<PetShop>().from(PetShop.MODEL_MODEL) .eq(nameColumn, "test"); List<PetShop> petShops5 = new PetShop().queryList(wrapper2); System.out.printf(petShops5.size() + ""); } IWrapper转为LambdaQueryWrapper @Function.Advanced(type= FunctionTypeEnum.QUERY) @Function.fun(FunctionConstants.queryPage) @Function(openLevel = {FunctionOpenEnum.API}) public Pagination<PetShopProxy> queryPage(Pagination<PetShopProxy> page, IWrapper<PetShopProxy> queryWrapper) { LambdaQueryWrapper<PetShopProxy> wrapper = ((QueryWrapper<PetShopProxy>) queryWrapper).lambda(); // 非存储字段从QueryData中获取 Map<String, Object> queryData = queryWrapper.getQueryData(); if (null != queryData && !queryData.isEmpty()) { String codes = (String) queryData.get("codes"); if (org.apache.commons.lang3.StringUtils.isNotBlank(codes)) { wrapper.in(PetShopProxy::getCode, codes.split(",")); } } return new PetShopProxy().queryPage(page, wrapper); }

    2024年5月25日
    1.9K00
  • 如何跳过固定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日
    83600
  • 同一行操作跳转到不同的视图(动态表单)

    背景 实际项目中,存在这样的场景:同一列表中的数据是泛化的数据集合,即数据来源于不同的模型;行操作需要根据来源去向不同的目标页。 如下图,「提报」操作需根据「报表类型」去向不同的表单。 并支持目标弹窗标题和弹框大小的配置。 解决思路 每行记录需要跳转到不同的模型不同视图,增加一个配置页面用于维护源模型和目标模型的调整动作关系; 返回数据的时候,同时返回自定义的动作。 前端自定义实现如上面图例中的「填报」,从返回数据中获取ViewAction并做对应的跳转。 具体步骤 [后端] 建立模型和视图的关系设置的模型 1、创建 模型和视图的关系设置的模型,用于配置列表模型和各记录即目标模型的视图关系 import pro.shushi.oinone.examples.simple.api.proxy.system.SimpleModel; import pro.shushi.oinone.examples.simple.api.proxy.system.SimpleModule; import pro.shushi.pamirs.boot.base.enmu.ActionTargetEnum; import pro.shushi.pamirs.boot.base.model.View; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.base.IdModel; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; /** * 模型和视图的关系设置 * ModelRelViewSetting */ @Model.model(ModelRelViewSetting.MODEL_MODEL) @Model(displayName = "模型和视图的关系设置", summary = "模型和视图的关系设置") @Model.Advanced(unique = {"oModel,model,target,viewType,viewName"}) public class ModelRelViewSetting extends IdModel { public static final String MODEL_MODEL = "examples.custom.ModelRelViewSetting"; @Field.many2one @Field(displayName = "模块") @Field.Relation(relationFields = {"module"}, referenceFields = {"module"}) private SimpleModule moduleDef; @Field.String @Field(displayName = "模块编码", invisible = true) private String module; @Field.many2one @Field(displayName = "源模型") @Field.Relation(relationFields = {"oModel"}, referenceFields = {"model"}) private SimpleModel originModel; @Field.String @Field(displayName = "源模型编码", invisible = true) private String oModel; @Field.many2one @Field(displayName = "目标模型") @Field.Relation(relationFields = {"model"}, referenceFields = {"model"}) private SimpleModel targetModel; @Field.String @Field(displayName = "目标模型编码", invisible = true) private String model; @Field.Enum @Field(displayName = "视图类型") private ViewTypeEnum viewType; @Field.Enum @Field(displayName = "打开方式", required = true) private ActionTargetEnum target; @Field.String @Field(displayName = "动作名称", invisible = true) private String name; @Field.many2one @Field.Relation(relationFields = {"model", "viewName"}, referenceFields = {"model", "name"}, domain = "systemSource=='UI'") @Field(displayName = "绑定页面", summary = "绑定页面") private View view; @Field.String @Field(displayName = "视图/页面", invisible…

    2025年2月19日
    88500
  • 推送自定义消息

    项目中添加消息依赖 pro.shushi.pamirs.core pamirs-message-api 调用pro.shushi.pamirs.message.engine.message.MessageSender#sendSystemMail发送系统消息示例: @Action(displayName = "发送消息") public Student sendMessage(Student data){ MessageSender mailSender = (MessageSender) MessageEngine.get(MessageEngineTypeEnum.MAIL_SEND).get(null); String content = "发送自定义消息"; String subject = null; List<Long> userIds = new ArrayList<>(); userIds.add(PamirsSession.getUserId()); PamirsMessage message = new PamirsMessage() .setName(subject) .setSubject(subject) .setBody(content) .setMessageType(MessageTypeEnum.NOTIFICATION); List<PamirsMessage> messages = new ArrayList<>(); messages.add(message); SystemMessage systemMessage = new SystemMessage(); systemMessage.setPartners(userIds.stream().map(i -> (PamirsUser) new PamirsUser().setId(i)).collect(Collectors.toList())) .setType(MessageGroupTypeEnum.SYSTEM_MAIL) .setMessages(messages); mailSender.sendSystemMail(systemMessage); return data; }

    2024年8月19日
    1.2K00

Leave a Reply

登录后才能评论