Reader Dev
在之前学习flutter过程中,经常查阅Dart pub中的packages,便想到利用相同的形式做一个分享书籍的Web应用,无须注册,可以进行匿名的发布、修改润色他人分享的推书卡片,当然也可以进行删除。目前只开发了增删改查的工作,打星、评论的功能也会后续增加。
一、开发过程
1.1 开发技术
使用了前后端分离技术,前端采用Vue3框架、后端采用SpringBoot2。
UI框架:TailwindCSS、ElementPlus
==TailwindCss==相比Boostrap更具自定义性,更能理解每一步做了什么,比纯css更方便。
1.2 项目部署
利用腾讯云学生云服务器,学习了linux + docker的部署方式。
整个项目部署在三个docker容器中,分别对应着前端、后端和数据库。
1.3 在学习过程中使用的参考资料
二、项目过程中的问题解决
2.1 前端方面
-
vue 组件间相互通信问题
项目过程中的例子:
1、父组件调用子组件函数
在项目中存在父组件AddForm.vue 和 UploadImage.vue 两个组件。
//子组件UploadImage.vue中 <el-upload ref="upload">...<el-upload> //父组件AddForm.vue中 <upload-image @onLoadImage="getImageUrl" ref="upload"></upload-image> //表单提交后调用子组件中的clearImage()清除图片 this.$refs.upload.clearImage();
ref特性就是为元素或子组件赋予一个ID引用, 父组件中通过this.$refs.refName来访问元素或子组件的实例
2、子组件向父组件传值
子组件通过 emit 传送
父组件使用 v-on 来绑定接收
//子组件中 handleSuccess(response) { this.url = response //传递上传后返回的图片的链接地址 this.$emit("onLoadImage", this.url); this.$message.warning('图片上传成功') } //父组件中 <upload-image @onLoadImage="getImageUrl" ref="upload" /> getImageUrl(url) { console.log("getImageUrl" + url); this.form.cover = url; },
-
axio全局设置
在 main.js 中加入如下代码
import axios from 'axios' app.config.globalProperties.$axios = axios axios.defaults.baseURL = 'http://服务器公网地址/api'
-
vue cli 打包后页面空白,检查元素出现:Failed to load resource: net::ERR_FILE_NOT_FOUND 问题
在根目录创建vue.config.js并加入如下代码
module.exports = { //打包路径 publicPath: './' }
-
书籍推荐中的概要在html中显示时无法换行和空格问题
使用 ==pre== 标签
该标签可定义预格式化的文本,被包围在 pre 元素中的文本通常会保留空格和换行符,并且文本会呈现为等宽字体。
2.2 后端方面
- 如何上传图片至服务器
ElementPlus中在
<el-upload
ref="upload"
action="http://ip:post/api/covers"
:on-preview="handlePreview"
:on-remove="handleRemove"
:on-success="handleSuccess"
:before-upload="beforImageUpload"
:file-list="fileList"
list-type="picture"
>
给上传的文件重命名以日期时间为前缀放置在/home/ubuntu/readerdev/imgs文件夹下,并返回给前端url地址。此时页面可以响应显示刚才上传的图片成功。
@CrossOrigin
@PostMapping("api/covers")
public String returnUploadCoverUrl(MultipartFile file) {
String fileName = file.getOriginalFilename();
String destFolder = "/home/ubuntu/readerdev/imgs";
assert fileName != null;
String suffixName = fileName.substring(fileName.lastIndexOf("."));
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmSS");
Random random = new Random();
String tempName = sdf.format(new Date()) + random.nextInt(100) + suffixName;
File tempFile = new File(destFolder, tempName);
if (!tempFile.getParentFile().exists()) {
tempFile.mkdirs();
}
try {
file.transferTo(tempFile);
String url = "http://ip:port/api/file/" + tempFile.getName();
return url;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
2.3 项目部署问题
2.3.1 nginx.conf配置方案
开启了gzip压缩,同时需要在前端项目中配置gzip压缩。
# 开启gzip
gzip on;
# 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;
# gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
gzip_comp_level 2;
# 进行压缩的文件类型。javascript有多种形式,后面的图片压缩不需要的可以自行删除
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
# 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
# 设置压缩所需要的缓冲区大小
gzip_buffers 4 16k;
server {
listen 80;
server_name localhost;
#charset koi8-r;
access_log /var/log/nginx/host.access.log main;
error_log /var/log/nginx/error.log error;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
2.3.2 docker部署nginx项目
写了一个shell文件来简化前端vue项目修改后的部署。
sudo docker stop reader_front
sudo docker container prune
sudo docker image rm mnginx
sudo docker build -t mnginx .
sudo docker run --name reader_front -p 8080:80 -d mnginx
sudo docker ps -a
2.3.3 docker部署springboot2项目
注释如下:
//将转储的sql文件复制到容器文件中,注意不是复制到文件夹中
sudo docker cp /../book.sql mymysql:/home/tmp/book.sql
//登录容器 mysql -uroot -pyzsby123 为同时登录mysql
docker exec -it mymysql(容器名) mysql -uroot -pyzsby123
//使用数据库名,如未出创建需先创建
use readerdev;
//导入执行sql文件
source /home/tmp/book.sql;
//制作镜像 (该目录包含jar和dockfile)
docker build -t readerdev .
//运行镜像
sudo docker run --link mymysql:mymysql --name=readerdev -p 8443:8443 -di readerdev
//跨容器通信、与宿主机映射
//--link 容器名:别名 mymysql:mymysql 容器间通信
//-v /home/ubuntu/readerdev/imgs:/home/ubuntu/readerdev/imgs 与宿主机绝对路径映射
//-p 8443:8443 与宿主机端口映射
//-d -detach 在后台运行
sudo docker run --link mymysql:mymysql -v /home/ubuntu/readerdev/imgs:/home/ubuntu/readerdev/imgs --name=readerdev -p 8443:8443 -di readerdev
三、项目总结
暂时没有绑定域名,此时可以通过访问http://ip:port/进行访问。
通过本次的结业作业,大概了解了前后端分离项目开发部署的流程,也是我的第一个Web项目。开发时也踩过很多坑,比如说springboot中的上传路径问题,vue组件通信问题、Dockerfile、nginx配置问题和vue项目打包优化等。但也收获了许多,如在vue项目打包时采用cdn的方式大大减小了项目体积,浏览速度加快。
但同时也存在了很多不足,比如选择了 optional api 而没有采用vue3 推出的 composition api的方式以及代码逻辑混乱、可复用性差等问题,后来在修改一些组件时非常耗时。
希望下一次的web项目能在此基础上有所提高!😆