使用Gitlab实现monorepo多项目CICD

news2024/11/16 2:52:22

CI/CD是什么

        CI/CD(Continuous Intergration/Continuous Delpoy),即持续集成/持续部署,或称为持续集成/持续交付,作为一套面向开发和运维团队的解决方案,CI/CD 主要解决集成新代码和向用户频繁交付应用的问题。更直接地说,就是可以解放开发人员的双手,将时间和精力专注于代码本身。

        传统的前端部署往往都要经历:本地代码更新 => 本地打包项目 => 清空服务器相应目录 => 上传项目包至相应目录几个阶段,这些都是机械重复的步骤,并且手动操作非常容易出错。对于这一过程,我们往往可以通过CI/CD 方式进行优化。

        从前端的角度看,CICD的流程中涉及:

  • CI:代码push到托管平台之后的lint测试、单元测试

  • CD:将build后的项目丢到远端 Nginx 的静态资源目录下

自动化部署的好处

  • 按照传统方式

    时间成本高:手动部署占用开发时间。

    沟通效率低:开发与测试间沟通频繁且易出错。

    错误风险高:人为操作易导致配置错误等问题。

    难以追踪:缺乏统一的日志记录和追踪。

    灵活性差:难以快速响应紧急部署需求。

  • 使用自动化部署

    节省时间:自动完成部署流程,提升开发效率。

    提高沟通效率:实时共享部署状态,减少沟通成本。

    减少错误:降低人为错误,提高部署稳定性。

    增强代码质量:集成代码检查,确保代码质量。

    提高灵活性:快速响应代码变更和紧急部署。

    增强可追溯性:记录详细日志,便于问题追踪。

    支持CI/CD:加速产品迭代和交付。

构建/部署

        说的简单点,就是先利用 webpack 或者 gulp 这类的工具把工程打包,然后把打包得到的文件放在服务器上某个托管静态资源的 Web 容器里,像 Java 就可以放在 Tomcat,不过现在流行用 Nginx 托管静态资源。有了 Web 容器,前端打包的那些文件(比如index.html, main.js等等)就可以被访问到了。

手动档

1、本地执行 npm run build构建项目

2、使用 FileZilla 或其他支持 sftp 的软件上传打包后的项目(当然也有其他方式)

3、修改 Nginx 的 nginx.conf 文件,配置项目的访问路径

        手动部署操作起来很简单,但缺点也很明显,每次构建完都要人为地进行部署的动作,一方面减少了实际敲代码的时间,另一方面,人工操作免不了会有疏忽出错的时候。

半自动挡

1、本地配置好脚本

2、使用 package.json 中配置的命令执行

3、等待自动打包上传流程结束

        虽然这样的操作也很方便且不易出错,但每次都要等待代码打包上传完了才能下机,还是挺浪费时间的。

自动挡

        随着工程化的发展和工具链的成熟,项目部署不再像以前简单粗暴。前端代码的健壮性可靠性越来越被重视,项目发布前往往需要 代码约束代码测试 ,校验通过后服务器拉取最新的代码,进行 build 和 nginx 配置后才算完成整个部署的过程。

1、代码扫描 npm run lint检查代码是否规范

2、npm run unit进行单元测试

3、git push提交更改到远端仓库

4、登录服务器,git pull拉取最新代码

5、npm run build构建项目

6、配置 nginx 访问路径

6、配置 nginx 访问路径 这个阶段,我们借助一些工具,能够减少代码不规范或隐藏bug的问题。

        但所有的操作还是得一行一行命令去敲,项目真正的部署也还是需要手动去操作服务器。也可以将上面的操作细节都集成到一个 shell 脚本里,通知执行 shell 也能减少很多重复的工作。

CI/CD 做了什么

        一个版本发布的过程主要分为以下几个步骤:

  • 代码合并:测试环境或生产环境都有独立的分支,等所有待发版的代码都合并到对应分支后,就可以考虑发版了。

  • 打包:或者叫构建。以生产环境部署为例,我们切到生产环境分支并 pull 最新代码后,就可以开始打包步骤了。这一步主要是通过一些 bundler 完成的,比如 webpack。而打包命令一般都是定义在package.jsonscripts中了,比如定义的命令是build:prod,那么只要运行npm run build:prod就行了。

  • 部署:把打包得到的文件放在 web 容器中,而 web 容器通常在 Linux 服务器上,这涉及到远程传输文件,这个时候我们一般要借助 shell 脚本或者 xftp。

        而 CI/CD 做的事情就是:用自动化技术接管流程

