代码示例:快速找到示例代码

1、图表设计器

数据可视化能加载到的接口,方法上需要加 category = FunctionCategoryEnum.QUERY_PAGE

@Model.model(ExpensesIncome.MODEL_MODEL)
@Component
@Slf4j
public class ExpensesIncomeAction {

    @Function.Advanced(type = FunctionTypeEnum.QUERY,category = FunctionCategoryEnum.QUERY_PAGE)
    @Function.fun(FunctionConstants.queryPage)
    @Function(openLevel = {FunctionOpenEnum.API})
    public Pagination<ExpensesIncome> queryPage(Pagination<ExpensesIncome> page, IWrapper<ExpensesIncome> queryWrapper) {
        page = new ExpensesIncome().queryPage(page, queryWrapper);

        if (page!=null && CollectionUtils.isNotEmpty(page.getContent())) {
            page.getContent().forEach(a->{
                if (a.getBudgetInCome()!=null && a.getBudgetInCome().compareTo(new BigDecimal("0.0"))!=0) {
                    if (a.getRetailAmount()!=null) {
                        a.setInComeRate(a.getRetailAmount().divide(a.getBudgetInCome(),2));
                    }
                }
            });
        }

        return page;
    }
}

2、事务支持

1)对于单个系统(InJvm)/模型内部采用强事务的方式。比如:在库存转移时,库存日志和库存数量的变化在一个事务中,保证两个表的数据同时成功或者失败。
2)强事务管理采用编码式,Oinone事务管理兼容Spring的事务管理方式;有注解的方式和代码块的方式。
a) 使用注解的方式:

    @Override
    @Transactional
    public void awardOut(AwardBookOutEmpRecordDetail detail) {
        List<OutEmpRecordSubjectDetail> subjectDetails = detail.getSubjectDetails();
        ……
    }

重要说明
基于注解的事务,Bean和加注解的方法必须能被Spring切面到。

b) 使用编码方式:

  //组装数据/获取数据/校验
  Tx.build(new TxConfig()).executeWithoutResult(status -> {
      // 1、保存部门数据
      deliDepartmentService.createOrUpdateBatch(departments);

      //2、如果父进行了下级关联设置,处理下级关联设置的逻辑
      for (DeliDepartment department : departments) {
          doDepartSubLink(department);
      }
  });
  …………

3)对于分布式事务采用最终数据一致性,借助【可靠消息】或者【Job】的方式来实现。

3、平台工具类使用

3.1 FetchUtil

pro.shushi.pamirs.core.common.FetchUtil,重点关注

# 根据Id查询列表
pro.shushi.pamirs.core.common.FetchUtil#fetchMapByIds

# 根据Id查询,返回Map
pro.shushi.pamirs.core.common.FetchUtil#fetchListByIds

# 根据Codes查询列表
pro.shushi.pamirs.core.common.FetchUtil#fetchMapByCodes

# 根据Code查询,返回Map
pro.shushi.pamirs.core.common.FetchUtil#fetchListByCodes

# 根据Entity查询
pro.shushi.pamirs.core.common.FetchUtil#fetchOne

其他更多方法参考这个类的源代码

3.2 ListUtils

pro.shushi.pamirs.meta.common.util.ListUtils

# 把输入的List,按给定的长度进行分组
pro.shushi.pamirs.meta.common.util.ListUtils#fixedGrouping

# 从给定的List中返回特定字段的数组,忽略Null并去重
pro.shushi.pamirs.meta.common.util.ListUtils#transform

4、枚举获取

根据枚举的name获取value
Integer value = ArchivesConfigTypeEnum.getValueByName(ArchivesConfigTypeEnum.class,“status1”);
根据枚举的name获取枚举项
ArchivesConfigTypeEnum typeEnum = TtypeEnum.getEnum(ArchivesConfigTypeEnum.class, “status1”);

5、Map类型的数据怎么定义,即ttype 为map的字段写法

@Field(displayName = "上下文", store = NullableBoolEnum.TRUE, serialize = JSON)
@Field.Advanced(columnDefinition = "TEXT")
private Map<String, Object> context;

6、后端获取前端请求中的variables

PamirsRequestVariables requestVariables = PamirsSession.getRequestVariables();

7、为什么有时候调用服务走远程了

1、假设:
A模型(modelA)所在的模块(ModuleA)
B模型(modelB)所在的模块(ModuleB)

部署方式决定调用方式:
1)部署方式1:
ModuleA 和 ModuleB 部署在一个jvm中,此时:
modelA的服务/页面去调用 modelB,因为部署在一起,直接走inJvm

