6.6 消息

在我们系统研发过程中经常需要发送短信、邮件、站内信等,笔者在本文给大家介绍下如何使用Oinone的消息模块。

准备工作

如果通过我们工程脚手架工具生成的则已经引入了无需做更多的配置,如果不是则需要按以下步骤先配置依赖和增加启动模块

pamirs-demo-boot的pom文件中引入pamirs-message-core包依赖

<dependency>
  <groupId>pro.shushi.pamirs.core</groupId>
  <artifactId>pamirs-message-core</artifactId>
</dependency>

pamirs-demo-boot的application-dev.yml文件中增加配置pamirs.boot.modules增加message,即在启动应用中增加message模块

pamirs:
    boot:
    modules:
      - message

消息参数设置

发送邮件和短信需要设置对应的发送邮箱服务器和短信云,短信目前默认阿里云短信。我们通过代码示例来完成对应邮箱和短信的参数设置

Step1 增加pamirs-message-api依赖

pamirs-demo-core的pom文件中引入pamirs-message-api包依赖

<dependency>
  <groupId>pro.shushi.pamirs.core</groupId>
  <artifactId>pamirs-message-api</artifactId>
</dependency>

Step2 消息参数设置

请自行替换邮箱服务器和短信通道的账号信息

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.api.init.InstallDataInit;
import pro.shushi.pamirs.boot.common.api.init.UpgradeDataInit;
import pro.shushi.pamirs.demo.api.DemoModule;
import pro.shushi.pamirs.message.enmu.EmailSendSecurityEnum;
import pro.shushi.pamirs.message.enmu.MessageEngineTypeEnum;
import pro.shushi.pamirs.message.enmu.SMSChannelEnum;
import pro.shushi.pamirs.message.model.EmailSenderSource;
import pro.shushi.pamirs.message.model.SmsChannelConfig;

import java.util.Collections;
import java.util.List;

@Component
public class DemoMessageInit implements InstallDataInit, UpgradeDataInit {

    private void initEmail(){
        EmailSenderSource emailSenderSource = new EmailSenderSource();
        emailSenderSource.setName("邮件发送服务");
        emailSenderSource.setType(MessageEngineTypeEnum.EMAIL_SEND);
        //优先级
        emailSenderSource.setSequence(10);
        //发送账号 FIXME 自行替换
        emailSenderSource.setSmtpUser("");
        //发送密码 FIXME 自行替换
        emailSenderSource.setSmtpPassword("");
        //发送服务器地址和端口
        emailSenderSource.setSmtpHost("smtp.exmail.qq.com");
        emailSenderSource.setSmtpPort(465);
        //" None: SMTP 对话用明文完成。" +
        //" TLS (STARTTLS): SMTP对话的开始时要求TLS 加密 (建议)" +
        //" SSL/TLS: SMTP对话通过专用端口用 SSL/TLS 加密 (默认是: 465)")
        emailSenderSource.setSmtpSecurity(EmailSendSecurityEnum.SSL);
        emailSenderSource.createOrUpdate();
    }

    private void initSms(){
        SmsChannelConfig smsChannelConfig = new SmsChannelConfig();
        smsChannelConfig.setType(MessageEngineTypeEnum.SMS_SEND);
        smsChannelConfig.setChannel(SMSChannelEnum.ALIYUN);
        //短信签名名称
        smsChannelConfig.setSignName("oinone");
        //阿里云账号信息  FIXME 自行替换
        smsChannelConfig.setAccessKeyId("");
        smsChannelConfig.setAccessKeySecret("");
        smsChannelConfig.setEndpoint("https://dysmsapi.aliyuncs.com");
        smsChannelConfig.setRegionId("cn-hangzhou");
        smsChannelConfig.setTimeZone("GMT");
        smsChannelConfig.setSignatureMethod("HMAC-SHA1");
        smsChannelConfig.setSignatureVersion("1.0");
        smsChannelConfig.setVersion("2017-05-25");
        smsChannelConfig.createOrUpdate();

        //初始化短信模版
        //目前支持阿里云短信通道:获取短信模板,如没有短信模板,需要先创建模板,并审核通过
        SmsTemplate smsTemplate = new SmsTemplate();
        smsTemplate.setName("通知短信");
        smsTemplate.setTemplateType(SMSTemplateTypeEnum.NOTIFY);
        smsTemplate.setTemplateCode("SMS_244595482");//从阿里云获取,自行提供 FIXME
        smsTemplate.setTemplateContent("尊敬的&{name},你的&{itemName}库存为&{quantity}");
        smsTemplate.setChannel(SMSChannelEnum.ALIYUN);
        smsTemplate.setStatus(SMSTemplateStatusEnum.SUCCESS);
        smsTemplate.createOrUpdate();
    }

