驾驭 Linux 云: JavaWeb 项目安全部署

目录

[1. 引言](#1. 引言)

[2. Linux 基础指令](#2. Linux 基础指令)

[2.1 ls 展示目录/文件](#2.1 ls 展示目录/文件)

[2.2 pwd 查看所在路径](#2.2 pwd 查看所在路径)

[2.3 mkdir 创建文件夹](#2.3 mkdir 创建文件夹)

[2.4 cd 切换路径](#2.4 cd 切换路径)

[2.5 touch 创建文件](#2.5 touch 创建文件)

[2.6 rm 删除文件](#2.6 rm 删除文件)

[2.6 rm -r/rf 删除文件夹](#2.6 rm -r/rf 删除文件夹)

[2.7 rz/sz 上传/下载文件](#2.7 rz/sz 上传/下载文件)

[2.7.1 rz 上传文件](#2.7.1 rz 上传文件)

[2.7.2 sz 下载文件](#2.7.2 sz 下载文件)

[2.8 mv 移动文件](#2.8 mv 移动文件)

[2.9 查看文件](#2.9 查看文件)

[2.9.1 cat](#2.9.1 cat)

[2.9.2 more](#2.9.2 more)

[2.9.3 less](#2.9.3 less)

[2.9.4 head](#2.9.4 head)

[2.9.5 tail](#2.9.5 tail)

[2.10 vim/vi 编辑文件](#2.10 vim/vi 编辑文件)

[2.11 grep 查找文件内容](#2.11 grep 查找文件内容)

[2.12 ps aux 查看运行进程](#2.12 ps aux 查看运行进程)

[2.12.1 管道(|)](#2.12.1 管道(|))

[2.13 netstat -anp 查看网络状态](#2.13 netstat -anp 查看网络状态)

[3. 搭建 Java 部署环境](#3. 搭建 Java 部署环境)

[3.1 apt](#3.1 apt)

[3.2 apt 常用命令](#3.2 apt 常用命令)

[3.3 安装 OpenJDK](#3.3 安装 OpenJDK)

[3.3.1 更新软件包](#3.3.1 更新软件包)

[3.3.2 查找/安装 JDK 软件包](#3.3.2 查找/安装 JDK 软件包)

[3.4 安装 MySQL](#3.4 安装 MySQL)

[4. Java 项目部署 Linux 云服务器](#4. Java 项目部署 Linux 云服务器)

[4.1 什么是部署](#4.1 什么是部署)

[4.2 环境配置](#4.2 环境配置)

[4.2.1 方法一](#4.2.1 方法一)

[4.2.2 方法二](#4.2.2 方法二)

[4.3 项目打包](#4.3 项目打包)

[4.4 为 Linux 服务器创建数据库表](#4.4 为 Linux 服务器创建数据库表)

[4.5 开放 8080 端口号](#4.5 开放 8080 端口号)

[4.5 上传 jar 包到服务器](#4.5 上传 jar 包到服务器)

[4.6 运行 jar 包](#4.6 运行 jar 包)

[4.6.1 nohup 后台运行程序](#4.6.1 nohup 后台运行程序)

[4.6.2 跟踪日志](#4.6.2 跟踪日志)

[4.7 观察错误日志](#4.7 观察错误日志)

[4.7.1 nohup.log 日志文件](#4.7.1 nohup.log 日志文件)

[4.7.2 > 重定向日志内容](#4.7.2 > 重定向日志内容)

[4.7.3 tail -f 追踪错误日志](#4.7.3 tail -f 追踪错误日志)

[4.7.3.1 tail 和 tail -f 的区别](#4.7.3.1 tail 和 tail -f 的区别)

[4.8 杀掉进程](#4.8 杀掉进程)

[4.8.1 ps -ef 查看当前运行进程](#4.8.1 ps -ef 查看当前运行进程)

[4.8.2 kill 杀掉进程](#4.8.2 kill 杀掉进程)

错误总结


1. 引言

本篇博客主要学习如何在 Linux 云服务器上部署 JavaWeb 项目, 以及一些基础 Linux 命令的使用.

2. Linux 基础指令

使用终端工具(这里使用的 XShell)连接 Linux 云服务器后, 就可以操作远程主机了.

为了完成了 JavaWeb 项目的部署, 我们需要学习简单的 Linux 指令.

2.1 ls 展示目录/文件

  • 语法: ls [选项] [目录或文件]
  • 功能: 列出当前目录下所有非隐藏文件和非隐藏目录

常用的选项如下:

  1. -a 列出目录下的所有文件, 包括以 . 开头的隐含文件。
  2. -d 将目录象文件一样显示,而不是显示其下的文件。如:ls-d指定目录
  3. -k 以k字节的形式表示文件的大小。ls-alk指定文件
  4. -l 列出文件的详细信息。
  5. -r 对目录反向排序。
  6. -t 以时间排序。
  7. -R 列出所有子目录下的文件(递归)

2.2 pwd 查看所在路径

使用 pwd 命令查看当前所在路径:

2.3 mkdir 创建文件夹

语法: mkdir 目录名

mkdir, 在当前目录下, 创建新目录.

注意, mkdir 命令只能创建单级目录, 无法创建多级目录:

如果要创建多级目录, 需要使用 mkdir -p:

2.4 cd 切换路径

语法: cd 目录

功能: 切换当前所在目录(改变工作路径)

cd 后也可以跟多级路径:

使用 cd .. 可以回退到上一级路径:

也可以使用 cd ~ 直接回退到根目录:

使用 cd - 返回最近访问的路径:

2.5 touch 创建文件

语法: touch 文件名

功能: 创建文件

2.6 rm 删除文件

语法: rm 文件

功能: 删除文件

2.6 rm -r/rf 删除文件夹

rm 命令只能用来删除文件, 不能用来删除文件夹:

rm -r 命令可以对文件夹进行递归式的删除(如果遇到被保护的文件, 会进行提示):

注意: 删除文件夹, 会把该文件夹下的所有文件和目录都进行删除.

除了 rm -r 外,rm -rf 也可以对目录进行删除(强制删除, 不会提示):

rm -r 和 rm -rf 的区别如下:

|------------|--------------------------------------------------------|------|
| 命令 | 描述 | 交互性 |
| rm -r | 递归删除目录及其内容,如果遇到只读文件或目录,或者没有删除权限的文件,会提示用户进行确认(y/n?) | 需要确认 |
| rm -rf | 递归地强制删除目录及其内容,不会提示确认,即使遇到受保护的文件或目录也会强制删除。 | 无需确认 |

注意: "rm -rf / " 是一个非常危险的操作, 会将操作系统中的所有文件进行删除!!

当然, rm -r 或 rm -rf 也可以删除文件.

2.7 rz/sz 上传/下载文件

  1. rz: 将 Windows 上的文件上传到 Linux 服务器中.
  2. sz: 将 Linux 服务器上的文件下载到 Windows 中.

使用 rz/sz 之前, 需要先下载这两个命令, 否则无法执行:

下载 rz/sz 命令:

复制代码
# 下载 rz/sz 命令
apt install lrzsz

2.7.1 rz 上传文件

下载完后, 上传文件有两种方式:

  1. 直接将文件拖到终端中:
  2. 使用 rz 命令手动选择文件:

注意: 文件上传后的位置是当前所在的目录下 .

2.7.2 sz 下载文件

sz, 即将 Linux 服务器中的文件下载到 Windows 中:

2.8 mv 移动文件

语法: mv 文件名 目标路径

功能: 将文件移动到目标路径

此外, mv 也可以改名.

2.9 查看文件

查看文件有多种方式, 我们只需掌握常见的几种命令即可:

  1. cat
  2. more
  3. less
  4. head
  5. tail

2.9.1 cat

cat 命令, 会一次性将文件中的内容全部展示出来:

2.9.2 more

more 命令, 使用 "懒加载" 的方式, 只展示当前屏幕大小的内容(可以说是一页一页的展示):

(展示的内容, 占文件全部内容的百分比)

如果想查看下面的内容, 回车即可. 如果想退出查看, ctr + c 即可.

此外, 如果想通过关键字查找内容, 输入 / + 关键字 即可(但无高亮提示)

2.9.3 less

less 命令查看文件内容, 也是懒加载来加载文件内容, 但是是以滑动滚轮的方式来加载新内容的.

退出 less 查看, 需要使用 :q 命令

常见的退出命令:

  1. ctr+c
  2. :q 正常退出
  3. :q! 强制退出
  4. exit

2.9.4 head

语法: head -n 文件

功能: 展示文件的前 n 行内容, 默认为前 10 行.(是文件的前 n 行, 而不是终端窗口的 n 行)

复制代码
# 展示文件前 10 行的内容
head -20 new.txt

2.9.5 tail

tail 和 head 的反过来的. 展示文件倒数前 n 行.

2.10 vim/vi 编辑文件

编辑文件的步骤如下:

  1. vim/vi 文件名 => 进入要编辑的文件
  2. i => 进入编辑模式
  3. 对文件进行编辑
  4. ESC 键 => 退出编辑模式
  5. 退出编辑页面, 回到终端窗口

其中, 退出编辑页面时, 有多种不同操作, 如下所示:

  1. :wq=>保存并退出(把修改/编辑的内容进行保存)
  2. :q!=>强制退出(不会保存修改的内容)
  3. :q=>退出(没有对文件进行任何修改,仅查看文件内容时的退出)
  4. :wq!=>强制退出并保存(他人也对该文件进行了修改并完成了保存, 该命令会强制覆盖他人修改的内容, 保存为你修改的内容)

详细流程如下:

2.11 grep 查找文件内容

在 Windows 中, 我们可以通过 Ctrl + F 定位文本文件中的内容, 在 Linux 中也是可以的.

语法: grep [参数]... [文件]...

功能: 在文件中查找指定的字符串(有高亮提示)

选项:

  • -n <行数> 显示的行数
  • -w 全字匹配. 要求整个单词都完全相同的结果才能匹配出来, 而而不仅仅是一个单词的一部分.
  • -r 递归查找. 可以搜索多级目录下的所有文件.
  • --color 高亮查找到的结果
  • --include 指定查找某些文件
  • --exclude 指定排除某些文件

使用 -n 演示:

2.12 ps aux 查看运行进程

ps aux 查找当前系统中, 运行的所有进程:

2.12.1 管道(|)

管道(|), 可以将两个命令连接起来, 将一个命令的输出, 作为另一个命令的输入.

ps aux 查看的是所有进程的详细信息, 展示在窗口中的内容会非常的多, 我们可以使用 ps aux + 管道(|) + grep 命令来查找指定的进程信息:

2.13 netstat -anp 查看网络状态

netstat -anp 也可以通过 管道 搭配 grep 使用, 查找指定 ip/端口号 网络状态:

复制代码
netstat -anp
netstat -anp | grep "进程名"
netstat -anp | grep "端⼝号"

3. 搭建 Java 部署环境

3.1 apt

apt(Advanced Packaging Tool), 是 Linux 软件包管理工具, 可以在 Linux 发行版(如: Ubuntu、Debian....)上对软件包进行安装更新删除等操作, 可以理解为 "应用市场".

3.2 apt 常用命令

注意: 大多数 apt 命令, 需要管理员(sudo)的身份才能运行.

切换 root 用户:

复制代码
sudo su 

查看所有软件包:

复制代码
sudo apt remove 软件包名称

# 查看所有软件包
apt list
# 对结果进行过滤
apt list | grep "xxx"

更新软件包数据库

复制代码
sudo apt-get update

安装软件包:

复制代码
sudo apt install 软件包名称

卸载软件包:

复制代码
sudo apt remove 软件包名称

sudo apt purge 软件包名称

卸载软件包时, apt remove 命令可能会有卸载残余(一些配置文件), apt purge 会将所有的配置文件都卸载掉.

3.3 安装 OpenJDK

要想把 Java 项目部署到服务器上, 毫无疑问需要两个东西:

  1. JDK
  2. 数据库

3.3.1 更新软件包

复制代码
sudo apt-get update

3.3.2 查找/安装 JDK 软件包

复制代码
# 查找 JDK 软件包
apt list | grep "jdk"

# 安装 JDK 软件包
sudo apt install openjdk-17-jdk

 # 验证是否安装成功(查看 JDK 版本)
java -version

如果想要卸载:

复制代码
# 检查安装的是哪个 OpenJDK
dpkg --list | grep -i jdk

# 移除 openjdk 包:
apt-get purge openjdk*

# 卸载 OpenJDK 相关包:
apt-get purge icedtea-* openjdk-*

# 检查所有 OpenJDK包是否都已卸载完毕:
dpkg --list | grep -i jdk

3.4 安装 MySQL

查找 MySQL 软件包:

复制代码
apt list | grep "mysql-server"

安装 MySQL 软件包:

复制代码
#安装 mysql
sudo apt install mysql-server

检查 MySQL 是否安装成功(查看 MySQL 状态):

复制代码
sudo systemctl status mysql

MySQL 默认的设置是不安全的, 我们需要将 MySQL 设置为强安全策略:

复制代码
# MySQL 安全设置
sudo mysql_secure_installation

安装过程中, 只有这个提示是输入 2, 表示选择强密码策略, 会强制用户设置符合特定复杂性要求的密码, 以提高数据库的安全性. 
Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 2(输入 2)

其他提示, 一路输入 y 即可.
  • 云服务器是直接暴露在公网上的, 这意味着它们更容易受到来自世界各地的攻击者的攻击.

  • 与内网环境相比, 公网环境的风险更高, 因为任何人都可以尝试连接到你的数据库服务器.

因此, 我们需要为数据库设置安全策略.

设置成功后, 若我们没有修改 MySQL 的默认密码, 输入 mysql 连接 mysql 服务:

复制代码
# 连接 MySQL 服务(修改密码前)
mysql

由于我们是在云服务器上启动 MySQL 服务的, 为避免他人攻击, 可以设置一个复杂的密码(并且由于我们在安全设置中, 选择了强密码策略, 因此 mysql 强制用户必须将密码设置为强类型的, 否则无法修改):

XML 复制代码
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY
'自定义强类型密码';

修改密码后, 后续再次连接 MySQL 服务时, 直接输入 mysql 就不能进入了, 需要以下命令, 并正确输入密码才可以进入:

复制代码
# 连接 MySQL 服务(修改密码后)
mysql -uroot -p

输入 exit 可退出 mysql 服务:


4. Java 项目部署 Linux 云服务器

4.1 什么是部署

我们需要先了解工作中常提到的 "环境":

  1. 开发环境: 我们开发人员写代码时用的机器
  2. 测试环境: 测试人员测试时用的机器
  3. 生产环境(线上环境): 最终项目发布时所使用的机器, 对稳定性要求很高(因此通常部署到 Linux 环境中)

将项目安装到生产环境, 就称为 "部署", 也称为 "上线".

部署是软件开发生命周期的最后一步, 一旦程序被部署到生产环境中, 就意味着这个程序可以被成千上万个用户所访问, 因此部署这一过程至关重要.

在实际工作中, 防止部署出错, 一般都是通过自动化部署工具来自动部署. 学习阶段, 我们通过手动部署来部署 javaweb 项目.

4.2 环境配置

将 Java Web 项目部署到服务器上时, 为了确保应用程序在不同环境中都能正确运行, 我们需要为不同平台配置不同的配置文件, 主要是因为不同环境(开发、测试、生产)的配置参数通常不同.

以之前的博客系统为例, 配置数据库连接时, 如果是在开发环境下, 配置的数据库用户名和密码需要是开发机中的数据库; 而如果将项目部署到服务器中时, 配置的用户名和密码需要是 Linux 服务器中那个数据库的用户名和密码.

因此, 我们需要提供两个不同的配置文件, 分别应对开发环境和生成环境下, 项目和数据库之间的连接.

注意: 给服务器配置数据库连接时, 配置 ip 和端口号依然需要为 127.0.0.1:3306, 因为当项目打包到服务器上运行时, 项目依然是在 "服务器本机" 上运行的.

不同的环境的配置文件, 有着不同的命名规范:

  • dev: 开发环境
  • test: 测试环境
  • prod: 生产环境

配置文件只有 application.yml 生效 , 其他配置文件是不生效的, 因此, 我们需要在 application.yml 中进行设置, 指定要执行的配置文件, 设置让 application-dev.yml 在开发环境中生效, 让 application-prod.yml 在生产环境中生效.

如何设置呢?

4.2.1 方法一

方法一, 手动在 application.yml 中执行哪个配置文件生效:

(active 后指定后缀即可)

4.2.2 方法二

方法一需要修改代码 来指定要生效的配置文件, 这样存在硬编码问题.

这里再介绍第二种 --- 通过 Maven 创建变量, 打包时, 动态指定哪个配置生效:

XML 复制代码
<!--    通过 Maven 中定义变量-->
<!--    变量1-->
    <profiles>
        <profile>
            <id>dev</id>
            <properties>
                <profile.name>dev</profile.name>
            </properties>
        </profile>
<!--        变量2-->
        <profile>
            <id>prod</id>
            <properties>
                <profile.name>prod</profile.name>
            </properties>
        </profile>
    </profiles>
复制代码
spring:
  profiles:
    active: @profile.name@ #变量名

注意:

  • 修改完 pom 文件后, 一定要加载 Maven!!
  • 在 Maven 框中勾选完后, 也一定要加载Maven!!

如果还是不行, 添加以下配置再试试:

XML 复制代码
<build>
     <resources>
          <resource>
              <directory>src/main/resources</directory>
                <!--开启过滤,用指定的参数替换directory下的文件中的参数-->>
              <filtering>true</filtering>
          </resource>
      </resources>
</build>

4.3 项目打包

4.4 为 Linux 服务器创建数据库表

要想让 jar 包中的项目能够在服务器跑起来, 我们需要在服务器中创建对应的数据库表.

4.5 开放 8080 端口号

基于之前网络部分的学习, 我们了解到, 公网 IP 地址就像你的住址, 告诉别人你的房子在哪里; 端口号就像你房子的门牌号, 告诉别人你想访问哪个房间(具体的某个服务).

如今, 我们通过云服务器已经有了公网 IP, 而对于端口号, 出于安全考虑, 云服务器提供商(阿里云、腾讯云、....)通常会在云服务器前面设置安全组或防火墙, 这些安全组/防火墙默认情况下会阻止所有入站流量, 只允许客户端访问特定的端口号.

因此, 我们需要开发 tomcat 的 8080 端口, 以便用户能够访问我们的项目:

(演示图是阿里云开放端口的流程, 其他云服务器大同小异)

4.5 上传 jar 包到服务器

这就用到上文所讲的, 如何在 Linux 上传文件的知识.

我们可以直接打开 Windows 中 jar 包所在路径, 直接将 jar 文件拖入 Linux 服务器中即可.

4.6 运行 jar 包

然后通过 java -jar 命令运行 jar 包即可.

复制代码
# 运行 jar 包
java -jar 文件名

运行 jar 包后, 我们的 Web 项目就跑起来了, 用户就可以访问了:

当然, 日志信息也会打印在 Linux 服务器中:

4.6.1 nohup 后台运行程序

但是, 此时有一个问题, 虽然现在我们的服务器启动了项目, 但是我们不能进行其他的命令操作了, 如果想要输入其他命令, 就需要 ctr+c, 而ctr+c 就会停掉项目:

因此, 正确运行项目的方式是使用 nohup 命令, 能够让项目在系统后台不挂断地持续运行, 即使退出终端/ctr+ c也不会终止.

使用 nohub 命令前, 需要先下载 lrzsz:

复制代码
apt-get install lrzsz

nohub 命名运行 jar 包 :

复制代码
 nohup java -jar blog-spring-0.0.1-SNAPSHOT.jar &

4.6.2 跟踪日志

此时, 项目已经在后台跑起来了. 如果想要查看日志, 使用 tail 命令:

复制代码
tail -f spring-blog.log 

注意: tail 是跟踪日志, 只会展示命令输入后产生的日志, 不会展示之前的日志.

在工作中, 我们 最常使用 tail + 管道 + grep 命令来跟踪 error 日志(这也是我们 java 程序员学习 Linux 的主要目的):

复制代码
# 展示新产生的日志中的 ERROR 日志
tail -f spring-blog.log | grep "ERROR"

grep "ERROR" 后, 窗口只会显示包含 "ERROR" 关键词的日志, 不会展示其他日志, 若想查看其他日志, 需要重写输入 tail 命令.


4.7 观察错误日志

我们学习 Linux 的主要目的之一, 就是查看错误日志.

4.7.1 nohup.log 日志文件

由于我们是使用 nohup 命令来运行项目的, 所以服务器会自动创建 nohup.out 文件来记录日志信息:

此外, 由于我们在项目中已经配置了日志文件(spring-blog.log), 并且没有在 nohup 命令中进行输出重定向, 那么日志信息会同时出现在 nohup.log(或 nohup.out)和项目配置的日志文件(spring-blog.log)中.

如果 nohub 启动项目时, 我们使用 > 将日志信息重定向到一个新文件, 那日志只会出现在这个新文件中, 而不会出现在 nohub.log 和项目本身配置的日志文件了:

在实际工作中,直接查看我们项目本身配置的日志文件(如 spring-blog.log)即可,不需要查看 nohup.log 或者额外使用>对日志进行重定向

4.7.2 > 重定向日志内容

> 命令, 可以将一个文件中的内容, 重定向到另一个文件中:

4.7.3 tail -f 追踪错误日志

当程序灰度部署到较少服务器上时, 我们要能够观察错误日志, 发现错误信息.

使用tail -f 命令追踪日志:

tail -f 文件名, 默认追踪所有日志的信息(默认从后 10 行开始追踪), 我们要将正常日志过滤掉, 只追踪错误日志即可:

复制代码
# 追踪带有 "Exception" 的异常日志
tail -f spring-blog.log | grep "Exception"

此外, 还可以 grep 后跟 -A/-B/-C 来展示所匹配日志的上下文, 帮助我们更好的定位错误原因:

  1. grep -A n => 展示匹配内容的后 n 行
  2. grep -B n => 展示匹配内容的前 n 行
  3. grep -C n => 展示匹配内容的前后 n 行

如下图所示, 展示异常信息及其后 10 行:

4.7.3.1 tail 和 tail -f 的区别

|----------|--------------------|---------------------------------------------------|
| 特征 | tail 文件名 | tail -f 文件名 |
| 读取内容 | 显示文件末尾的指定行数(默认 10) | 显示文件末尾的指定行数(默认 10) |
| 退出行为 | 显示完毕后立即退出 | 保持运行,持续监听文件更新,需要手动中断 |
| 跟踪更新 | 不跟踪文件更新 | 实时跟踪文件更新.每当文件有新的内容追加写入时, 会实时地将新增的内容显示在终端上 |
| 主要用途 | 一次性查看文件末尾内容 | 实时监控文件更新,特别是日志文件 |

4.8 杀掉进程

如果需要关闭运行的项目, 或者对项目重新进行部署, 我们需要先杀掉原先的项目, 让其停止占用端口号.

4.8.1 ps -ef 查看当前运行进程

复制代码
# 从当前运行的进程中筛选 Java 进程
ps -ef | grep java

除了使用上述的 ps -ef 命令, 也可以使用 ps aux 命令查看进程信息:

复制代码
# 从当前运行的进程中筛选 Java 进程
ps aux | grep java

4.8.2 kill 杀掉进程

使用 ps -ef 或者 ps aux 获取 Java 项目进程的 PID(进程 ID) 后, 就可以使用 kill 命令杀掉这个进程.

语法: kill 进程ID

此时, 我们的项目就停掉了.


错误总结

  1. 由于我给服务器中数据库配置的密码带了 '@', 虽然可以打 jar 包, 但是 jar 包无法在服务器运行, 后来将数据库密码使用引号包裹起来, 这个问题得以解决.
  2. 由于我没有在配置文件中没有给 MyBatis-plus 设置驼峰映射, 导致运行 jar 包时, 只展示 Spring banner, 到 MyBatis-plus 就报错. 后来添加驼峰映射, 这个问题得以解决.

END

相关推荐
liyongjun631636 分钟前
CentOS 下 Zookeeper 常用命令与完整命令列表
linux·服务器·zookeeper·centos
声声codeGrandMaster38 分钟前
Django之modelform使用
后端·python·django
一一Null39 分钟前
Android studio 动态布局
android·java·android studio
假女吖☌42 分钟前
Maven 编译指定模版
java·开发语言·maven
facaixxx20242 小时前
什么是巨型帧Jumbo Frames?云服务器开启巨型帧有什么用?
运维·服务器
体育分享_大眼3 小时前
从零搭建高并发体育直播网站:架构设计、核心技术与性能优化实战
java·性能优化·系统架构
老李不敲代码3 小时前
榕壹云无人共享系统:基于SpringBoot+MySQL+UniApp的物联网共享解决方案
spring boot·物联网·mysql·微信小程序·uni-app·软件需求
琢磨先生David4 小时前
Java 在人工智能领域的突围:从企业级架构到边缘计算的技术革新
java·人工智能·架构
巨可爱熊4 小时前
高并发内存池(定长内存池基础)
linux·运维·服务器·c++·算法
zkmall4 小时前
ZKmall开源商城静态资源管理:Nginx 配置与优化
运维·nginx·开源