核心工具

GitLab Runner

   GitLab Runner是配合GitLab CI/CD完成工作的核心程序,出于性能考虑,GitLab Runner应该与Gitlab部署在不同的服务器上(Gitlab在单独的仓库服务器上,GitLab Runner在部署web应用的服务器上)。GitLab Runner在与GitLab关联后,可以在服务器上完成诸如项目拉取、文件打包、资源复制等各种命令操作。

Git

        web服务器上需要安装Git来进行远程仓库的获取工作。

Node

        用于在web服务器上完成打包工作。

NPM or Yarn or pnpm

        用于在web服务器上完成依赖下载等工作(用yarn,pnpm亦可)。

Gitlab CI/CD是如何工作的

        从 GitLab 8.0 开始,GitLab CI 就已经集成在 GitLab 中,我们只要在项目中添加一个 .gitlab-ci.yml 文件,然后添加一个 Runner,即可进行持续集成。 而且随着 GitLab 的升级,GitLab CI 变得越来越强大。

Pipeline

        Pipeline 是 CI/CD 的最上层组件,它翻译过来是管道,也可理解为流水线,每一个符合.gitlab-ci.yml触发规则的 CI/CD 任务都会产生一个 Pipeline。这个概念有点像工厂中的车间流水线,我们知道车间中有很多条流水线,不同的流水线可能会处理同一类型的生产任务,也可能处理不同类型的生产任务。当一条流水线空闲的时候,就有可能会被用来安排执行其他的生产任务。而 Gitlab 的 Pipeline 虽然没有空闲的概念,一个 Pipeline 执行结束后也不会被复用,但是会将资源让出来给其他的 Pipeline,所以和车间流水线也有异曲同工之妙。

        一次 Pipeline 其实相当于一次构建任务,里面可以包含多个流程,如安装依赖、运行测试、编译、部署测试服务器、部署生产服务器等流程。我们的任何提交或者 Merge Request 的合并都可以触发 Pipeline。

        不同 push/merge 所触发的 CI 流程不会互相影响,也就是说,你的一次push引发的CI流程并不会因为接下来另一位同事的push而阻断,它们是互不影响的。这一个特点方便让测试同学根据不同版本进行测试。

Stages

        Stages 表示构建阶段,其实就是上面提到的流程。我们可以在一次 Pipeline 中定义多个 Stages,每个Stage可以完成不同的任务。一个 Pipeline 有若干个stage,每个 stage 上有至少一个 Job。Stages 有下面的特点:

  • 所有 Stages 会按照顺序运行,即当一个 Stage 完成后,下一个 Stage 才会开始

  • 只有当所有 Stages 完成后,该构建任务 (Pipeline) 才会成功

  • 如果任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败

Jobs

        Jobs 表示构建工作,就是某个 Stage 里面执行的工作。Job是pipeline的任务节点,它构成了pipeline的基本单元。我们可以在 Stages 里面定义多个 Jobs,每个Job都会配置一个stage属性,表示这个Job所处的阶段。Jobs 有以下特点:

  • 相同 Stage 中的 Jobs 会并行执行

  • 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功

  • 如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 失败

Runner

        有了流水线,还必须有辛勤的工人进行生产作业,Runner 在 Gitlab Pipeline 中就扮演着工人角色,根据我们下达的指令进行作业。

        它是脚本执行的承载者,.gitlab-ci.yml 的 script 部分的运行就是由 Runner 来负责的。GitLab-CI 浏览过项目里的 .gitlab-ci.yml 文件之后,根据里面的规则,分配到各个 Runner 来运行相应的脚本 script。这些脚本有的是测试项目用的,有的是部署用的。

Runner的类型

        在 Gitlab 中,Runner 有很多种,分为 Shared Runner, Group Runner, Specific Runner

  • Shared Runner 是所有项目都可以使用的,可以理解为机动人员,他可能会在工厂的各个流水线机动作业,随时支援!在整个 Gitlab 应用中,可以服务于各个 Project。使用受运行时间的限制。

  • Specific Runner 只服务于指定的项目,也就是 Project 级别,别的项目咱都不去。使用完全自由。

  • Group Runner 就比较好理解了,他只在这个组上班,别的组他是不会去的。在 Gitlab 中,我们是可以建立不同的 Group 的,比如前端一个 Group,后端一个 Group,甚至前端里面还可以分 N 个 Group。所以,Group Runner 只服务于指定的 Group