    @Override
    public boolean init(AppLifecycleCommand command, String version) {
        initEmail();
        initSms();
        return Boolean.TRUE;
    }

    @Override
    public boolean upgrade(AppLifecycleCommand command, String version, String existVersion) {
        initEmail();
        initSms();
        return Boolean.TRUE;
    }

    @Override
    public List<String> modules() {
        return Collections.singletonList(DemoModule.MODULE_MODULE);
    }

    @Override
    public int priority() {
        return 0;
    }
}

消息发送举例

该例子以各种站内信、邮件、短信方式发送宠物商品库存记录信息为例,构建宠物商品库存信息发送服务并在宠物商品库存模型的表格页面创建发送入口

Step1 创建宠物商品库存信息发送服务接口

在Api工程新建PetItemInventoryMessageService接口,并定义发送站内信、邮件、短信的三个Function

package pro.shushi.pamirs.demo.api.service;

import pro.shushi.pamirs.demo.api.model.PetItemInventroy;
import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;

@Fun(PetItemInventoryMessageService.FUN_NAMESPACE)
public interface PetItemInventoryMessageService {

    String FUN_NAMESPACE = "demo.PetItemInventoryMessageService";
    @Function
    void sendMail(PetItemInventroy data);
    @Function
    void sendEmail(PetItemInventroy data);
    @Function
    void sendSms(PetItemInventroy data);

}

Step2 发送站内信

在Core工程新建PetItemInventoryMessageService接口的实现类

package pro.shushi.pamirs.demo.core.service;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.demo.api.enumeration.DemoExpEnumerate;
import pro.shushi.pamirs.demo.api.model.PetItemInventroy;
import pro.shushi.pamirs.demo.api.service.PetItemInventoryMessageService;
import pro.shushi.pamirs.demo.core.session.DemoSession;
import pro.shushi.pamirs.message.engine.MessageEngine;
import pro.shushi.pamirs.message.engine.email.EmailSender;
import pro.shushi.pamirs.message.engine.message.MessageSender;
import pro.shushi.pamirs.message.engine.sms.SMSSender;
import pro.shushi.pamirs.message.enmu.MessageEngineTypeEnum;
import pro.shushi.pamirs.message.enmu.MessageGroupTypeEnum;
import pro.shushi.pamirs.message.enmu.MessageTypeEnum;
import pro.shushi.pamirs.message.enmu.SMSTemplateTypeEnum;
import pro.shushi.pamirs.message.model.PamirsMessage;
import pro.shushi.pamirs.message.model.SmsTemplate;
import pro.shushi.pamirs.message.tmodel.EmailPoster;
import pro.shushi.pamirs.message.tmodel.SystemMessage;
import pro.shushi.pamirs.meta.annotation.Fun;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;
import pro.shushi.pamirs.meta.common.exception.PamirsException;
import pro.shushi.pamirs.meta.util.JsonUtils;
import pro.shushi.pamirs.user.api.model.PamirsUser;

import javax.mail.MessagingException;
import javax.mail.SendFailedException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Fun(PetItemInventoryMessageService.FUN_NAMESPACE)
@Slf4j
@Component
public class PetItemInventoryMessageServiceImpl implements PetItemInventoryMessageService {

    public static final String INVALID_ADDRESSES_CODE = "Invalid Addresses";
    public static final String INVALID_ADDRESSES_MSG = "非法的邮箱地址";
    public static final String CAN_NO_CONNECT_TO_SMTP_CODE = "Could not connect to SMTP";
    public static final String CAN_NO_CONNECT_TO_SMTP_MSG = "连接邮件服务失败";

