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

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

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

相关推荐

  • 如何跳过固定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.4K00
  • 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日
    3.2K00
  • 【前端】项目开发前端知识要点地图

    概述 下面整理了目前现有的所有文章,并提供了基本的学习路径。所有使用*标记的文章属于推荐必读文章。 目录 基础篇 【路由】浏览器地址栏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日
    5.9K00
  • 同一行操作跳转到不同的视图(动态表单)

    背景 实际项目中,存在这样的场景:同一列表中的数据是泛化的数据集合,即数据来源于不同的模型;行操作需要根据来源去向不同的目标页。 如下图,「提报」操作需根据「报表类型」去向不同的表单。 并支持目标弹窗标题和弹框大小的配置。 解决思路 每行记录需要跳转到不同的模型不同视图,增加一个配置页面用于维护源模型和目标模型的调整动作关系; 返回数据的时候,同时返回自定义的动作。 前端自定义实现如上面图例中的「填报」,从返回数据中获取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日
    1.6K00
  • Oinone登录扩展:对接SSO(适应于4.7.8及之后的版本)

    适配版本 4.7.8及其之后的版本 概述 在企业内部,对于已有一套完整的登录系统(SSO)的情况下,通常会要求把所有的系统都对接到SSO中;本文主要讲解用Oinone开发的项目对接SSO的具体实现。 对接步骤 1、项目自定义实现UserCookieLogin,可参考示例说明: pro.shushi.pamirs.user.api.login.UserCookieLoginFree 2、对接SSO示例 对接流程说明: 1)【必须】从请求头Header或者Query中获取到token; 2)【必须】去SSO服务端验证token的有效性; 3)【可选】根据token去服务端获取用户信息;如果token可以直接反解析出用户信息,则该步骤忽略; 4)【可选】根据实际情况用户信息是否进行DB的存储; 5)【必须】验证token有效后,生成Session和Cookie(即token换cookie); 注意超时时间需要 <= SSO服务端token失效时间。 package pro.shushi.pamirs.demo.core.sso; import com.alibaba.fastjson.JSON; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import pro.shushi.pamirs.demo.core.sso.constant.HttpConstant; import pro.shushi.pamirs.demo.core.sso.constant.SessionUserTypeEnum; import pro.shushi.pamirs.demo.core.sso.model.ApiCommonTransient; import pro.shushi.pamirs.demo.core.sso.model.PermissionInfoResp; import pro.shushi.pamirs.demo.core.sso.utils.AuthenticateUtils; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.model.PamirsUserDTO; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.common.exception.PamirsException; import pro.shushi.pamirs.meta.common.spring.BeanDefinitionUtils; import pro.shushi.pamirs.resource.api.enmu.UserSignUpType; import pro.shushi.pamirs.user.api.cache.UserCache; import pro.shushi.pamirs.user.api.constants.UserConstant; import pro.shushi.pamirs.user.api.enmu.UserExpEnumerate; import pro.shushi.pamirs.user.api.enmu.UserLoginTypeEnum; import pro.shushi.pamirs.user.api.login.IUserLoginChecker; import pro.shushi.pamirs.user.api.login.UserCookieLogin; import pro.shushi.pamirs.user.api.login.UserCookieLoginSimple; import pro.shushi.pamirs.user.api.model.PamirsUser; import pro.shushi.pamirs.user.api.model.tmodel.PamirsUserTransient; import pro.shushi.pamirs.user.api.service.UserService; import pro.shushi.pamirs.user.api.utils.CookieUtil; import javax.servlet.http.HttpServletResponse; /** * * @author shushi * * 完全自定义login的过程 * 需要实现登陆部分login 以及拦截部分fetchUserIdByReq * 如果fetchUserIdByReq返回值为null的时候 将会被拦截 */ @Slf4j @Order(0) @Component public class DemoUserSSOCookieLogin extends UserCookieLogin<PamirsUser> { //刷新令牌 private static String REFRESH_TOKEN = "refreshToken"; //系统id private static String CLIENT_ID = "client-id"; //访问令牌 private static String AUTHORIZATION = "Authorization"; private IUserLoginChecker checker; @Autowired private UserService userService; @Autowired private RedisTemplate<String, String> redisTemplate; @Override public String type() { return UserLoginTypeEnum.COOKIE.value(); } @Override public PamirsUser resolveAndVerification(PamirsUserTransient user) { if (checker == null) { checker = BeanDefinitionUtils.getBean(IUserLoginChecker.class); } return checker.check4login(user); } /** * 重写登录拦截功能 * 该函数主要作用,通过三方权限校验. * @return */ // 版本升级需要修改 @Override public PamirsUserDTO fetchUserIdByReq() { String sessionId =…

    2024年4月2日
    2.5K00

Leave a Reply

Please Login to Comment