KubeSphere 核心实战之四【在kubesphere平台上部署Ruoyi-cloud项目】(实操篇 4/4)

**《KubeSphere 核心实战系列》**

KubeSphere 核心实战之一(实操篇 1/4)

KubeSphere 核心实战之二(实操篇 2/4)

KubeSphere 核心实战之三(实操篇 3/4)

KubeSphere 核心实战之四(实操篇 4/4)

**《KubeSphere 核心实战系列》**

文章目录

    • 1、Rouyi-Cloud架构
    • 2、项目上云分析
    • 3、开始部署
      • 3.1、部署中间件
        • 3.1.1 部署mysql和redis
        • 3.1.2 mysql数据库迁移到云上mysql
        • 3.1.3 部署nacos
      • 3.2、部署ruoyi-cloud微服务模块前的准备
        • 3.2.1. 云上环境Dockerfile配置
        • 3.2.1. 微服务上云分析
        • 3.2.2. 制作微服务镜像并推送给个人阿里云镜像仓库
      • 3.3、部署ruoyi-cloud微服务模块上云
        • 3.3.1、部署规则
        • 3.3.2、ruoyi-visual-monitor微服务模块上云
        • 3.3.2、ruoyi-system微服务模块上云
        • 3.3.3、ruoyi-job微服务模块上云
        • 3.3.4、ruoyi-gen微服务模块上云
        • 3.3.5、ruoyi-gateway微服务模块上云
        • 3.3.5、ruoyi-file微服务模块上云
        • 3.3.6、ruoyi-auth微服务模块上云
        • 3.3.7、所有后端微服务和中间件服务总览
      • 3.4、部署ruoyi-cloud前端vue项目上云
        • 3.4.1、修改vue.config.js
        • 3.4.2、打包前端项目
        • 3.4.3、存放前端ruoyi-ui构建好的静态文件,用于nginx请求访问
        • 3.4.4、修改ngnix配置文件
        • 3.4.5、压缩上传到云服务器
        • 3.4.6、解压并制作镜像并推送到阿里云个人镜像仓库
        • 3.4.7、使用kubesphere平台部署ruoyi-cloud前端项目

1、Rouyi-Cloud架构

请添加图片描述

2、项目上云分析

将rouyi-cloud项目搬上云需要考虑的问题如下:

  • 1,项目中用到了多少中间件?中间件是有状态应用,有些中间件需要导入默认的数据后才能上云。

  • 2,ruoyi-cloud包含8个微服务子模块(带端口的模块对应一个微服务)

  - ruoyi-ui                  // 前端框架 [80]- ruoyi-gateway             // 网关模块 [8080]- ruoyi-auth                // 认证中心 [9200]- ruoyi-system              // 系统模块 [9201]- ruoyi-gen                 // 代码生成 [9202]- ruoyi-job                 // 定时任务 [9203]- ruoyi-file                // 文件服务 [9300]- ruoyi-visual-monitor      // 监控中心 [9100]

它们都是无状态的应用,自己写的微服务需要自己制作镜像(编写Dockerfile文件)。

  • 3,中间件和微服务上云以后,各个中间件和微服务之间的访问问题,涉及整个项目的网络拓扑模型;优先集群内网地址访问微服务中间件(使用内网ip或者内网域名)。

  • 4,每个微服务的配置如何分离(生产配置分离URL),生产环境与开发环境的配置分离。

请添加图片描述

  • 中间件:有状态、数据导入

  • 微服务:无状态、制作镜像

  • 网络:各种访问地址,各个微服务和中间件之间访问(通过集群内部网络进行)

  • 配置:生产配置分离、URL

每个微服务上云需要做的工作:

  • 1、每个微服务准备 bootstrap.properties,配置 nacos地址信息(默认使用本地链接),nacos配置中心中每个配置文件信息需要修改为上云后的mysql和redis链接地址。
  • 2、每个微服务准备Dockerfile,启动命令,指定线上nacos配置等。
  • 3、每个微服务制作自己镜像。