    @Override
    @Function
    public void sendMail(PetItemInventroy data) {
        //接收对象列表
        PamirsUser user = DemoSession.getUser();

        List<Long> userIds = new ArrayList<>();
        userIds.add(user.getId());

        String subject = "商品库存信息";
        String body = data.getItemName() + "_" + data.getQuantity();
        MessageSender mailSender = (MessageSender) MessageEngine.get(MessageEngineTypeEnum.MAIL_SEND).get(null);
        PamirsMessage message = new PamirsMessage()
                .setName(subject)
                .setSubject(subject)
                .setBody(body)
                .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);
        try {
            mailSender.sendSystemMail(systemMessage);
        } catch (Exception e) {
            // TODO: 可增加失败业务处理
            throw PamirsException.construct(DemoExpEnumerate.SYSTEM_ERROR, e).appendMsg("站内信发送失败").errThrow();
        }
    }

    @Override
    @Function
    public void sendEmail(PetItemInventroy data) {
        //发送一个邮件
        List<String> receiveEmails = new ArrayList<>();
        receiveEmails.add("testhaha@shushi.pro");//收件人邮箱,自行替换 FIXME 
        EmailSender emailSender = null;
        EmailPoster emailPoster = null;

        emailSender = (EmailSender) MessageEngine.get(MessageEngineTypeEnum.EMAIL_SEND).get(null);

        String title = data.getItemName();//"邮件标题";
        String body = data.getItemName() + "_" + data.getQuantity();//"邮件内容";
        String sender = DemoSession.getUserName();//"发件人";
        String replyEmail = "回复邮箱";

        emailPoster = new EmailPoster().setSender(sender).setTitle(title).setBody(body).setReplyTo(replyEmail);

        EmailPoster finalEmailPoster = emailPoster;
        EmailSender finalEmailSender = emailSender;

        StringBuilder errorMessages = new StringBuilder();
        receiveEmails.stream().distinct().collect(Collectors.toList()).forEach(
                email -> {
                    try {
                        if (!finalEmailSender.send(finalEmailPoster.setSendTo(email))) {
                            log.error("发送邮件失败:emailPoster:{}", JsonUtils.toJSONString(finalEmailPoster));
                            String message = "发送邮件失败,错误信息:" + "系统异常" + ",邮箱:" + email + ";";
                            errorMessages.append(message);
                        }
                    } catch (Exception e) {
                        log.error("发送邮件失败:emailPoster:{},异常:{}", JsonUtils.toJSONString(finalEmailPoster), e);
                        String errorMsg = transferEmailThrowMessage(e);
                        String message = "发送邮件失败,错误信息:" + errorMsg + ",邮箱:" + email + ";";
                        errorMessages.append(message);
                    }
                }
        );

        if (StringUtils.isNotBlank(errorMessages.toString())) {
            // TODO: 可增加处理邮件发送失败的业务逻辑
        }
    }

    private String transferEmailThrowMessage(Exception e) {
        String errorMessage = e.getMessage();
        Throwable cause = e.getCause();
        if (cause != null) {
            if (cause instanceof SendFailedException) {
                String message = cause.getMessage();
                if (INVALID_ADDRESSES_CODE.equals(message)) {
                    errorMessage = INVALID_ADDRESSES_MSG;
                }
            } else if (cause instanceof MessagingException) {
                String message = cause.getMessage();
                if (StringUtils.isNotBlank(message) && message.contains(CAN_NO_CONNECT_TO_SMTP_CODE)) {
                    errorMessage = CAN_NO_CONNECT_TO_SMTP_MSG;
                }
            }
        }
        return errorMessage;
    }

    @Override
    @Function
    public void sendSms(PetItemInventroy data) {
        StringBuilder errorMessages = new StringBuilder();

        List<String> receivePhoneNumbers = new ArrayList<>();
        receivePhoneNumbers.add("13777899044");//接收手机号,自行提供 FIXME 

        //目前支持阿里云短信通道:获取短信模板,如没有短信模板,需要先创建模板,并审核通过
        //如以下示例
        SmsTemplate smsTemplate = new SmsTemplate().setTemplateType(SMSTemplateTypeEnum.NOTIFY).setTemplateCode("SMS_246455054").queryOne();//从阿里云获取

        // 占位符处理
        Map<String, String> vars = new HashMap<>();
        vars.put("name", DemoSession.getUserName());
        vars.put("itemName", data.getItemName());
        vars.put("quantity", data.getQuantity().toString());

        SMSSender smsSender = (SMSSender) MessageEngine.get(MessageEngineTypeEnum.SMS_SEND).get(null);
        receivePhoneNumbers.stream().distinct().forEach(it -> {
            try {
                if (!smsSender.smsSend(smsTemplate, it, vars)) {
                    String message = "发送短信失败,错误信息:" + "系统异常" + ",手机号:" + it + ";";
                    errorMessages.append(message);
                }
            } catch (Exception e) {
                String message = "发送短信失败,错误信息:" + e.getMessage() + ",手机号:" + it + ";";
                errorMessages.append(message);
            }
        });
        if (StringUtils.isNotBlank(errorMessages.toString())) {
            // TODO: 可增加失败业务处理
        }
    }
}