2、部署方式2:
ModuleA 和 ModuleB 部署在不同的jvm中;
modelA的服务/页面去调用 modelB,则会走远程(RPC);此时需要:
a)ModuleB 需要开启dubbo服务,且ModuleA 和 ModuleB注册中心相同
b)ModuleB 对应的方法需要暴露dubbo接口,自定义service需要增加@Function注解

8、流程拒绝和回退调用自定义函数

1)、工作流撤销的自定义函数

@Function
public XXX recall(String data) {    
    return new XXX();
} 

2)、撤销回退调用的自定义函数
调用入口:
pro/shushi/pamirs/workflow/app/core/service/operator/ApprovalFallbackOperatorService.java:181

@Function
public XXX fallBack(String data) {
    return new XXX();
}

3)、工作流拒绝之后回调钩子

@Function
public XXX reject((String data) {    
    return new XXX();
} 

9、启动后访问页面报枚举项不存在

现象:枚举项不存在, model:base.ViewAction, name:target,value:ROUTER

pro.shushi.pamirs.meta.common.exception.PamirsException: 枚举项不存在, model:base.ViewAction, name:target,value:ROUTER
    at pro.shushi.pamirs.meta.common.exception.PamirsException$Builder.errThrow(PamirsException.java:173) ~[pamirs-meta-common-4.6.6.jar:na]
    at pro.shushi.pamirs.framework.orm.converter.entity.handler.EnumNamedHandler.lambda$dealEnum$4(EnumNamedHandler.java:149) ~[pamirs-framework-orm-4.6.8.jar:na]
    at pro.shushi.pamirs.framework.orm.converter.multi.MultiValueStrategy.submit(MultiValueStrategy.java:59) ~[pamirs-framework-orm-4.6.8.jar:na]
    at pro.shushi.pamirs.framework.orm.converter.multi.MultiValueStrategy.submit(MultiValueStrategy.java:23) ~[pamirs-framework-orm-4.6.8.jar:na]
    at pro.shushi.pamirs.framework.orm.converter.entity.handler.EnumNamedHandler.dealEnum(EnumNamedHandler.java:86) ~[pamirs-framework-orm-4.6.8.jar:na]
    at pro.shushi.pamirs.framework.orm.converter.entity.handler.EnumNamedHandler.stringify(EnumNamedHandler.java:66) ~[pamirs-framework-orm-4.6.8.jar:na]
    at pro.shushi.pamirs.framework.orm.converter.entity.handler.EnumHandler.stringify(EnumHandler.java:57) ~[pamirs-framework-orm-4.6.8.jar:na]
    at pro.shushi.pamirs.framework.orm.client.converter.entity.ClientEnumConverter.out(ClientEnumConverter.java:30) ~[pamirs-framework-orm-client-4.6.8.jar:na]
    at pro.shushi.pamirs.framework.orm.client.converter.processor.ClientTypeProcessor.lambda$out$6(ClientTypeProcessor.java:71) ~[pamirs-framework-orm-client-4.6.8.jar:na]
    at pro.shushi.pamirs.meta.common.enmu.BaseEnum.switchConsume(BaseEnum.java:717) ~[pamirs-meta-common-4.6.6.jar:na]
    at pro.shushi.pamirs.meta.common.enmu.BaseEnum.switch0(BaseEnum.java:697) ~[pamirs-meta-common-4.6.6.jar:na]
    at pro.shushi.pamirs.meta.common.enmu.BaseEnum.switches(BaseEnum.java:638) ~[pamirs-meta-common-4.6.6.jar:na]

问题原因:
Oinone重写了GraphQL的枚举转换类,报错是没有加载到这个自定义类

解决方法
在boot工程的pom的最前面引用如下的jar,重新发布即可

<dependency>
  <groupId>pro.shushi.pamirs</groupId>
  <artifactId>a</artifactId>
</dependency>

10、配置日志文件

现在启动输出到out.log应该是启动脚本中定向输出了(>>)

不定向输出,采用自己配置的方式,与标准的SpringBoot工程配置日志一样
两种方式(都是Spring提供的方式):
1、bootstrap.yml 里面可以按profiles指定logback的配置文件,例如:
logging:
config: classpath:logback-pre.xml
具体文件名和文件输入在logback里面进行配置,跟通用的logback配置一致

2、resources的根目录,直接配置 logback-spring.xml, 启动会自动加载

11、自定义controller如何获取用户信息

    private PamirsUser fetchUserByRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String sessionId = CookieUtil.getValue(request, pro.shushi.pamirs.framework.common.utils.CookieUtil.USER_SESSION_ID);
        PamirsUserDTO pamirsUserDTO = UserCache.get(sessionId);
        if (pamirsUserDTO!=null) {
            // 根据用户ID获取完整的用户信息
           return UserInfoCache.queryUserById(pamirsUserDTO.getUserId()); 
        } else {
            throw PamirsException.construct(BaseExpEnumerate.BASE_USER_NOT_LOGIN_ERROR).errThrow();
        }
    }