3、开始部署

3.1、部署中间件

根据ruoyi-cloud架构图分析得到,项目需要的中间件有三个,分别是:

  1. mysql(数据迁移:将若依的数据库迁移到云上的mysql中,共三个库)
  2. redis
  3. nacos(注册和配置中心)
3.1.1 部署mysql和redis

首先保证在kubesphere上已经部署好mysql和redis两个服务,具体部署流程参见我的上两篇博客:

  • redis部署:https://tigerhhzz.blog.csdn.net/article/details/135640662

  • mysql部署:https://tigerhhzz.blog.csdn.net/article/details/135623659

名称集群内访问地址集群外部访问地址
mysqlhis-mysql.his:3306192.168.162.31:30201
redishis-redis.his:6379192.168.162.31:30608
3.1.2 mysql数据库迁移到云上mysql

mysql数据库初始化导入,将ruoyi-cloud所需的三个数据库内容导入到部署好的mysql中;三个数据库如下:

  1. ry-cloud
  2. ry-config
  3. ry-seata

具体操作可以通过navicat工具中的数据传输进行数据库的迁移。

在这里插入图片描述

在这里插入图片描述

3.1.3 部署nacos

具体参见nacos的官方文档

https://nacos.io/docs/v2/guide/admin/cluster-mode-quick-start/
请添加图片描述

配置文件 application.properties
如果是集群配置nacos多一个配置文件:cluster.conf
挂载配置文件使用子路径进行挂载。

/home/nacos/conf/application.properties
/home/nacos/conf/cluster.conf

在这里插入图片描述

在kubesphere上创建nacos服务

  1. 首先创建nacos的配置
    请添加图片描述
    请添加图片描述
    使用子路径挂载nacose的两个配置文件:
    请添加图片描述
    上面配置文件别忘了修改mysql数据库的链接地址:his-mysql.his:3306 以及登录账号和密码。

  2. 创建nacos服务:

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

镜像名称:nacos/nacos-server:v2.1.0
nacos客户端下载地址:https://github.com/alibaba/nacos/releases/tag/2.0.3

请添加图片描述
这里补充一个bug:
因为nacos启动需要连接mysql数据库,当nacos服务启动了,然而mysql服务还没有准备就绪,此时会出现服务从nacos中读取配置文件失败的情况。

解决办法:使用探针,nacos服务中增加健康检查机制,定时向nacos容器组发请求来探究运行状况,如果状态是错误的,k8s就不断的重启服务,直到服务正常。

在这里插入图片描述

请添加图片描述

在这里插入图片描述

nacos数据没有挂载的,都存在mysql数据库;

创建一个外网能访问的nacos服务,以node方式访问,暴露外网端口
请添加图片描述
游览器访问nacos: 192.168.162.31:30986请添加图片描述
至此,我们部署完成nacos,redis和mysql 三个中间件服务。

接下来我们开始部署rouyi-cloud项目的微服务模块。

3.2、部署ruoyi-cloud微服务模块前的准备

根据ruoyi-cloud架构图分析得到:
首先是前端vue项目模块,用来用户发送请求到网关服务;网关模块接受到前端的请求后分发给各个微服务模块。

在这里插入图片描述

微服务部署
请添加图片描述

3.2.1. 云上环境Dockerfile配置
  1. nacos中创建prod命名空间:
    在这里插入图片描述

  2. 克隆dev环境中配置到prod命名空间中
    在这里插入图片描述

  3. Dockerfile文件

