低代码开发平台部署与实施实验手册_第1页
低代码开发平台部署与实施实验手册_第2页
低代码开发平台部署与实施实验手册_第3页
低代码开发平台部署与实施实验手册_第4页
低代码开发平台部署与实施实验手册_第5页
已阅读5页,还剩79页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

低代码开发平台部署与实施实验手册1实验概述1.1低代码平台概述低代码开发平台(LCDP)是一种革命性的应用开发方法,它通过可视化建模和配置驱动的方式,大幅降低了传统编程的技术门槛。在2025年的数字化转型浪潮中,低代码平台已成为企业实现业务敏捷性和数字化创新的核心工具。据统计,采用低代码开发的企业平均应用开发速度提升3-5倍,开发成本降低50-70%,业务人员参与度提高80%以上。本实验采用的Mendix和OutSystems双平台方案,分别代表了低代码领域的两大技术路线:Mendix注重业务友好性和生态开放性,而OutSystems强调企业级性能和架构严谨性。通过对比学习,学员将全面掌握不同场景下的平台选型标准。1.2实验目标本实验旨在培养学员的低代码平台全栈部署和企业级应用构建能力,具体目标包括:-平台部署:掌握Mendix和OutSystems在容器化环境中的部署、配置和高可用架构搭建-开发技能:熟练运用可视化建模、流程设计、数据建模等核心低代码开发技术-集成能力:实现低代码平台与企业现有系统(ERP、CRM、数据库)的无缝集成-运维管理:建立完整的DevOps流水线、监控体系和安全管理机制-架构设计:具备设计企业级低代码治理框架和标准化开发规范的能力通过本实验,学员将具备在企业环境中主导低代码平台实施和推广的实战能力,成为企业数字化转型的关键技术人才。1.3预备知识要求为确保实验效果,学员应具备以下知识基础:-基础开发知识:了解基本的编程概念、数据库原理和Web技术-系统管理经验:具备Linux操作系统和Docker容器的基础操作能力-网络知识:熟悉TCP/IP协议、防火墙配置和负载均衡概念-数据库技能:掌握SQL语言和常见数据库管理工具的使用-业务理解:具备一定的业务流程分析和需求理解能力1.4实验环境规划1.4.1软件环境清单-操作系统:UbuntuServer20.04LTS或CentOS8.4-容器平台:Docker20.10+,DockerCompose2.0+-数据库:PostgreSQL13+,MicrosoftSQLServer2019-中间件:Redis6.2+,Nginx1.20+-监控工具:Prometheus2.30+,Grafana8.0+-低代码平台:Mendix9.0+,OutSystems11.0+2低代码平台技术选型2.1主流平台对比分析在开始部署前,必须对主流低代码平台进行全面评估,确保选型符合企业技术战略和业务需求。2.2Mendix平台架构解析Mendix采用云原生架构设计,支持多种部署模式:```mermaidgraphTBA[MendixStudioPro]-->B[TeamServer]B-->C[MendixRuntime]C-->D[数据库服务]C-->E[外部服务集成]F[Web客户端]-->CG[移动客户端]-->Csubgraph"部署选项"H[MendixCloud]I[私有云]J[公有云]K[混合云]endC-->HC-->IC-->JC-->K```核心组件说明:-StudioPro:Windows端专业开发工具,提供完整的可视化开发环境-TeamServer:基于SVN的协作服务器,管理版本控制和团队协作-Runtime:Java-based运行时环境,执行Mendix应用-CloudPortal:Web管理控制台,用于应用部署和运维管理2.3OutSystems平台架构解析OutSystems采用全栈可视化开发模式,生成优化的本地代码:```mermaidgraphLRA[ServiceStudio]-->B[PlatformServer]B-->C[应用部署]C-->D[前端服务]C-->E[后端服务]D-->F[Web应用]D-->G[移动应用]E-->H[数据库]E-->I[外部集成]subgraph"架构特性"J[TrueChange引擎]K[依赖分析]L[增量部署]endB-->JJ-->KJ-->L```核心优势:-TrueChange引擎:自动管理应用依赖和部署顺序-增量部署:只部署变更部分,大幅提升发布效率-性能优化:生成高度优化的本地代码,性能接近原生开发3平台部署实施3.1基础设施准备3.1.1服务器标准化配置```bash!/bin/bashlowcode-platform-init.sh低代码平台基础环境初始化脚本set-eecho"开始低代码平台基础环境配置..."系统更新和基础包安装apt-getupdate&&apt-getupgrade-yapt-getinstall-ycurlwgetvimnet-toolstelnetopensslca-certificates创建低代码平台专用用户和组groupaddlowcodeuseradd-m-s/bin/bash-glowcodemendixuseruseradd-m-s/bin/bash-glowcodeoutsystemsuser创建标准化目录结构mkdir-p/opt/lowcode/{mendix,outsystems,backup,logs,scripts}mkdir-p/opt/lowcode/mendix/{apps,data,models,temp}mkdir-p/opt/lowcode/outsystems/{apps,services,deploy,logs}设置目录权限chown-Rmendixuser:lowcode/opt/lowcode/mendixchown-Routsystemsuser:lowcode/opt/lowcode/outsystemschmod-R755/opt/lowcode配置内核参数优化cat>>/etc/sysctl.conf<<EOF低代码平台内核优化net.core.somaxconn=65535net.ipv4.tcp_max_syn_backlog=65535vm.swappiness=10vm.overcommit_memory=1EOF应用内核参数sysctl-pecho"基础环境配置完成!"```3.1.2容器环境部署```yamldocker-compose-infra.ymlversion:'3.8'services:PostgreSQL数据库postgresql:image:postgres:13container_name:lowcode-postgresenvironment:POSTGRES_DB:lowcode_platformPOSTGRES_USER:lowcode_adminPOSTGRES_PASSWORD:${DB_PASSWORD}ports:-"5432:5432"volumes:-postgres_data:/var/lib/postgresql/data-./init-scripts:/docker-entrypoint-initdb.dnetworks:-lowcode-networkRedis缓存redis:image:redis:6.2-alpinecontainer_name:lowcode-rediscommand:redis-server--requirepass${REDIS_PASSWORD}ports:-"6379:6379"volumes:-redis_data:/datanetworks:-lowcode-networkNginx负载均衡nginx:image:nginx:1.20container_name:lowcode-nginxports:-"80:80"-"443:443"volumes:-./nginx/conf.d:/etc/nginx/conf.d-./nginx/ssl:/etc/nginx/ssl-./nginx/logs:/var/log/nginxdepends_on:-mendix-runtime-outsystems-servernetworks:-lowcode-networkvolumes:postgres_data:redis_data:networks:lowcode-network:driver:bridge```3.2Mendix平台部署3.2.1运行时环境配置```bash!/bin/bashmendix-deploy.shecho"开始部署Mendix平台..."创建Mendix专用数据库sudo-upostgrespsql-c"CREATEDATABASEmendix_platform;"sudo-upostgrespsql-c"CREATEUSERmendix_runtimeWITHPASSWORD'${RUNTIME_PASSWORD}';"sudo-upostgrespsql-c"GRANTALLPRIVILEGESONDATABASEmendix_platformTOmendix_runtime;"下载并安装MendixRuntimewget-O/opt/lowcode/mendix/mendix-runtime.deb\"/runtime/mendix-runtime-9.0.0-amd64.deb"dpkg-i/opt/lowcode/mendix/mendix-runtime.deb配置Runtime环境cat>/etc/mendix/runtime.cfg<<EOFMendixRuntime配置AppName=LowCodePlatformAppVersion=1.0.0DatabaseType=PostgreSQLDatabaseName=mendix_platformDatabaseUserName=mendix_runtimeDatabasePassword=${RUNTIME_PASSWORD}DatabaseHost=localhostDatabasePort=5432JVM配置-Xmx2048m-Xms1024m-XX:MaxMetaspaceSize=512m日志配置LogLevel=INFOLogOutput=fileLogFilename=/opt/lowcode/mendix/logs/runtime.logEOF启动Mendix服务systemctlenablemendix-runtimesystemctlstartmendix-runtimeecho"Mendix平台部署完成!"```3.2.2Docker化部署方案```yamldocker-compose-mendix.ymlversion:'3.8'services:mendix-runtime:image:mendix/runtime:9.0.0container_name:mendix-runtimeenvironment:-MX_RUNTIME_DB_TYPE=PostgreSQL-MX_RUNTIME_DB_HOST=postgresql-MX_RUNTIME_DB_NAME=mendix_platform-MX_RUNTIME_DB_USERNAME=mendix_runtime-MX_RUNTIME_DB_PASSWORD=${RUNTIME_PASSWORD}-MX_RUNTIME_DB_PORT=5432-MX_RUNTIME_DB_CONNECTION_PARAMS=sslmode=preferports:-"8080:8080"-"8090:8090"volumes:-mendix_data:/data-mendix_logs:/logs-./mendix/apps:/appsdepends_on:-postgresql-redisnetworks:-lowcode-networkrestart:unless-stoppedmendix-gateway:image:nginx:1.20container_name:mendix-gatewayports:-"80:80"volumes:-./mendix/nginx.conf:/etc/nginx/nginx.confdepends_on:-mendix-runtimenetworks:-lowcode-networkvolumes:mendix_data:mendix_logs:networks:lowcode-network:external:true```3.3OutSystems平台部署3.3.1平台服务器安装```bash!/bin/bashoutsystems-deploy.shecho"开始部署OutSystems平台..."下载OutSystems安装包wget-O/opt/lowcode/outsystems/outsystems-platform.tar.gz\"/Platform/11/OutSystemsPlatformServer.11.0.0.tar.gz"解压安装包tar-xzf/opt/lowcode/outsystems/outsystems-platform.tar.gz-C/opt/lowcode/outsystems/运行安装向导cd/opt/lowcode/outsystems/PlatformServer./installer.sh--silent--installation-path/opt/lowcode/outsystems/install配置数据库连接/opt/lowcode/outsystems/install/servicecenter_admin.exe\-configDatabaseServer=localhost\-configDatabaseCatalog=outsystems_platform\-configDatabaseUserName=outsystems_admin\-configDatabaseUserPassword=${OUTSYSTEMS_DB_PASSWORD}启动服务systemctlenableoutsystems-platformsystemctlstartoutsystems-platformecho"OutSystems平台部署完成!"```3.3.2分布式架构部署```yamldocker-compose-outsystems.ymlversion:'3.8'services:outsystems-frontend:image:outsystems/platform:11.0container_name:outsystems-frontendenvironment:-OS_DB_TYPE=PostgreSQL-OS_DB_HOST=postgresql-OS_DB_NAME=outsystems_platform-OS_DB_USER=outsystems_runtime-OS_DB_PASSWORD=${OUTSYSTEMS_DB_PASSWORD}-OS_REDIS_HOST=redis-OS_REDIS_PASSWORD=${REDIS_PASSWORD}ports:-"8000:8000"volumes:-outsystems_frontend_data:/data-outsystems_frontend_logs:/logsdepends_on:-postgresql-redisnetworks:-lowcode-networkdeploy:replicas:2outsystems-deployment:image:outsystems/deployment:11.0container_name:outsystems-deploymentenvironment:-OS_DB_TYPE=PostgreSQL-OS_DB_HOST=postgresql-OS_DB_NAME=outsystems_platform-OS_DB_USER=outsystems_deployment-OS_DB_PASSWORD=${DEPLOYMENT_DB_PASSWORD}volumes:-outsystems_deployment_data:/datadepends_on:-postgresqlnetworks:-lowcode-networkoutsystems-scheduler:image:outsystems/scheduler:11.0container_name:outsystems-schedulerenvironment:-OS_DB_TYPE=PostgreSQL-OS_DB_HOST=postgresql-OS_DB_NAME=outsystems_platform-OS_DB_USER=outsystems_scheduler-OS_DB_PASSWORD=${SCHEDULER_DB_PASSWORD}depends_on:-postgresqlnetworks:-lowcode-networkvolumes:outsystems_frontend_data:outsystems_frontend_logs:outsystems_deployment_data:networks:lowcode-network:external:true```3.4高可用集群配置3.4.1Mendix集群配置```yamldocker-compose-mendix-cluster.ymlversion:'3.8'services:mendix-runtime-1:image:mendix/runtime:9.0.0container_name:mendix-runtime-1environment:-MX_RUNTIME_DB_TYPE=PostgreSQL-MX_RUNTIME_DB_HOST=postgresql-MX_RUNTIME_DB_NAME=mendix_platform-MX_RUNTIME_DB_USERNAME=mendix_runtime-MX_RUNTIME_DB_PASSWORD=${RUNTIME_PASSWORD}-MX_RUNTIME_CLUSTER_ENABLED=true-MX_RUNTIME_CLUSTER_NODES=mendix-runtime-1,mendix-runtime-2,mendix-runtime-3networks:-lowcode-networkdeploy:replicas:1mendix-runtime-2:image:mendix/runtime:9.0.0container_name:mendix-runtime-2environment:-MX_RUNTIME_DB_TYPE=PostgreSQL-MX_RUNTIME_DB_HOST=postgresql-MX_RUNTIME_DB_NAME=mendix_platform-MX_RUNTIME_DB_USERNAME=mendix_runtime-MX_RUNTIME_DB_PASSWORD=${RUNTIME_PASSWORD}-MX_RUNTIME_CLUSTER_ENABLED=true-MX_RUNTIME_CLUSTER_NODES=mendix-runtime-1,mendix-runtime-2,mendix-runtime-3networks:-lowcode-networkdeploy:replicas:1mendix-loadbalancer:image:nginx:1.20container_name:mendix-loadbalancerports:-"8080:8080"volumes:-./mendix/loadbalancer.conf:/etc/nginx/nginx.confdepends_on:-mendix-runtime-1-mendix-runtime-2networks:-lowcode-networknetworks:lowcode-network:external:true```4平台配置与集成4.1用户认证与权限管理4.1.1LDAP/ActiveDirectory集成```java//MendixLDAP集成配置publicclassLDAPConfiguration{@AutowiredprivateEnvironmentenv;@BeanpublicLdapContextSourcecontextSource(){LdapContextSourcecontextSource=newLdapContextSource();contextSource.setUrl(env.getProperty("ldap.url"));contextSource.setBase(env.getProperty("ldap.base.dn"));contextSource.setUserDn(env.getProperty("ldap.username"));contextSource.setPassword(env.getProperty("ldap.password"));returncontextSource;}@BeanpublicLdapTemplateldapTemplate(){returnnewLdapTemplate(contextSource());}@BeanpublicAuthenticationManagerauthenticationManager(){returnnewLdapAuthenticationManager(contextSource(),env.getProperty("ldap.user.search.base"),env.getProperty("ldap.user.search.filter"));}}```4.1.2SAML单点登录配置```xml<!--MendixSAML配置--><?xmlversion="1.0"encoding="UTF-8"?><md:EntityDescriptorxmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"entityID="/saml"><md:IDPSSODescriptorWantAuthnRequestsSigned="false"protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptoruse="signing"><ds:KeyInfoxmlns:ds="/2000/09/xmldsig"><ds:X509Data><ds:X509Certificate>${SAML_CERTIFICATE}</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:SingleSignOnServiceBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"Location="/saml/sso"/></md:IDPSSODescriptor></md:EntityDescriptor>```4.2数据源与系统集成4.2.1数据库连接配置```sql--创建Mendix平台数据库用户和权限CREATEUSERmendix_appuserWITHPASSWORD'${APP_USER_PASSWORD}';GRANTCONNECTONDATABASEmendix_platformTOmendix_appuser;--创建应用专用schemaCREATESCHEMAIFNOTEXISTShr_app;GRANTUSAGEONSCHEMAhr_appTOmendix_appuser;GRANTSELECT,INSERT,UPDATE,DELETEONALLTABLESINSCHEMAhr_appTOmendix_appuser;--创建OutSystems集成视图CREATEVIEWhr_app.employee_dataASSELECTe.employee_id,e.first_name,e.last_name,e.email,d.department_name,p.position_titleFROMenterprise_hr.employeeseJOINenterprise_hr.departmentsdONe.department_id=d.department_idJOINenterprise_hr.positionspONe.position_id=p.position_id;```4.2.2RESTAPI集成配置```java//MendixREST消费配置publicclassRESTIntegration{publicvoidcallExternalService(Stringendpoint,Objectpayload){try{RestTemplaterestTemplate=newRestTemplate();HttpHeadersheaders=newHttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);headers.set("Authorization","Bearer"+getAccessToken());HttpEntity<Object>request=newHttpEntity<>(payload,headers);ResponseEntity<String>response=restTemplate.exchange(endpoint,HttpMethod.POST,request,String.class);if(response.getStatusCode()==HttpStatus.OK){processResponse(response.getBody());}else{handleError(response.getStatusCode(),response.getBody());}}catch(Exceptione){log.error("REST调用失败:{}",e.getMessage());thrownewRuntimeException("外部服务调用失败",e);}}privateStringgetAccessToken(){//OAuth2.0令牌获取逻辑returntokenService.acquireToken();}}```4.3平台监控配置4.3.1应用性能监控```yamlprometheus-lowcode.ymlglobal:scrape_interval:15sscrape_configs:-job_name:'mendix-platform'static_configs:-targets:['mendix-runtime-1:8080','mendix-runtime-2:8080']metrics_path:'/monitoring/prometheus'scrape_interval:30s-job_name:'outsystems-platform'static_configs:-targets:['outsystems-frontend:8000']metrics_path:'/servicecenter/monitoring_metrics'-job_name:'database-metrics'static_configs:-targets:['postgresql:5432']-job_name:'system-metrics'static_configs:-targets:['node-exporter:9100']```4.3.2业务日志收集```java//统一日志配置@Configuration@Slf4jpublicclassLoggingConfiguration{@BeanpublicFilterloggingFilter(){returnnewCommonsRequestLoggingFilter(){@OverrideprotectedvoidbeforeRequest(HttpServletRequestrequest,Stringmessage){MDC.put("requestId",generateRequestId());MDC.put("userId",getCurrentUserId());("开始处理请求:{}",message);}@OverrideprotectedvoidafterRequest(HttpServletRequestrequest,Stringmessage){("请求处理完成:{}",message);MDC.clear();}};}@BeanpublicMeterRegistryCustomizer<MeterRegistry>metricsCommonTags(){returnregistry->registry.config().commonTags("application","lowcode-platform","environment","production");}}```5应用开发实战5.1需求分析与领域建模5.1.1业务流程分析以"员工请假审批系统"为例,进行完整的低代码应用开发:```mermaidgraphTDA[员工提交请假申请]-->B[部门经理审批]B-->C{审批结果}C-->|通过|D[HR备案]C-->|拒绝|E[通知员工]D-->F[考勤系统同步]E-->G[流程结束]F-->Gsubgraph"业务规则"H[假期余额检查]I[审批权限验证]J[自动催办]endA-->HB-->IB-->J```5.1.2数据模型设计```sql--请假系统数据模型CREATETABLEleave_application(idUUIDPRIMARYKEYDEFAULTgen_random_uuid(),employee_idVARCHAR(20)NOTNULL,leave_typeVARCHAR(50)NOTNULL,--年假、病假、事假start_dateDATENOTNULL,end_dateDATENOTNULL,total_daysINTEGERNOTNULL,reasonTEXT,statusVARCHAR(20)DEFAULT'PENDING',--PENDING,APPROVED,REJECTEDapplicant_commentTEXT,approver_commentTEXT,current_approver_idVARCHAR(20),created_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP,updated_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP);CREATETABLEleave_balance(employee_idVARCHAR(20)PRIMARYKEY,annual_leave_daysDECIMAL(5,2)DEFAULT0,sick_leave_daysDECIMAL(5,2)DEFAULT0,personal_leave_daysDECIMAL(5,2)DEFAULT0,updated_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP);CREATETABLEapproval_workflow(idUUIDPRIMARYKEY,application_idUUIDREFERENCESleave_application(id),approver_idVARCHAR(20)NOTNULL,approval_orderINTEGERNOTNULL,approval_statusVARCHAR(20)DEFAULT'PENDING',approved_atTIMESTAMP,commentsTEXT);```5.2Mendix应用开发5.2.1领域模型创建在MendixStudioPro中创建领域模型:```java//实体定义示例@EntitypublicclassLeaveApplicationextendsGenericEntity{@Column(length=20)privateStringemployeeId;@Column(length=50)privateStringleaveType;@Temporal(TemporalType.DATE)privateDatestartDate;@Temporal(TemporalType.DATE)privateDateendDate;privateIntegertotalDays;@Column(length=20)privateStringstatus="PENDING";@OneToMany(mappedBy="application")privateList<ApprovalWorkflow>workflows;//业务逻辑方法publicbooleanvalidateLeaveBalance(){//验证假期余额逻辑returngetAvailableBalance()>=this.totalDays;}publicvoidstartApprovalWorkflow(){//启动审批流程ApprovalWorkflowworkflow=newApprovalWorkflow();workflow.setApplication(this);workflow.setApproverId(findNextApprover());workflow.setApprovalOrder(1);workflow.save();//发送通知sendApprovalNotification(workflow.getApproverId());}}```5.2.2微流设计创建请假申请审批微流:```java//请假申请提交微流@MicroflowpublicvoidsubmitLeaveApplication(LeaveApplicationapplication){try{//1.数据验证if(!application.validateLeaveBalance()){thrownewValidationException("假期余额不足");}//2.设置初始状态application.setStatus("PENDING");mit();//3.启动审批流程startApprovalWorkflow(application);//4.记录操作日志auditService.logAction("LEAVE_SUBMIT",application.getId());//5.发送提交确认通知notificationService.sendConfirmation(application.getEmployeeId());}catch(Exceptione){rollbackTransaction();handleError(e);thrownewRuntimeException("请假申请提交失败",e);}}```5.2.3页面设计创建响应式请假申请页面:```xml<!--请假申请页面布局--><pagetitle="请假申请"layoutType="responsive"><header><title-caption>员工请假申请系统</title-caption></header><body><form-container><text-fielddata-source="${employeeId}"label="工号"required="true"enabled="false"/><select-fielddata-source="${leaveType}"label="请假类型"required="true"><optionvalue="ANNUAL">年假</option><optionvalue="SICK">病假</option><optionvalue="PERSONAL">事假</option></select-field><date-pickerdata-source="${startDate}"label="开始日期"required="true"/><date-pickerdata-source="${endDate}"label="结束日期"required="true"/><text-areadata-source="${reason}"label="请假事由"rows="3"/><action-buttoncaption="提交申请"on-click="submitApplication"style="primary"/></form-container><!--假期余额显示--><data-griddata-source="${leaveBalance}"><columncaption="假期类型"data-source="leaveType"/><columncaption="可用天数"data-source="availableDays"/><columncaption="已用天数"data-source="usedDays"/></data-grid></body></page>```5.3OutSystems应用开发5.3.1数据模型设计在OutSystemsServiceStudio中设计数据模型:```sql--OutSystems实体定义CREATEENTITYLeaveApplication(Id:IntegerIdentifierAutoNumber,EmployeeId:Text(20)Mandatory,LeaveType:Text(50)Mandatory,StartDate:DateMandatory,EndDate:DateMandatory,TotalDays:IntegerMandatory,Reason:TextMandatory,Status:Text(20)Default'Pending',CreatedBy:Text(20)Mandatory,CreatedOn:DateTimeMandatory,UpdatedBy:Text(20),UpdatedOn:DateTime);CREATEENTITYApprovalWorkflow(Id:IntegerIdentifierAutoNumber,LeaveApplicationId:IntegerMandatory,ApproverId:Text(20)Mandatory,ApprovalOrder:IntegerMandatory,Status:Text(20)Default'Pending',Comments:Text,ApprovedOn:DateTime);```5.3.2业务流程设计设计请假审批业务流:```javascript//请假审批流程逻辑functionStartLeaveApprovalProcess(leaveApplicationId){//获取申请信息varapplication=LeaveApplication.GetById(leaveApplicationId);//验证业务规则if(!ValidateLeaveApplication(application)){thrownewError("申请验证失败");}//查找审批人varapprovers=FindApprovers(application.EmployeeId,application.LeaveType);//创建审批流程for(vari=0;i<approvers.length;i++){CreateApprovalStep(application.Id,approvers[i],i+1);}//更新申请状态application.Status="InApproval";application.Update();//发送通知SendApprovalNotification(approvers[0],application.Id);//记录审计日志AuditLog.Record("APPROVAL_STARTED",application.Id);}```5.3.3响应式界面开发创建移动友好的审批界面:```html<!--请假审批页面--><divclass="container-fluid"><divclass="row"><divclass="col-md-8"><!--申请详情--><divclass="card"><divclass="card-header"><h5>请假申请详情</h5></div><divclass="card-body"><divclass="row"><divclass="col-md-6"><label>申请人:</label><p>{{EmployeeName}}</p></div><divclass="col-md-6"><label>请假类型:</label><p>{{LeaveTypeName}}</p></div></div><divclass="row"><divclass="col-md-6"><label>时间范围:</label><p>{{StartDate}}至{{EndDate}}</p></div><divclass="col-md-6"><label>总天数:</label><p>{{TotalDays}}天</p></div></div><divclass="row"><divclass="col-12"><label>请假事由:</label><p>{{Reason}}</p></div></div></div></div><!--审批操作--><divclass="cardmt-3"><divclass="card-body"><textareaclass="form-control"rows="3"placeholder="审批意见"ng-model="ApprovalComments"></textarea><divclass="mt-3"><buttonclass="btnbtn-success"ng-click="ApproveApplication()">批准</button><buttonclass="btnbtn-dangerml-2"ng-click="RejectApplication()">拒绝</button></div></div></div></div><divclass="col-md-4"><!--审批流程状态--><divclass="card"><divclass="card-header"><h6>审批流程</h6></div><divclass="card-body"><divclass="timeline"><divclass="timeline-item"ng-repeat="stepinApprovalSteps"ng-class="{'completed':step.Status=='Approved'}"><divclass="timeline-marker"></div><divclass="timeline-content"><h6>{{step.ApproverName}}</h6><p>{{step.Status}}-{{step.UpdatedOn}}</p></div></div></div></div></div></div></div></div>```6DevOps与持续集成6.1代码版本管理6.1.1Git工作流设计```yaml.gitlab-ci.yml-低代码平台CI/CD流水线stages:-build-test-security_scan-deployvariables:MAVEN_OPTS:"-Dmaven.repo.local=.m2/repository"build:stage:buildimage:maven:3.8.4-openjdk-11script:-mvncleancompile-mvnpackage-DskipTestsartifacts:paths:-target/.jarexpire_in:1weekonly:-develop-mainunit_test:stage:testimage:maven:3.8.4-openjdk-11script:-mvntestcoverage:'/Codecoverage:\d+\.\d+/'security_scan:stage:security_scanimage:name:aquasec/trivy:0.32.1entrypoint:[""]script:-trivyfilesystem--exit-code1--no-progress.allow_failure:truedeploy_development:stage:deployimage:alpine:3.16script:-chmod+xdeploy-scripts/deploy-dev.sh-./deploy-scripts/deploy-dev.shenvironment:name:developmenturl:only:-developdeploy_production:stage:deployimage:alpine:3.16script:-chmod+xdeploy-scripts/deploy-prod.sh-./deploy-scripts/deploy-prod.shenvironment:name:productionurl:only:-mainwhen:manual```6.2自动化测试策略6.2.1测试金字塔实施```java//单元测试示例@ExtendWith(MockitoExtension.class)classLeaveApplicationServiceTest{@MockprivateLeaveBalanceRepositorybalanceRepository;@MockprivateApprovalWorkflowServiceworkflowService;@InjectMocksprivateLeaveApplicationServiceapplicationService;@TestvoidshouldSubmitApplication_WhenBalanceIsSufficient(){//GivenLeaveApplicationapplication=createValidApplication();given(balanceRepository.findByEmployeeId(anyString())).willReturn(createSufficientBalance());//WhenApplicationResultresult=applicationService.submitApplication(application);//ThenassertThat(result.isSuccess()).isTrue();assertThat(application.getStatus()).isEqualTo("PENDING");verify(workflowService).startApprovalProcess(application);}@TestvoidshouldRejectApplication_WhenBalanceIsInsufficient(){//GivenLeaveApplicationapplication=createValidApplication();given(balanceRepository.findByEmployeeId(anyString())).willReturn(createInsufficientBalance());//When&ThenassertThatThrownBy(()->applicationService.submitApplication(application)).isInstanceOf(InsufficientBalanceException.class).hasMessage("假期余额不足");

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论