12、查询设置不排序

查询的page和Wrapper可设置setSortable(Boolean.FALSE),来实现查询不需要排序的场景

示例1:page中设置不排序

page.setSortable(Boolean.FALSE);
page = new PetShop().queryPage(page, queryWrapper);

示例2:Wrapper中设置不排序

IWrapper wrapper = Pops.lambdaQuery()
    .from(PetShop.MODEL_MODEL).setBatchSize(-1).setSortable(Boolean.FALSE);
List petShops4 = new PetShop().queryList(wrapper);

持续补充中。。。。。

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

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

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

相关推荐

  • 后端:如何自定义表达式实现特殊需求?扩展内置函数表达式

    平台提供了很多的表达式,如果这些表达式不满足场景?那我们应该如何新增表达式去满足项目的需求?目前平台支持的表达式内置函数,参考 1. 扩展表达式的场景 注解@Validation的rule字段支持配置表达式校验如果需要判断入参List类型字段中的某一个参数进行NULL校验,发现平台的内置函数不支持该场景的配置,这里就可以通过平台的机制,对内置函数进行扩展。 常见的一些代码场景,如下: package pro.shushi.pamirs.demo.core.action; ……引用类 @Model.model(PetShopProxy.MODEL_MODEL) @Component public class PetShopProxyAction extends DataStatusBehavior<PetShopProxy> { @Override protected PetShopProxy fetchData(PetShopProxy data) { return data.queryById(); } @Validation(ruleWithTips = { @Validation.Rule(value = "!IS_BLANK(data.code)", error = "编码为必填项"), @Validation.Rule(value = "LEN(data.name) < 128", error = "名称过长,不能超过128位"), }) @Action(displayName = "启用") @Action.Advanced(invisible="!(activeRecord.code !== undefined && !IS_BLANK(activeRecord.code))") public PetShopProxy dataStatusEnable(PetShopProxy data){ data = super.dataStatusEnable(data); data.updateById(); return data; } ……其他代码 } 2. 新建一个自定义表达式的函数 校验入参如果是个集合对象的情况下,单个对象的某个字段如果为空,返回false的函数。 例子:新建一个CustomCollectionFunctions类 package xxx.xxx.xxx; import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Component; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.meta.common.constants.NamespaceConstants; import pro.shushi.pamirs.meta.util.FieldUtils; import java.util.List; import static pro.shushi.pamirs.meta.enmu.FunctionCategoryEnum.COLLECTION; import static pro.shushi.pamirs.meta.enmu.FunctionLanguageEnum.JAVA; import static pro.shushi.pamirs.meta.enmu.FunctionOpenEnum.LOCAL; import static pro.shushi.pamirs.meta.enmu.FunctionSceneEnum.EXPRESSION; /** * 自定义内置函数 */ @Fun(NamespaceConstants.expression) @Component public class CustomCollectionFunctions { /** * LIST_FIELD_NULL 就是我们自定义的表达式,不能与已经存在的表达式重复!!! * * @param list * @param field * @return */ @Function.Advanced( displayName = "校验集成的参数是否为null", language = JAVA, builtin = true, category = COLLECTION ) @Function.fun("LIST_FIELD_NULL") @Function(name = "LIST_FIELD_NULL", scene = {EXPRESSION}, openLevel = LOCAL, summary = "函数示例: LIST_FIELD_NULL(list,field),函数说明: 传入一个对象集合,校验集合的字段是否为空" ) public Boolean listFieldNull(List list, String field) { if (null == list) { return false; } if (CollectionUtils.isEmpty(list)) { return false; } for (Object data : list) { Object value =…

    2024年5月30日
    1.9K00
  • 【前端】项目开发前端知识要点地图

    概述 下面整理了目前现有的所有文章,并提供了基本的学习路径。所有使用*标记的文章属于推荐必读文章。 目录 基础篇 【路由】浏览器地址栏url参数介绍 母版-布局-DSL 渲染基础(v4)* 组件SPI机制(v4)* 组件数据交互基础(v4)* 组件生命周期(v4) 入门篇 自定义视图组件(v4)* 如何通过浏览器开发者工具提高调试效率* 如何提高自定义组件的开发效率* 自定义组件之自动渲染(组件插槽的使用)(v4)* GraphQL请求详解(v4)* 上下文在字段和动作中的应用 如何实现页面间的跳转 如何自定义指定页面的样式 进阶篇 自定义组件之手动渲染基础(v4) 自定义组件之手动渲染弹出层(v4) 自定义组件之手动渲染任意视图(v4) 【前端】IOC容器(v4) 最佳实践篇 【前端】工程结构最佳实践(v4)* 【前端】移动端工程结构最佳实践(v4)* 界面设计器实战篇 基础篇 【界面设计器】模型增删改查基础 【界面设计器】他表字段 【界面设计器】左树右表 【界面设计器】树形表格 【界面设计器】树下拉/级联选择 【界面设计器】自定义字段组件基础 展示篇 【界面设计器】自定义字段组件实战——轮播图 【界面设计器】自定义字段组件实战——表格字段组合展示 【界面设计器】自定义字段组件实战——表格字段内嵌表格 交互篇 【界面设计器】自定义字段组件实战——千分位输入框 其他 前端低无一体使用教程 如何自定义表格字段? 【界面设计器】组件开发常见问题 【前端】低无一体部署常见问题 【前端】生产环境性能调优 API文档 OioProvider详解(v4.3.0)* 前端环境配置(v4)* 默认布局模板(v4) 表格主题配置(v4) 运行时上下文API文档(v4) Class Component(ts)(v4)

    2024年5月25日
    3.8K00
  • 系统图标使用自定义CDN地址(内网部署)

    在实际项目中,客户网络环境不能访问外网即纯内网部署。此时需要将所有的静态资源都放在客户内部的CDN上,该篇详细说明实现步骤。 实现步骤 1、把图片等静态资源上传到本地CDN上(如MINIO、Nginx等),图片等静态资源找 数式支持人员 提供; 【注意】:MINIO情况,放置图片等静态资源的桶权限需设置为公共读; 2、项目中YAML的OSS配置,使用本地CDN、并指定使用的本地CDN图标的标识appLogoUseCdn: true, OSS配置参考如下: 本地CDN使用MINIO(仅示例需根据实际情况修改) cdn: oss: name: MINIO type: MINIO # MINIO的配置根据实际情况修改 bucket: pamirs(您的bucket) # 上传和下载地址根据实际情况修改 uploadUrl: http://39.103.145.77:9000 downloadUrl: http://39.103.145.77:9000 accessKeyId: 您的accessKeyId accessKeySecret: 您的accessKeySecret # mainDir对用CDN的图片目录,根据项目情况自行修改 mainDir: upload/demo/ validTime: 3600000 timeout: 600000 active: true referer: # 使用客户自己的CDN的图片,否则系统默认的从数式的CDN中获取 appLogoUseCdn: true 或本地CDN使用Nginx(仅示例需根据实际情况修改) cdn: oss: name: 本地文件NG系统 type: LOCAL bucket: # uploadUrl 这个是Oinone后端服务地址和端口 uploadUrl: http://192.168.0.129:8099 # downloadUrl前端地址,即直接映射在nginx的静态资源的路径和端口 downloadUrl: http://192.168.0.129:9999 validTime: 3600000 timeout: 600000 active: true referer: # 本地Nginx静态资源目录 localFolderUrl: /opt/pamirs/static # 使用客户自己的CDN的图片,否则系统默认的从数式的CDN中获取 appLogoUseCdn: true 3、前端工程3.1 前端源码工程,在.evn中把 STATIC_IMG地址进行修改;http(https)、IP和端口改成与CDN对应的配置,URL中/oinone/static/images是固定的;例如: 本地CDN使用MINIO(仅示例需根据实际情况修改) STATIC_IMG: 'http://39.103.145.77:9000/pamirs(这里替换为OSS中的bucket)/oinone/static/images' 或本地CDN使用Nginx(仅示例需根据实际情况修改) STATIC_IMG: 'http://192.168.0.129:9999/static/oinone/static/images' 3.2 对于已经打包好的前端资源对于已打包好的前端资源即无法修改.evn的情况;需在前端资源的根目录,新建config/manifest.js. 如果已存在则不需要新建,同时原来的内容也不需要删除(追加即可),需增加的配置: 本地CDN使用MINIO(仅示例需根据实际情况修改) runtimeConfigResolve({ STATIC_IMG: 'http://39.103.145.77:9000/pamirs(这里替换为OSS中的bucket)/oinone/static/images', plugins: { usingRemote: true } }) 或本地CDN使用Nginx(仅示例需根据实际情况修改) runtimeConfigResolve({ STATIC_IMG: 'http://192.168.0.129:9999/static/oinone/static/images', plugins: { usingRemote: true } })

    2025年2月8日
    86900
  • 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.6K00
  • 对字段进行加密存储

    需求: 模型字段上使用 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日
    98500

Leave a Reply

登录后才能评论