FROM openjdk:8-jdk
LABEL maintainer=tigerhhzz#docker run -e PARAMS="--server.port 9090"
ENV PARAMS="--server.port=8080 --spring.profiles.active=prod --spring.cloud.nacos.discovery.server-addr=his-nacos.his:8848 --spring.cloud.nacos.config.server-addr=his-nacos.his:8848 --spring.cloud.nacos.config.namespace=prod --spring.cloud.nacos.config.file-extension=yml"
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezoneCOPY target/*.jar /app.jar
EXPOSE 8080#
ENTRYPOINT ["/bin/sh","-c","java -Dfile.encoding=utf8 -Djava.security.egd=file:/dev/./urandom -jar app.jar ${PARAMS}"]

启动镜像时,加一些额外的参数,每个微服务启动后对应一个pod,每个pod有不同的ip,但是端口都是8080,这样每个pod的访问地址就是唯一的。

规则:

1、容器默认以8080端口启动
2、时间为CST
3、环境变量 PARAMS 可以动态指定配置文件中任意的值,默认激活的是开发dev环境,去nacos配置中心中找xxxxx-dev.yml配置文件,应用上云打包镜像启动会自动激活生产环境pro,然后去nacos配置中心中找xxxxx-prod.yml配置文件。
4、nacos集群内地址为 his-nacos.his:8848   
5、微服务默认启动加载 nacos中  服务名-激活的环境.yml 文件,所以线上的配置可以全部写在nacos中。
3.2.1. 微服务上云分析

请添加图片描述
idea中使用maven打包jar包。
在这里插入图片描述
在这里插入图片描述
所用微服务模块打包成功。

编辑整理各个模块的jar和Dockerfile文件(每个微服务模块制作镜像的准备工作)
在这里插入图片描述
上传Dockerfile-images-ry整个文件夹到服务器(任何一个节点)
在这里插入图片描述

3.2.2. 制作微服务镜像并推送给个人阿里云镜像仓库

在这里插入图片描述

##打包镜像命令
docker build -t ruoyi-auth:v1.0  .##查看镜像
docker images|grep ruoyi

在这里插入图片描述
在这里插入图片描述

创建阿里云个人镜像仓库

开通阿里云“容器镜像服务(个人版)

阿里云镜像服务参考官网地址:https://cr.console.aliyun.com/cn-hangzhou/instance/repositories

首先创建一个命名空间,默认仓库类型设置为公开

在这里插入图片描述
然后,在自己的命名空间下,创建一个镜像仓库:
在这里插入图片描述
最后,进行镜像推送

##登录阿里云Docker Registry
docker login --username=hehu****@126.com registry.cn-hangzhou.aliyuncs.com##将镜像推送到Registry
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi:[镜像版本号]
docker push registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi:[镜像版本号]

在这里插入图片描述

把所有微服务镜像推送到个人阿里云镜像仓库。

docker push registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-auth:v1.0
docker push registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-file:v1.0
docker push registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-gateway:v1.0
docker push registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-gen:v1.0
docker push registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-job:v1.0
docker push registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-system:v1.0
docker push registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-visual-monitor:v1.0

在这里插入图片描述

思考两个问题:

  1. 手动一个个制作镜像,很费力费时,有没有一个自动化制作镜像流程?
  2. 这是使用了阿里云个人镜像仓库,有没有自己搭建公司仓库?一般开发中,搭建公司的habor私有仓库;专门存放项目镜像。

3.3、部署ruoyi-cloud微服务模块上云

ruoyi-cloud所用镜像都已经推送到个人阿里云镜像仓库:

3.3.1、部署规则

● 应用一启动会从云上nacos获取到 "应用名-激活的环境标识.yml"的配置文件

● 每次部署应用的时候,需要提前修改nacos线上配置,确认好每个中间件的连接地址是否正确

● 云上nacos配置文件中的中间件例如redis、mysql等链接地址一定是集群内的访问地址

在这里插入图片描述

在这里插入图片描述

3.3.2、ruoyi-visual-monitor微服务模块上云

整个操作在kubesphere云平台进行

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
查看容器运行日志:
在这里插入图片描述

监控模块启动成功!!!

3.3.2、ruoyi-system微服务模块上云

阿里云镜像名称为:registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-system:v1.0
过程同3.3.1一样。

3.3.3、ruoyi-job微服务模块上云

阿里云镜像名称为:registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-job:v1.0
过程同3.3.1一样。

3.3.4、ruoyi-gen微服务模块上云

阿里云镜像名称为:registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-gen:v1.0
过程同3.3.1一样。

3.3.5、ruoyi-gateway微服务模块上云

阿里云镜像名称为:registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-gateway:v1.0
过程同3.3.1一样。

3.3.5、ruoyi-file微服务模块上云

阿里云镜像名称为:registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-file:v1.0
过程同3.3.1一样。

3.3.6、ruoyi-auth微服务模块上云

阿里云镜像名称为:registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-auth:v1.0
过程同3.3.1一样。

3.3.7、所有后端微服务和中间件服务总览

在这里插入图片描述
工作负载一览:
在这里插入图片描述
在这里插入图片描述

3.4、部署ruoyi-cloud前端vue项目上云

ruoyi-cloud前端是vue项目,端口是80
打包方式:其实就是ngnix镜像,将前端打包的文件夹放到ngnix指定文件夹下。

其实就是运行package.json文件中的脚本build:prod
在这里插入图片描述

3.4.1、修改vue.config.js

修改的内容是:
在这里插入图片描述
在这里插入图片描述

http://ruoyi-gateway.his:8080
3.4.2、打包前端项目

打包命令:

# 构建生产环境
npm run build:prod

在这里插入图片描述

3.4.3、存放前端ruoyi-ui构建好的静态文件,用于nginx请求访问

打包完毕后,会生成一个dist文件,然后将dist文件夹中的内容拷贝到如图下的位置中:

在这里插入图片描述

存放前端ruoyi-ui构建好的静态文件,用于nginx请求访问。

3.4.4、修改ngnix配置文件

在这里插入图片描述
修改后的 nginx.conf文件如下

worker_processes  1;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;sendfile        on;keepalive_timeout  65;server {listen       80;server_name  _;location / {root   /home/ruoyi/projects/ruoyi-ui;try_files $uri $uri/ /index.html;index  index.html index.htm;}location /prod-api/{proxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://ruoyi-gateway.his:8080/;}# 避免actuator暴露if ($request_uri ~ "/actuator") {return 403;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}
}
3.4.5、压缩上传到云服务器

压缩上传到集群内任意节点机子上。
在这里插入图片描述

3.4.6、解压并制作镜像并推送到阿里云个人镜像仓库

Dockerfile文件内容:

# 基础镜像
FROM nginx
# author
MAINTAINER ruoyi# 挂载目录
VOLUME /home/ruoyi/projects/ruoyi-ui
# 创建目录
RUN mkdir -p /home/ruoyi/projects/ruoyi-ui
# 指定路径
WORKDIR /home/ruoyi/projects/ruoyi-ui
# 复制conf文件到路径
COPY ./conf/nginx.conf /etc/nginx/nginx.conf
# 复制html文件到路径
COPY ./html/dist /home/ruoyi/projects/ruoyi-ui

制作ngnix镜像:

docker build -t registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-ui:v1.0 -f dockerfile .

在这里插入图片描述
镜像制作成功:
在这里插入图片描述

推送到阿里云个人镜像仓库

docker push registry.cn-hangzhou.aliyuncs.com/tiger-ruoyi/ruoyi-ui:v1.0
3.4.7、使用kubesphere平台部署ruoyi-cloud前端项目

创建无状态服务
需要注意的时候,前端项目云部署暴露外网访问地址nodeport。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

前端项目启动成功:
在这里插入图片描述

如果内存不够,(启动无顺序限制)

 Auth服务和Gateway服务必须启动system服务如果你想访问后台就启动job和gen服务这两个一个是定时任务一个是代码生成 如果你有用得到就启动 反则不需要启动

在这里插入图片描述
在这里插入图片描述
前端项目启动成功!!至此所有服务都部署完成!!!

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

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

相关文章

前端颜料盘??

前端颜料盘&#xff1f;&#xff1f; 一、原生颜料盘 <input type"color" placeholder"选择颜色">二、第三方开源库 Pickr&#xff1a; GitHub: https://github.com/Simonwep/pickr官方网站: https://simonwep.github.io/pickr/Pickr 是一个轻量级…

20240130 大模型快讯

//社区生态// 讯飞星火大模型v3.5发布。讯飞发布了完全基于全国产算力平台“飞星一号”训练的星火大模型v3.5&#xff0c;同时开源深度适配国产算了的iFlyTekSpark-13B大模型。 Code Llama 70B大模型发布。Meta发布并开源了基于Llama 2的大模型Code Llama 70B&#xff0c;在Hu…

产品说明书怎么做?有模板吗?

产品说明书是一种重要的工具&#xff0c;它向消费者提供有关产品的详细信息和使用指南。一个好的产品说明书不仅可以帮助消费者正确地使用产品&#xff0c;还可以增加产品的销售量和用户满意度。那么&#xff0c;如何制作一份优秀的产品说明书呢&#xff1f;是否有现成的模板可…

ubantu操作hbase

到firefox中按照网站找以下文件进行下载 新建一个窗口启动节点 下载完成则回到下载目录 如果下载慢也可以将文件放在share中&#xff0c;然后拷贝到当前目录 进入到root 然后回到hadoop 解压到/usr/local 进入到local&#xff0c;将hbase改名 修改权限 配置环境变量 执行 回到h…

【小白学unity】上下左右移动+跳跃

1. 找到一个棒棒糖图片&#xff0c;拖入到unity中。 2. 将棒棒糖拖入到场景中&#xff0c;重命名为lolipop。 3. 给lolipop添加一个Rigidbody2D组件。 4. 创建一个C#脚本LolipopController.cs&#xff0c;并将其添加到lolipop游戏对象上。 5. 运行游戏, 棒棒糖由于Rigidbod…

专业120+总分400+宁波大学912信号与系统考研经验电子信息通信集成电路光电

今年考研顺利上岸&#xff0c;专业课912信号与系统120&#xff0c;总分400&#xff0c;被宁波大学录取&#xff0c;回望这一年的复习有过迷茫和犹豫&#xff0c;也有过坚持和坚强&#xff0c;总结一下自己的复习得失&#xff0c;希望对大家复习有所帮助。专业课&#xff1a; 前…

何为蓝海项目?抖音老隋分享的temu项目算吗?

在当今快速发展的商业环境中&#xff0c;蓝海项目成为了人们关注的焦点。那么&#xff0c;究竟什么是蓝海项目?抖音老隋分享的temu项目又是否算得上一个蓝海项目呢?本文将就此进行探讨。 首先&#xff0c;让我们明确什么是蓝海项目 蓝海项目通常指的是那些市场潜力巨大、竞争…

转盘寿司 - 华为OD统一考试

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 寿司店周年庆&#xff0c;正在举办优惠活动回馈新老用户。 寿司转盘上总共有 n 盘寿司&#xff0c; prices[i] 是第 i 盘寿司的价格。 如果客户选择了第 i 盘寿…

pytorch 优化训练显存方式

转载自&#xff08;侵删&#xff09;&#xff1a; https://www.cnblogs.com/chentiao/p/17901639.html 1. 显存都用在哪儿了&#xff1f; 一般在训练神经网络时&#xff0c;显存主要被网络模型和中间变量占用。 网络模型中的卷积层&#xff0c;全连接层和标准化层等的参数占…

R语言【taxlist】——subset():取taxlist对象的子集

Package taxlist version 0.2.4 Description taxlist对象的子集将通过逻辑操作或模式匹配来完成。子集可以引用包含在插槽taxonNames、taxonRelations或taxonTraits中的信息。 Usage ## S4 method for signature taxlist subset(x,subset,slot "names",keep_child…

【游戏服务器部署】幻兽帕鲁服务器一键部署保姆级教程,游戏私服还是自己搭建的香

在帕鲁的世界&#xff0c;你可以选择与神奇的生物「帕鲁」一同享受悠闲的生活&#xff0c;也可以投身于与偷猎者进行生死搏斗的冒险。帕鲁可以进行战斗、繁殖、协助你做农活&#xff0c;也可以为你在工厂工作。你也可以将它们进行售卖&#xff0c;或肢解后食用。—幻兽帕鲁 想要…

ThinkPHP5.0.0~5.0.23反序列化利用链分析

本次测试环境仍然是ThinkPHP v5.0.22版本&#xff0c;我们将分析其中存在的一条序列化链。 一道CTF题 这次以一道CTF题作为此次漏洞研究的开头。题中涉及PHP的死亡绕过技巧&#xff0c;是真实环境中存在的情况。 $payload; $filename$payload.468bc8d30505000a2d7d24702b2cda…

春季选品策略:如何在Shopee平台上脱颖而出

在Shopee平台上进行春季选品时&#xff0c;卖家需要制定有效的策略来吸引消费者的注意并提高销售业绩。本文将介绍一些关键的选品策略&#xff0c;帮助卖家在春季市场中脱颖而出。 先给大家推荐一款shopee知虾数据运营工具知虾免费体验地址&#xff08;复制浏览器打开&#xf…

MyBatis 源码系列:MyBatis 解析配置文件、二级缓存、SQL

文章目录 解析全局配置文件二级缓存解析解析二级缓存缓存中的调用过程缓存中使用的设计模式 解析SQL 解析全局配置文件 启动流程分析 String resource "mybatis-config.xml"; //将XML配置文件构建为Configuration配置类 reader Resources.getResourceAsReader(re…

探索ESP32 C++ OOP开发:与传统面向过程编程的比较

探索ESP32 OOP开发&#xff1a;与传统面向过程编程的比较 在嵌入式系统开发中&#xff0c;ESP32是一个强大的平台&#xff0c;可以应用于各种项目和应用场景。在编写ESP32代码时&#xff0c;我们可以选择使用面向对象编程&#xff08;OOP&#xff09;的方法&#xff0c;将代码…

数据结构—栈实现前缀表达式的计算

前缀表达式计算 过程分析 中缀表达式&#xff1a;&#xff08;1 5&#xff09;*3 > 前缀表达式&#xff1a;*153 &#xff08;可参考这篇文章&#xff1a;中缀转前缀&#xff09; 第一步&#xff1a;从右至左扫描前缀表达式&#xff08;已存放在字符数组中&#xff09;&a…

termux 玩法(一)

termux基础 termux基础玩法推荐国光写的手册&#xff1a;Termux 高级终端安装使用配置教程 | 国光 (sqlsec.com) termux安装 个人使用F-Droid安装的termux&#xff1a;Termux | F-Droid - Free and Open Source Android App Repository 基础知识 这些基础知识简单了解一下…

自定义模块加载(Python)

加载自定义模块&#xff0c;系统抛出“找不到文件”异常提示信息。 (笔记模板由python脚本于2024年01月28日 12:50:00创建&#xff0c;本篇笔记适合初通Python的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免…

LeetCode316. Remove Duplicate Letters——单调栈

文章目录 一、题目二、题解 一、题目 Given a string s, remove duplicate letters so that every letter appears once and only once. You must make sure your result is the smallest in lexicographical order among all possible results. Example 1: Input: s “bca…

盲人程序员是怎么编程的?闭眼编程

解决 读代码&#xff0c;读键盘变成听。 盲人程序员可以借助屏幕阅读器来使用计算机&#xff0c;绝大多数编程工具也可以正常访问&#xff0c;所以&#xff0c;盲人掌握编程语言是没有问题的。 具体的工作流程如下&#xff1a; 使用屏幕阅读器来“阅读”屏幕上的文本和代码。…