注册Runner

        工人是要持证上岗的,同样,Runner 有一个注册的过程,就相当于在工厂中入职登记的意思。具体见 Registering Runners。只有合法注册的 Runner,才有资格执行 Pipeline。

.gitlab-ci.yml

        流水线和工人都安排好之后,就必须制定车间生产规章制度了,一条流水线到底怎么干活,总要有个规矩。而.gitlab-ci.yml文件就是用来制定规则的!它是流水线执行的流程文件,Runner 会据此完成规定的一系列流程,保存并推送至 gitlab 后即可自动开始构建部署,构建中可在 gitlab CI/CD 面板查看构建进程。

        .gitlab-ci.yml 是在 git 项目的根目录下的一个文件,记录了一系列的阶段和执行规则。GitLab-CI 在 push 后会解析它,根据里面的内容调用 Runner 来运行。简单来讲,就是当我们 push 了本地代码到 Remote 上(这里就是 gitlab.com),然后 Gitlab就通知服务器,即 Gitlab-Runner 来运行构建任务。然后跑测试用例,测试用例通过了就 build 出相应的环境的代码,自动部署到不同的环境服务器上面去。

        配置好 Runner 后,我们要做的事情就是在项目根目录中添加 .gitlab-ci.yml 文件了,可以控制 CI 流程的不同阶段,例如install/检查/编译/部署服务器,gitlab 平台会扫描.gitlab-ci.yml文件,并据此处理ci流程。 当我们添加了 .gitlab-ci.yml 文件后,每次提交代码或合并 MR 都会自动运行构建任务了。

        CI 流程在每次 push/merge 之后触发,每当 push/merge 一次,gitlab-ci 都会检查项目下有没有 .gitlab-ci.yml 文件,如果有,它会执行里面编写的脚本,并完整地走一遍从 intall => eslint检查 => 编译 => 部署服务器 的流程。

变量 Variables

        Gitlab 通过 Variables 为 CI/CD 提供了更多配置化的能力,方便我们快速取得一些关键信息,用来做流程决策。上述示例中的$CI_COMMIT_REF_NAME$CI_PROJECT_DIR就是 Gitlab 的预定义变量。

        除了预定义变量,我们也可以自行定义一些环境变量,比如服务器 ip,用户名等等,这样就免去了在配置文件中明文列出私密信息的风险;另一方面也方便后期快速调整配置,避免直接修改.gitlab-ci.yml

授信问题

        在不同主机间通过scp传输文件需要建立信任关系,在 CI/CD 中最好选择免密方式,其基本原理就是把 ssh公钥 交给对方。

        在 GitLab 的 CI/CD 流程中,使用 scp 或任何基于 SSH 的命令来在不同的主机之间传输文件时,需要建立一种安全的免密登录方式。这通常通过 SSH 密钥认证来实现,即将一个 SSH 公钥添加到远程服务器的 ~/.ssh/authorized_keys 文件中,这样持有相应私钥的用户就可以无密码登录该服务器了。

使用Gitlab实现多项目CICD

背景

        有一个 monorepo 微前端项目,需要一次构建3个项目,放在根目录下的packages文件夹下,分别是rdm、rdm-old、rdm-new,在测试分支打包,分别生成自己的 dist/test,正式服则是 dist/prod,正式服构建到 A 服务器的 rdm、rdm-old、rdm-new 文件夹,测试服到 B 服务器的 rdm、rdm-old、rdm-new 文件夹。现在,我们希望在一次CI/CD流程中构建并部署多个子应用(rdm, rdm-new, rdm-old),同时这些应用需要被部署到不同服务器上的不同的 FTP 目录。

        用直观的方式呈现如下图:

方案

        为了实现这个需求,我们可以在.gitlab-ci.yml文件中设置一个共同的构建阶段,然后针对不同的环境(测试服和正式服)和不同的子应用设置不同的部署阶段。

# 定义CI/CD的阶段 
stages:  
  - build   # 构建阶段 
  - deploy  # 部署阶段  
  