Step3 为宠物商品库存模型的表格页面新增发送入口

把以下代码复制到PetItemInventroyAction类中

@Autowired
private PetItemInventoryMessageService petItemInventoryMessageService;
@Action(displayName = "发送站内信",bindingType = ViewTypeEnum.TABLE,contextType = ActionContextTypeEnum.SINGLE)
public PetItemInventroy sendMail(PetItemInventroy data) {
    petItemInventoryMessageService.sendMail(data);
    return data;
}

/**
 * 发送邮件
 */
@Action(displayName = "发送邮件",bindingType = ViewTypeEnum.TABLE,contextType = ActionContextTypeEnum.SINGLE)
public PetItemInventroy sendEmail(PetItemInventroy data){
    petItemInventoryMessageService.sendEmail(data);
    return data;
}

/**
 * 发送短息
 */
@Action(displayName = "发送短信",bindingType = ViewTypeEnum.TABLE,contextType = ActionContextTypeEnum.SINGLE)
public PetItemInventroy sendSms(PetItemInventroy data){
    petItemInventoryMessageService.sendSms(data);
    return data;
}

Step4 重启看效果

请分别点击发送邮件、发送短信、发送站内信测试效果,自行测试效果

image.png

Oinone社区 作者:史, 昂原创文章,如若转载,请注明出处:https://doc.oinone.top/oio4/9330.html

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

(0)
史, 昂的头像史, 昂数式管理员
上一篇 2024年5月23日
下一篇 2024年5月23日

