云服务器初始化
【腾讯云】请务必使用此链接注册,否则无法享受优惠
https://cloud.tencent.***/act/cps/redirect?redirect=1079&cps_key=875015f9746044c254a9c6c36007262f&from=console
这个链接也有优惠,但是必须要学生认证且是只能是第一次购买云服务器:
https://cloud.tencent.***/act/campus
【快捷方式】如何创建远程桌面快捷方式教程:
https://mengwangyun.***/news/127.html
安装宝塔 linux 面板
防火墙开发端口
点击添加规则,开放宝塔 linux 端口 8888
登录宝塔面板
点击登录:
粘贴复制的命令并执行:
打开外网 ipv4 面板地址,复制账号秘密并登录:
激活依赖
激活后选择这套 LNMP 依赖,记得勾选 PHP:
如果在安装依赖时等了很久,或者安装的某一个依赖失败了,可以在服务器重置系统中,选择直接重装 linux 宝塔面板:
安装过程中,可以点击设置面板,修改默认账号、秘密:
查看安装进度:
部署规划
1、源码地址
https://github.***/liyupi/yu-picture
2、部署方案
为了提高效率,本项目前端和后端均使用宝塔面板进行部署,可以很方便地管理服务器。
涉及到具体的部署方式,前端要遵循 Vue 项目的部署模式,基于 Nginx 运行;后端可以直接利用宝塔的 Java 项目管理器运行 jar 包。
3、地址规划
前端:通过 Nginx 进行转发,访问地址为 http://{域名}。
后端:通过 Nginx 进行转发,访问地址为 http://{域名}/api。实际运行在 8123 端口。JDK 建议选择 17 版本!(caffeine 要求 JDK > 11)
- 为什么要用 Nginx 转发?
- 前端和后端域名一致,保证不会出现跨域问题。
Nginx:服务器 80 端口,默认已安装。
数据库:服务器 3306 端口,默认已安装。
Redis:服务器 6379 端口,需要手动安装。
4、注意事项
做好规划后,我们需要在腾讯云控制台的防火墙中开通需要外网访问的服务端口,比如 MySQL 和 Redis:
安装依赖
1、数据库
宝塔面板已经自动安装 MySQL 数据库,我们可以直接使用。
先为后端项目添加一个数据库。数据库名称和我们项目需要的数据库名称保持一致,注意用户名、密码和访问权限:
在宝塔中开放数据库端口号:
在 IDEA 中打开后端项目,通过数据库面板在本地检查连接是否正常:
配置数据源,执行脚本,初始化库表:
-- 创建数据库
create database if not exists yu_picture;
-- 切换库
use yu_picture;
-- 用户表
-- 用户表
create table if not exists user
(
id bigint auto_increment ***ment 'id' primary key,
userA***ount varchar(256) not null ***ment '账号',
userPassword varchar(512) not null ***ment '密码',
userName varchar(256) null ***ment '用户昵称',
userAvatar varchar(1024) null ***ment '用户头像',
userProfile varchar(512) null ***ment '用户简介',
userRole varchar(256) default 'user' not null ***ment '用户角色:user/admin',
editTime datetime default current_timestamp not null ***ment '编辑时间',
createTime datetime default current_timestamp not null ***ment '创建时间',
updateTime datetime default current_timestamp not null on update current_timestamp ***ment '更新时间',
isDelete tinyint default 0 not null ***ment '是否删除',
unique key uk_userA***ount (userA***ount),
index idx_userName (userName)
) ***ment '用户' collate = utf8mb4_unicode_ci;
-- 图片表
create table if not exists picture
(
id bigint auto_increment ***ment 'id' primary key,
url varchar(512) not null ***ment '图片 url',
name varchar(128) not null ***ment '图片名称',
introduction varchar(512) null ***ment '简介',
category varchar(64) null ***ment '分类',
tags varchar(512) null ***ment '标签(JSON 数组)',
picSize bigint null ***ment '图片体积',
picWidth int null ***ment '图片宽度',
picHeight int null ***ment '图片高度',
picScale double null ***ment '图片宽高比例',
picFormat varchar(32) null ***ment '图片格式',
userId bigint not null ***ment '创建用户 id',
createTime datetime default current_timestamp not null ***ment '创建时间',
editTime datetime default current_timestamp not null ***ment '编辑时间',
updateTime datetime default current_timestamp not null on update current_timestamp ***ment '更新时间',
isDelete tinyint default 0 not null ***ment '是否删除',
index idx_name (name), -- 提升基于图片名称的查询性能
index idx_introduction (introduction), -- 用于模糊搜索图片简介
index idx_category (category), -- 提升基于分类的查询性能
index idx_tags (tags), -- 提升基于标签的查询性能
index idx_userId (userId) -- 提升基于用户 ID 的查询性能
) ***ment '图片' collate = utf8mb4_unicode_ci;
alter table picture
-- 添加新列
add column reviewStatus INT default 0 not null ***ment '审核状态:0-待审核; 1-通过; 2-拒绝',
add column reviewMessage VARCHAR(512) null ***ment '审核信息',
add column reviewerId BIGINT null ***ment '审核人 ID',
add column reviewTime DATETIME null ***ment '审核时间';
-- 创建基于 reviewStatus 列的索引
alter table picture
-- 添加新列
add column thumbnailUrl varchar(512) null ***ment '缩略图 url';
-- 空间表
create table if not exists space
(
id bigint auto_increment ***ment 'id' primary key,
spaceName varchar(128) null ***ment '空间名称',
spaceLevel int default 0 null ***ment '空间级别:0-普通版 1-专业版 2-旗舰版',
maxSize bigint default 0 null ***ment '空间图片的最大总大小',
maxCount bigint default 0 null ***ment '空间图片的最大数量',
totalSize bigint default 0 null ***ment '当前空间下图片的总大小',
totalCount bigint default 0 null ***ment '当前空间下的图片数量',
userId bigint not null ***ment '创建用户 id',
createTime datetime default current_timestamp not null ***ment '创建时间',
editTime datetime default current_timestamp not null ***ment '编辑时间',
updateTime datetime default current_timestamp not null on update current_timestamp ***ment '更新时间',
isDelete tinyint default 0 not null ***ment '是否删除',
-- 索引设计
index idx_userId (userId), -- 提升基于用户的查询效率
index idx_spaceName (spaceName), -- 提升基于空间名称的查询效率
index idx_spaceLevel (spaceLevel) -- 提升按空间级别查询的效率
) ***ment '空间' collate = utf8mb4_unicode_ci;
-- 添加新列
alter table picture
add column spaceId bigint null ***ment '空间 id(为空表示公共空间)';
-- 创建索引
create index idx_spaceId on picture (spaceId);
alter table picture
add column pi***olor varchar(16) null ***ment '图片主色调';
ALTER TABLE space
ADD COLUMN spaceType int default 0 not null ***ment '空间类型:0-私有 1-团队';
CREATE INDEX idx_spaceType ON space (spaceType);
-- 空间成员表
create table if not exists space_user(
id bigint auto_increment ***ment 'id' primary key,
spaceId bigint not null ***ment '空间 id',
userId bigint not null ***ment '用户 id',
spaceRole varchar(128) default 'viewer' null ***ment '空间角色:viewer/editor/admin',
createTime datetime default CURRENT_TIMESTAMP not null ***ment '创建时间',
updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP ***ment '更新时间',
-- 索引设计
UNIQUE KEY uk_spaceId_userId (spaceId, userId), -- 唯一索引,用户在一个空间中只能有一个角色
INDEX idx_spaceId (spaceId), -- 提升按空间查询的性能
INDEX idx_userId (userId) -- 提升按用户查询的性能
) ***ment '空间用户关联' collate = utf8mb4_unicode_ci;
记得验证数据库表是否创建成功,如下图:
2、Redis
在宝塔面板的软件商店中,搜索并安装 Redis,版本选择默认的即可:
安装完成后,需要配置 Redis,开启远程访问并配置密码,否则我们自己的电脑是无法连接 Redis 的:
修改配置后,一定要重载配置才能生效:
进行如下配置后,记得保存配置:
最后,在 IDEA 数据库面板中验证本地能否连接远程 Redis:
如果 redis 状态异常,可以在宝塔面板重启 redis:
3、Java 环境
要部署 Java 项目,必须安装 JDK。在宝塔面板中,可以通过下图的方式快速安装指定版本的 JDK。此处我们先安装 JDK 17:
建议多安装几个版本,比如 JDK 8、11、17,需要用哪个版本的时候可以随时切换。
4、其他服务
比如 腾讯云 COS 对象存储、阿里云百炼 AI,可以去对应的官网开通。
如果不会开通的话,可以通过第4章教程开通 COS 对象存储,第 9 章教程开通阿里云百炼 AI。
注意,要给对象存储增加该服务器 IP(或者实际访问前端域名)的跨域配置,否则编辑图片时将无法正确加载图片。
接下来,我们分别进行后端和前端部署。
后端部署
1、修改配置
修改 application-prod 生产环境配置,包括数据库、Redis、对象存储、阿里云百炼 AI 的 key 等,替换为上述安装依赖时指定的配置(如用户名、密码)。
注意为了性能,还要关闭 MyBatis Plus 的日志;为了安全,要给 Knife4j 接口文档设置用户名和密码。
参考配置如下:
# 线上配置文件
server:
port: 8123
spring:
# 数据库配置
# todo 需替换配置
datasource:
driver-class-name: ***.mysql.cj.jdbc.Driver
url: jdbc:mysql://云服务器IP:3306/yu_picture
username: yu_picture_root
password: yu_picture_123456
# Redis 配置
# todo 需替换配置
redis:
database: 0
host: 101.34.40.20
port: 6379
timeout: 5000
password: yu_picture_123456
mybatis-plus:
configuration:
# 生产环境关闭日志
log-impl: ''
# 接口文档配置
knife4j:
basic:
enable: true
username: yu_picture_root
password: yu_picture_123456
# 对象存储配置
cos:
client:
host: xxx
secretId: xxx
secretKey: xxx
region: xxx
bucket: xxx
# 阿里云 AI 配置
aliYunAi:
apiKey: xxx
由于配置文件存在敏感信息,使用 git 提交代码时,忽视该配置文件的提交:
2、打包部署
首先更改 pom.xml 文件的打包配置,删除掉主类配置的 skip 配置,才能打包:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>***.yupi.yupicturebackend.YuPictureBackendApplication</mainClass>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
在 IDEA 中打开后端项目,忽略测试并打包:
双击 package 打包,打包成功,得到 jar 包文件:
找到 Jar 包对应的路径,复制路径,方便在面板上传 Jar 包:
上传 jar 包到服务器,此处为了方便,就放到 web 根目录:
然后添加 Java 项目:
在项目执行命令中,必须指定生产环境的配置!还可以根据需要调整内存:
项目启动命令中,指定生产环境配置:
/www/server/java/jdk-17.0.8/bin/java -jar -Xmx1024M -Xms256M /www/wwwroot/yu-picture-backend-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
点击确认后,忽略后面数据库密码的校验,可能是没识别到而已。
启动成功后,能够看到状态和端口占用如图:
如果发现启动失败,需要先观察日志,下图仅为一个示例:
但是,我们现在无法通过浏览器访问接口文档:http://云服务器 IP:8123/api/doc.html
这是因为我们的服务器防火墙没有放开 8123 端口。这里我们故意不放开,因为在之前的部署规划中,后端需要通过 Nginx 进行转发,从而解决跨域问题。
如果我们部署的 Jar 包部署后,总是莫名其妙中断,就一定要看看项目对应的日志,比如以下问题,需要重装 redis 并且重新过一遍设置 redis 的 IP 、密码的流程:
3、Nginx 转发
新建一个 Nginx 站点,域名填写当前服务器 IP 或者自己的域名,根目录随意填写即可(只要不包含中文):
如果访问的是后端接口(地址有 /api 前缀),则 Nginx 将请求转发到后端服务,对应配置代码如下:
location /api {
proxy_pass http://127.0.0.1:8123;
proxy_set_header Host $proxy_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
proxy_set_header Connection "";
}
但是,对于本项目,光有 HTTP 转发配置还不够!后端还需要提供 WebSocket 连接,所以也要对 WebSocket 进行转发,再给 Nginx 补充下列配置:
# 代理 WebSocket 连接 (专门用于 WebSocket 请求)
location /api/ws {
proxy_pass http://127.0.0.1:8123;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
proxy_read_timeout 86400s;
}
修改 Nginx 配置如图:
修改完后,就可以通过 80 端口(可以省略)访问到接口了。
之后,我们重新访问以下去掉端口号的接口文档地址:
登录之后什么也没有显示:
按 F12 排查问题:
一定要注释掉下列配置!否则访问接口文档时,静态资源的加载可能会出错。因为浏览器会从本地缓存加载资源,而不是动态请求资源。
再次访问只有 IP 没有端口号的地址,访问成功:
前端部署
前端部署可以参考 Vite 官方文档:https://***.vitejs.dev/guide/static-deploy.html
分为修改配置、打包部署和 Nginx 转发这 3 个步骤。
1、修改配置
线上的前端需要请求线上的后端接口,所以需要修改 request.ts 文件中的请求地址为线上:
// 区分开发和生产环境
const DEV_BASE_URL = "http://localhost:8123";
const PROD_BASE_URL = "http://云服务器IP";
// 创建 Axios 实例
const myAxios = axios.create({
baseURL: PROD_BASE_URL,
timeout: 10000,
withCredentials: true,
});
此外,由于本项目用到了 WebSocket,还要同步修改 pictureEditWebSocket.ts 文件中的 WebSocket 的连接地址:
const DEV_BASE_URL = "ws://localhost:8123";
const PROD_BASE_URL = "ws://云服务器IP";
const url = `${PROD_BASE_URL}/api/ws/picture/edit?pictureId=${this.pictureId}`
2、打包部署
1)刚刚下载好源码,先运行 dev 命令:
参考 Vite 官网,在 package.json 文件中定义 pure-build 命令:
{
"scripts": {
"dev": "vite",
"pure-build": "vite build",
"build": "run-p type-check \"build-only {@}\" --",
}
}
为什么明明已经有 build 命令了,我们还要自己定义 pure-build 命令呢?
因为脚手架内置的 build 命令会执行类型检查,如果项目代码中有任何类型不规范的地方,都会导致打包失败!
虽然可以自己一个个修复类型,但是太影响效率了,得不偿失,所以引入一个更干净的构建命令。
2)执行 pure-build 命令,执行打包构建。
注意,如果 Node.js 版本较低,会构建失败,这时可以到 官网 安装更新的版本,比如 v20.17.0 等长期支持版本。
构建成功后,可以得到用于部署的静态文件 dist 目录:
把 dist 目录下的所有文件上传到服务器上(可以新建一个 yu-picture-frontend 目录)。
3、Nginx 转发
一般来说,用户无法直接访问服务器上的文件,需要使用 Nginx 提供静态文件的访问能力。
修改已有站点的网站目录配置,指向前端文件根目录:
然后访问服务器地址(或者自己配置的域名),就能打开前端网站了:
但是经过验证,目前访问除了主页外的其他页面(比如 /add_picture),如果刷新页面,就会出现 404 错误。
这个问题是由于 Vue 是单页面应用(前端路由),打包后的文件只有 index.html,服务器上不存在对应的页面文件(比如 /add_picture.html),所以需要在 Nginx 配置转发。如果找不到某个页面文件,就加载主页 index.html 文件。
修改 Nginx 配置,补充下列代码:
location / {
try_files $uri $uri/index.html /index.html;
}
如图:
保存配置后,再次刷新页面,可以正常访问。
至此,智能协同云图库项目已经完成上线啦~~~
我们还需要对项目进行功能的测试,因为本次云图库项目煮波只做了后端,没有结合前端进行功能测试,所以项目出现了很多 bug,就不放出上线地址啦~~~
希望大家能通过这个项目掌握企业级项目的开发、优化和上线方法,得到全方面编程技能和程序员素养的提升。