# 定义一些全局变量,用于SSH连接和部署  
variables:  
  SSH_USER: "用户名"  
  SSH_PASSWORD: "用户密码"  
  SSH_OPTIONS: "-o StrictHostKeyChecking=no"  
  
# 定义一个模板,用于SSH部署  
.deploy_template: &deploy_template  
  stage: deploy  
  script:  
    - echo "Deploying to $TARGET_SERVER in $DEPLOY_PATH"  
    - sshpass -p "$SSH_PASSWORD" ssh $SSH_USER@$TARGET_SERVER "mkdir -p $DEPLOY_PATH"  
    - sshpass -p "$SSH_PASSWORD" scp -r $SSH_OPTIONS ./dist/$DEPLOY_TYPE/* $SSH_USER@$TARGET_SERVER:$DEPLOY_PATH  
  

# RDM 构建和部署  
rdm-build:  
  stage: build  
  script:   # 构建脚本
    - cd packages/rdm  
    - pnpm install  
    - pnpm run build:$CI_COMMIT_REF_NAME  # 假设你有一个脚本来根据分支构建到不同的目录  
    - |  # 使用管道符来在单行中写多条命令,如果是主分支,将dist目录重命名为dist/prod    
      if [ "$CI_COMMIT_REF_NAME" == "main" ]; then  
        mv dist dist/prod   
      else  
        mv dist dist/test  
      fi  
  artifacts:  # 指定要保留的构建产物 
    paths:  
      - packages/rdm/dist/prod/  # 如果需要包含主分支的产出  
      - packages/rdm/dist/test/  # 如果需要包含非主分支的产出  
  
rdm-deploy-prod:  
  <<: *deploy_template  
  variables:  # 覆盖模板中的变量 
    TARGET_SERVER: "正式服-服务器 A 地址"  
    DEPLOY_PATH: "/rdm"   # 部署路径  
    DEPLOY_TYPE: "prod"   # 部署类型
  only:   # 仅当提交到prod分支时运行
    - prod  
  
rdm-deploy-test:  
  <<: *deploy_template  
  variables:  
    TARGET_SERVER: "测试服-服务器 B 地址"   
    DEPLOY_PATH: "/rdm"  
    DEPLOY_TYPE: "test"  
  except:  
    - main  


# RDM-OLD  
rdm-old-build:  
  stage: build  
  script:  
    - cd packages/rdm-old  
    - pnpm install  
    - pnpm run build:$CI_COMMIT_REF_NAME  # 假设你有一个脚本来根据分支构建到不同的目录  
    - |  # 使用管道符来在单行中写多条命令  
      if [ "$CI_COMMIT_REF_NAME" == "main" ]; then  
        mv dist dist/prod  
      else  
        mv dist dist/test  
      fi  
  artifacts:  
    paths:  
      - packages/rdm-old/dist/prod/  # 如果需要包含主分支的产出  
      - packages/rdm-old/dist/test/  # 如果需要包含非主分支的产出  
  
rdm-old-deploy-prod:  
  <<: *deploy_template  
  variables:  
    TARGET_SERVER: "正式服-服务器 A 地址"  
    DEPLOY_PATH: "/rdm-old"  
    DEPLOY_TYPE: "prod"  
  only:  
    - prod  
  
rdm-old-deploy-test:  
  <<: *deploy_template  
  variables:  
    TARGET_SERVER: "测试服-服务器 B 地址"  
    DEPLOY_PATH: "/rdm-old"  
    DEPLOY_TYPE: "test"  
  except:  
    - main  
  

# RDM-NEW  
rdm-new-build:  
  stage: build  
  script:  
    - cd packages/rdm-new  
    - pnpm install  
    - pnpm run build:$CI_COMMIT_REF_NAME  # 假设这个脚本会根据分支名称构建到不同的目录,但实际上它不会改变dist的目录名  
    - |  # 使用管道符来在单行中写多条命令  
      if [ "$CI_COMMIT_REF_NAME" == "main" ]; then  
        mv dist dist/prod  
      else  
        mv dist dist/test  
      fi  
  artifacts:  
    paths:  
      - packages/rdm-new/dist/prod/  # 如果需要包含主分支的产出  
      - packages/rdm-new/dist/test/  # 如果需要包含非主分支的产出  
  
rdm-new-deploy-prod:  
  <<: *deploy_template  
  variables:  
    TARGET_SERVER: "正式服-服务器 A 地址" 
    DEPLOY_PATH: "/rdm-new"  
    DEPLOY_TYPE: "prod"  
  only:  
    - prod 
  
rdm-new-deploy-test:  
  <<: *deploy_template  
  variables:  
    TARGET_SERVER: "测试服-服务器 B 地址"  
    DEPLOY_PATH: "/rdm-new"  
    DEPLOY_TYPE: "test"  
  except:  
    - main  

参考资料:

Tutorial: Create and run your first GitLab CI/CD pipeline | GitLab

🛫 前端自动化部署:借助Gitlab CI/CD实现 - 掘金 (juejin.cn)

前端的gitlab的ci初尝试 - 掘金 (juejin.cn)

花半天时间,轻松打造前端CI/CD工作流 - 掘金 (juejin.cn)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1993739.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL注入实例(sqli-labs/less-22)

0、初始页面 1、确定闭合字符 闭合字符为单引号双引号 2、爆库名 3、爆表名 4、爆列名 5、查询最终目标

初识redis:String类型

在Redis中的所有key都是字符串&#xff0c;而value的类型是存在差异的。本文介绍的就是value中的string类型。 首先要知道&#xff0c;Redis中的字符串&#xff0c;直接就是按照二进制数据的方式存储的&#xff0c;不会做任何的编码转换。也就是说&#xff0c;redis不仅仅可以…

JMeter——异步请求性能测试

前段时间任务要求要对一种异步请求做性能测试&#xff0c;异步请求步骤如下&#xff1a; step1: 发一个数据计算的请求&#xff0c;response里面返回一个jobId step2: 带上这个jobId&#xff0c;就可以实时查看这个请求返回的jobStatus, 如果jobStatus0, 则成功返回计算结果&…

29_反序列化漏洞、反序列化概念、反序列化原理、反序列化漏洞防御、序列化

概念 序列化和反序列化 序列化 将对象型转换成字符串的过程。 反序列化 将字符串还原成对象型的过程。 反序列化漏洞&#xff08;了解&#xff09; 便于传输和存储 接下来上代码进行测试&#xff0c;先搞个类&#xff0c; <?phpheader("content-type:text/html;…

基于SpringBoot+Vue的校园失物招领系统(带1w+文档)

基于SpringBootVue的校园失物招领系统(带1w文档) 基于SpringBootVue的校园失物招领系统(带1w文档) 本课题研发的校园失物招领系统管理系统&#xff0c;就是提供校园失物招领系统信息处理的解决方案&#xff0c;它可以短时间处理完信息&#xff0c;并且这些信息都有专门的存储设…

51单片机个人学习笔记16(红外遥控)

前言 本篇文章属于STC89C52单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 [1-1] 课程简介_哔哩…

Qt编程技巧小知识点(2)GPIB缓存区数据读取

文章目录 Qt编程技巧小知识点&#xff08;2&#xff09;GPIB缓存区数据读取小结 Qt编程技巧小知识点&#xff08;2&#xff09;GPIB缓存区数据读取 大端小端的问题&#xff0c;其主要表现如下例子&#xff1a; 例如&#xff1a;输入为QByteArray str "#14M\xB6q\xC1\n&qu…

ImageNet_2014数据集下载与解压

前言 最近在配OpenLongTailRecognition-OLTR代码用的ImageNet_2014&#xff0c;因为数据集较大的原因&#xff0c;导致下载和数据集配置一直被耽误&#xff0c;进度很满&#xff0c;故此记录&#xff0c;以背不时只用。 进入imageNet主页 注: 需要注册账号&#xff0c;教育邮箱…

【论文阅读】MobileNetV4 - Universal Models for the Mobile Ecosystem

文章目录 摘要一、介绍二、相关工作三、与硬件无关的帕累托效率四、通用倒置瓶颈五、移动MQA六、MNv4模型的设计6.1 为增强的体系结构改进NAS6.2 MNv4模型的优化 7. 结果7.1 ImageNet分类7.2 COCO目标检测 8. 强化蒸馏配方9. 结论 MobileNetV4 - 移动生态系统的通用模型 摘要 …

linux系统编程:(4)

1.系统时间的获取函数 1. time函数 功能: 获得1970年到现在的秒数 参数: t:存放秒数的空间首地址 返回值: 成功返回1970年到现在的秒数 失败返回-1 2.localtime 函数 功能: 将一个秒数转化成日历时间 参数: timep:保存秒数空间的地址 返回值: 成功…

Node.js异步编程

【图书介绍】《Node.jsMongoDBVue.js全栈开发实战》-CSDN博客 《Node.jsMongoDBVue.js全栈开发实战&#xff08;Web前端技术丛书&#xff09;》(邹琼俊)【摘要 书评 试读】- 京东图书 (jd.com) 本节主要介绍Node.js异步编程的相关内容。内容包括 同步API、异步API、同步API与…

拿捏!远程观影之详细操作教程

碎碎念 相信不少小伙伴是有收藏影片的&#xff0c;时不时会取出来进行观看。大多时候&#xff0c;我们都是在局域网中观影&#xff0c;局域网中是直连&#xff0c;所以可以一直流畅进行观影&#xff0c;但是有不少朋友是有远程观影需求的&#xff0c;那么怎么实现能随时在手机…

squidpy学习总结

下载安装 首先不要使用pip install squidpy[interactive] 安装&#xff0c;因为我在base环境里python版本是python3.11.5, 导致安装narapi包的时候出现问题&#xff0c;所以我选择的办法是 conda create -n sp_env python3.9.12 注意这个有个问题&#xff0c;我的mac为啥建立不…

【git】git与​TortoiseGit​下载教程

下载地址&#xff1a;https://git-scm.com/ 下载TortoiseGit 官网链接&#xff1a;https://tortoisegit.org/ 拉去代码错误&#xff1a; 找到在本地安装的 git 服务的根目录 -> Git -> usr -> bin 目录下选中 ssh.exe &#xff0c;再点击打开即可&#xff0c;如下图&a…

在Ubuntu上基于NDK(r21)交叉编译FFmpeg for Android

各软件版本号&#xff1a;VMware为17 Pro、FFmpeg版本号为4.3.8、NDK版本号为r21e、Ubuntu版本号为20.04 1.下载FFmpeg4.3.8并解压 2.下载NDK&#xff08;r21e&#xff09;并解压 https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64.zip 3.在ffmpeg-4.…

FastReport数据区横向排列展示

FastReport数据区横向排列展示 步骤1&#xff1a;设置数据区的Columns Editor属性 1、Count&#xff1a;2表示数据区里的控件将最多显示两列 2、AcrossThenDown&#xff1a;数据区里的控件将会被从做到右依次循环遍历 3、Width&#xff1a;9.25&#xff0c;因为我只设置了两列…

mmdebstrap:创建 Debian 系统 chroot 环境的利器 ️

文章目录 mmdebstrap 的一般性参数说明 &#x1f4dc;mmdebstrap 的常见用法示例 &#x1f308;使用 mmdebstrap 的注意事项 ⚠️ &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f388;欢迎踏入我的博客世界&#xff0c;能与您在此邂逅&#xff0c;真是缘分使然&am…

我的创新大赛经验分享:如何打磨优化项目

我的创新大赛经验分享&#xff1a;如何打磨优化项目 前言1. 强化创新性与独特性2. 深度市场调研与用户需求洞察3. 优化商业模式与财务规划4. 提升团队表现与协作效率5. 完善展示材料与演示技巧6. 模拟答辩与专家评审7. 关注细节与排除潜在问题结语 前言 在创新的浪潮中&#xf…

Vue前端服务加密后端服务解密--AES算法实现

在实际项目中考虑到用户数据的安全性&#xff0c;在用户登录时&#xff0c;前端需要对用户密码加密&#xff08;防止用户密码泄露&#xff09;&#xff0c;服务端收到登录请求时先对密码进行解密&#xff0c;然后再进行用户验证登操作。本文 AES ECB 模式来实现前端机密后端解密…

PLSQL导入导出ORACLE数据提示失败问题修改PLSQL配置

oracle中plsql导入提示无法导入问题 1.首先看下是否环境变量已经配置(具体配置看下面环境变量配置) 2.plsql数据导入中tools-->Preferences中配置如下框中的内容 3.设置 tnsnames.ora文件中看下是否设置有问题 4.PLSQL乱码问题 NLS_LANG SIMPLIFIED CHINESE_CHINA.ZHS16…