相关推荐

  • 第5章 Oinone的CDM

    2024年5月23日
    1.3K00
  • 数据编码

    1. 什么是数据编码 当模型中的字段数据需要有一定的编码规定,可以在模型中设计模型或字段的数据编码。 编码预览:实时展示规则设置后的编码。 2. 编码前/后缀 编码前缀:必须以字母开头,且仅支持数字或字母,最多8个字符。 编码后缀:必须以字母开头,且仅支持数字或字母,最多8个字符。 3. 格式化日期 开关默认关闭,即数据编码中不包含日期。开关打开后,默认的日期格式为“年年年年月月日日”,也可以切换成“年年月月日日、年年月月、年年年年、年年”。 序列归零周期:与格式化日期选择有关,若选择为“年年年年月月日日”,则可选“年、月、日”,选择为“年年年年”,则只可选“年”数据编码序列会按照设置的这个周期归零。 4. 编码序列 编码方式:可选择连续序列或非连续序列,选择会影响后续包含哪些设置。 序列长度:序列包含多少位数字,可以设置1 – 18之间的整数。 序列起始值:数据编码序列的起始值,默认值为3。 当编码方式设置为非连续序列时,展示其余两个配置项。 步长类型:默认值为“自定义步长”,也可以设置成“1 – 10之间随机步长”。 步长:当选择“自定义步长”时,设置的步长即为真实步长。当选择“1 – 10之间随机步长”时,实际步长为1 – 设置值之间的随机整数。

    2024年6月20日
    1.4K00
  • 4.2.2 框架之MessageHub

    一、MessageHub 请求出现异常时,提供”点对点“的通讯能力 二、何时使用 错误提示是用户体验中特别重要的组成部分,大部分的错误体现在整页级别,字段级别,按钮级别。友好的错误提示应该是怎么样的呢?我们假设他是这样的 与用户操作精密契合 当字段输入异常时,错误展示在错误框底部 按钮触发服务时异常,错误展示在按钮底部 区分不同的类型 错误 成功 警告 提示 调试 简洁易懂的错误信息 在oinone平台中,我们怎么做到友好的错误提示呢?接下来介绍我们的MessageHub,它为自定义错误提示提供无限的可能。 三、如何使用 订阅 import { useMessageHub, ILevel } from "@kunlun/dependencies" const messageHub = useMessageHub('当前视图的唯一标识'); /* 订阅错误信息 */ messageHub.subscribe((errorResult) => { console.log(errorResult) }) /* 订阅成功信息 */ messageHub.subscribe((errorResult) => { console.log(errorResult) }, ILevel.SUCCESS) 图4-2-2-1 订阅的示例代码 销毁 /** * 在适当的时机销毁它 * 如果页面逻辑运行时都不需要销毁,在页面destroyed是一定要销毁,重要!!! */ messageHub.unsubscribe() 图4-2-2-2 销毁的示例代码 四、实战 让我们把3.5.7.5【自定义视图-表单】一文中的自定义表单进行改造,加入我们的messageHub,模拟在表单提交时,后端报错信息在字段下方给予提示。 Step1 (后端)重写PetType的创建函数 重写PetType的创建函数,在创建逻辑中通过MessageHub返回错误信息,返回错误信息的同时要设置paths信息方便前端处理 @Action.Advanced(name = FunctionConstants.create, managed = true) @Action(displayName = "确定", summary = "创建", bindingType = ViewTypeEnum.FORM) @Function(name = FunctionConstants.create) @Function.fun(FunctionConstants.create) public PetType create(PetType data){ List<Object> paths = new ArrayList<>(); paths.add("demo.PetType"); paths.add("kind"); PamirsSession.getMessageHub().msg(new Message().msg("kind error").setPath(paths).setLevel(InformationLevelEnum.ERROR).setErrorType(ErrorTypeEnum.BIZ_ERROR)); List<Object> paths2 = new ArrayList<>(); paths2.add("demo.PetType"); paths2.add("name"); PamirsSession.getMessageHub().msg(new Message().msg("name error").setPath(paths2).setLevel(InformationLevelEnum.ERROR).setErrorType(ErrorTypeEnum.BIZ_ERROR)); // data.create(); return data; } 图4-2-2-3 (后端)重写PetType的创建函数 Step 2 修改PetForm.vue <template> <div class="petFormWrapper"> <form :model="formState" @finish="onFinish"> <a-form-item label="品种种类" id="name" name="kind" :rules="[{ required: true, message: '请输入品种种类!', trigger: 'focus' }]"> <a-input v-model:value="formState.kind" @input="(e) => onNameChange(e, 'kind')" /> <span style="color: red">{{ getServiceError('kind') }}</span> </a-form-item> <a-form-item label="品种名" id="name" name="name" :rules="[{ required: true, message: '请输入品种名!', trigger: 'focus' }]"> <a-input v-model:value="formState.name" @input="(e) => onNameChange(e, 'name')" /> <span style="color: red">{{ getServiceError('name') }}</span> </a-form-item> </form> </div> </template>- <script lang="ts"> import { defineComponent, reactive…

    2024年5月23日
    1.3K00
  • 2.4.2 Oinone独特性之每一个需求都可以是一个模块

    我们的Oinone平台采用模型驱动的方式,并符合面向对象设计原则,每个需求都可以是一个独立模块,可以独立安装、升级和卸载。这让系统真正像乐高积木一样搭建,具有高度的灵活性和可维护性。 与大部分低代码或无代码平台不同的是,它们的应用市场上的应用往往是模板式的,也就是说,这是一个拷贝,个性化只能在应用上直接修改,而且一旦修改就不能升级。这对于软件公司和客户来说都非常痛苦。客户无法享受到软件公司产品的升级功能,而软件公司在服务大量客户时,也会面临不同版本的维护问题,成本也非常高。而我们的Oinone平台完全避免了这些问题,让客户和软件公司都可以从中受益(如下图2-9、2-10所示)。 图2-9软件公司与客户项目的关系-让标准与个性化共存 图2-10 软件公司与客户项目的关系-让升级无忧 实现原理 在满足客户个性化定制需求时,传统的方法通常是直接修改标准产品源码,但这样做会带来一个问题:标准产品无法持续升级。相反,无论是在OP模式还是SaaS模式下,Oinone都采用全新的模块为客户进行个性化开发,保持标准产品和个性化模块的独立维护和升级。这是因为在元数据设计时,Oinone采用了面向对象的设计原则,实现了元数据设计与面向对象设计思想的完美融合。 面向对象设计的核心特征包括封装、继承、多态,而Oinone的元数据设计完全融入了这些思想。下面是几个例子,说明Oinone的元数据设计如何体现面向对象设计的核心特征,并带来了什么好处: 继承:在继承原有模型的字段、逻辑、展示的情况下,增加一段代码来扩展模型的字段、逻辑、展示。 多态:在继承原有模型的字段、逻辑、展示的情况下,增加一段代码来覆盖模型的原有字段、逻辑、展示。 封装:外部无需关心模型内部如何实现,只需按照不同场景调用模型对应开放级别的字段、逻辑、展示。 这些特征和优势使得Oinone在满足客户个性化需求时更加灵活和可持续,同时使得标准产品的维护和升级变得更加容易和高效。 在Java语言设计中,万物皆对象,一切都以对象为基础。而Oinone的元数据设计则是以模型为出发点,作为数据和行为的承载体。如下图2-11清晰地描述了Java面向对象编程中封装、继承、多态在Oinone元数据中的对应关系。Oinone元数据描述了B对象继承A对象并拥有其所有属性和方法,并覆盖了A对象的属性1和方法1,同时新增了属性3和方法3。 此外,Oinone的面向对象特性是用元数据来描述的。一方面,我们基于Java编码规范收集相关元数据,以保持不改变Java编程习惯。另一方面,方法和对象的挂载是松耦合的,只要按照元数据规范进行挂载,就能轻松地将其附加到模型上。在不改变原有A对象的情况下,我们可以直接增加方法和属性(如下图2-12所示)。 图2-11 java面向对象在Oinone元数据中对应 图2-12 java对象的修改 VS Oinone元数据模型的修改 Oinone函数不仅支持面向对象的继承和多态特性,还提供了面向切面的拦截器和SPI机制的扩展点,以应对方法逻辑的覆盖和扩展,以及系统层面的逻辑扩展(如下图2-13所示)。这些扩展功能可以独立地在模块中维护。 其中,拦截器可以在不侵入函数逻辑的情况下,根据优先级为满足条件的函数添加执行前和执行后的逻辑。 扩展点是一种类似于SPI机制的逻辑扩展机制,用于扩展函数的逻辑。通过这一机制,可以对函数逻辑进行灵活的扩展,以满足不同的业务需求。 图2-13 Oinone函数拦截与扩展机制 不管是对象、属性还是方法,都可以以独立的模块方式来扩展,这就使得每一个需求都可以成为一个独立的模块,方便我们在研发标准产品时进行模块化的划分,同时也让我们在以低代码模式为客户进行二次开发时,能够更好地支持“标准产品迭代与个性化保持独立”的需求。在2.4.3【oinone独特性之低无一体】一文中,我们也提到了这个特性,但那是在低无一体的情况下,通过元数据融合来实现的。让我们看看基于低代码开发模式下,典型的Oinone二次开发工程结构(如下图2-14所示),就可以更好地理解这个特性啦! 图2-14 Oinone典型的二开工程结构

    2024年5月23日
    1.3K00
  • 7.4 Oinone的低无一体

    基础介绍 前面我们学习了基于低代码开发平台进行快速开发,以及通过oinone的设计器进行零代码开发两种模式。当然低无一体不是简单地说两种模式还指:低无两种模式可以融合。 在做核心产品的时候以低代码开发为主,以无代码为辅助。见低代码开发的基础入门篇中设计器的结合一文 在做实施或临时性需求则是以无代码为主,以低代码为辅助 本文主要介绍第二种模式,它是www.oinone.top官网在SaaS模式下的专有特性。满足客户安装标品后通过设计器进行适应性修改后,但对于一些特殊场景还是需要通过代码进行完善或开发 在该模式下,我们提供了jar模式和代码托管两种模式,客户只要选择需要进行代码开发的模块,点击生产SDK,下载扩展工程模版,按Oinone低代码开发平台规范进行研发,后上传扩展工程即可。 操作手册 低无一体这个模块是连接无代码设计器的桥梁,可以为一个模块或应用设计低代码的逻辑,可以在界面设计器或流程设计器中使用低代码的逻辑。 1.选择模块 首先需要在下拉单选中选择需要低代码的模块或应用。 下拉选中只展示在「应用中心」中已安装的模块或应用,可前往「应用中心」安装后继续低代码操作。 选择模块中不展示系统的基础模块或应用,因为这些模块或应用无法自定义模型。 2.模块信息 模块信息展示的是选择模块的基础信息:模块名称、模块编码、模块作者、模块版本、包的前缀、工程模板下载地址,下载地址仅在上传jar包模式时候用到。 3.低无一体操作 低无一体支持了两种使用模式:上传jar包模式、源码托管模式。 上传控制工程或创建研发分支动作完成会生成一条数据,可以对单条数据进行部署、卸载、修改、删除。 3.1 上传jar包模式 在这个模式下,需要做四步动作。 生成SDK,点击按钮之后,会把模块的当前模型状态打成一个SDK包,SDK最新生成时间更新。当模型变更但未生成SDK时,使用低无一体就会出错,请重新生成SDK并修改扩展工程。生成SDK通常需要1分钟左右,若第一次使用低无一体模块,可能需要更长时间,请耐心等待。 下载扩展工程模板,点击按钮之后,会将SDK包和工程模板生成一个下载链接,复制模块信息中的卸载地址打开即可下载。 技术人员在工程模板的基础上写低代码逻辑。 上传扩展工程,点击按钮展开弹窗,在弹窗中设置标签、备注,并将最终的jar包上传,完成上传之后表格中就会新增一条数据。 上传jar包模式下,模板工程中代码需要注意的点参考下图: 3.2 源码托管模式 在这个模式下,需要做三步动作。 生成SDK,点击按钮之后,会把模块的当前模型状态打成一个SDK包,SDK最新生成时间更新。当模型变更但未生成SDK时,使用低无一体就会出错,请重新生成SDK并修改扩展工程。生成SDK通常需要1分钟左右,若第一次使用低无一体模块,可能需要更长时间,请耐心等待。 创建研发分支,点击按钮展开弹窗。首次创建时需要设置git账号名称、git账号邮箱来创建一个账号,另外在弹窗中设置分支名称、标签、备注,完成创建后表格中就会新增一条数据。 通过表格中的Gitlab地址,技术人员写低代码逻辑。 3.3 行内操作 部署:工程状态为未部署、部署失败、已卸载时展示行内的部署按钮,点击之后进行部署,工程状态变为部署中。部署过程大致需要5-10分钟,请耐心等待。部署完成之后,会生成一个新的模块:“原模块名称”扩展工程。 卸载:工程状态为已部署时展示行内的卸载按钮,点击之后会卸载这个已部署的工程,工程状态变为已卸载。同一模块只能有一个已部署的工程(与选择的模式无关),若需要使用新的工程请先卸载已部署的工程。 修改:行内操作修改按钮始终展示,只允许修改标签、备注。 删除:工程状态为未部署、部署失败、已卸载时展示行内的删除按钮,点击之后删除这一条工程记录。 3.4 部署效果 低无一体部署成功之后,可以进入对应模块的模型页面中使用提交动作来使用低代码逻辑,也可以在流程设计器中的引用逻辑节点中使用低代码逻辑。

    2024年5月23日
    2.2K00

Leave a Reply

登录后才能评论