开端

tremblingboy 又来了,难道是因为刚建博客所以这么勤快更新博文吗?并不是的。纯属是因为,最近我人生中的第一个项目写完了,这是一个历经 6 个多月,9000 多行代码的前后端分离项目。之前尝试过将项目部署到服务器上,踩了不少坑,出了不少 bug, 问了不少人,最后都没有部署成功。很多个晚上,我辗转反侧,思考为什么不能成功部署,一大早起来饭也不吃就又开始了部署。

失败过,绝望过,就在今天中午,它突然成了!激动的心,颤抖的手,指向把这一伟大的事儿给记录下来,方便下次部署项目,也算是给其他人一个方案。我相信项目部署这块并不是谁都能一次成功的,特别是像我这样 Linux 和服务器方面基础比较薄弱的人,更是会遇到不少的问题。那废话不多说了,开始准备吧!

软硬件基础

前端

Node.js (运行环境)

Vue.js (基本框架)

NPM (包管理工具)

后端

JavaJDK 中内置 JVM 运行环境)

Spring (基本框架)

Spring MVC (框架)

Spring Boot (自动化框架)

MybatisSQL框架)

Maven (包管理工具)

其他

IDEA (编译器)

Postman (接口测试工具)

Putty (远程登录工具)

阿里云服务器

域名 (已备案)

宝塔面板 (推荐使用)

劝退准备阶段

OK,如果大家的基础和我差不多,前端是用 Vue 框架在写,那就符合一大半了。如果后端也是 SSM ,那这篇教程你就可以点赞投币加收藏一键三连了。不过后端用其他问题也不是很大,比如老一点的 SSH 等等。只要你不用 Jsp 写,咱们都是朋友。目前是这样的,我们都已经完成了前后端程序的编写,并且你已经可以通过在本地分开启动前后端的程序实现浏览器本地 IP 的访问和接口的调用。这样就可以了,线上的部署只要避开一些容易踩的坑就行,后面我都会讲到。

实操

准备好了之后,我们开始一步一步部署项目。

服务器准备

建网站

首先咱得有个网站才能让别人访问是不,关于宝塔面板安装等可以见我的第一篇文章

->[购买学生服务器、备案域名、搭建博客菜鸟级教程]

实在不行咱先把先前搭博客的网站清空用来部署项目,不过还是建议大家多买一个域名,早点备案以备不时之需。

2020-07-28-8.10.58.png

首先登陆我们的宝塔面板添加网站,ims.cool 是我买的域名,所以我可以建一个 test.ims.cool 的网站,同时建一个 FTP 和一个 MySQL 数据库。

2020-07-28-8.13.14.png

建完之后我们登陆刚刚的网站肯定是打不开的,我们要去阿里云服务器的控制台绑定。

2020-07-28-8.15.01.png

输入刚刚建站的域名进行绑定,然后开始解析域名,大概需要 3-5 分钟时间。

2020-07-28-8.19.14.png

刷新一下看看,如果显示已解析,那么就可以顺利打开网站了,在浏览器输入地址试试,发现成功了,那简单的建站就到此为止。

建数据库

前端和后端是通过接口访问数据库数据进行交互的,没有数据库前端只能独自美丽,后端只能在命令行玩。相信大家在学习 Mybatis 框架的时候也已经玩过数据库了,所以多的不说,我们需要对刚刚网站的数据库进行一些操作。

2020-07-28-8.29.56.png

在宝塔面板点开数据库-管理-SQL,将本地数据库的建表,数据插入的代码复制粘贴进这里然后执行,我们就可以得到我们项目所需要的数据表和数据了。当然你要是会写脚本导入,或者远程连接数据库复制也是没问题的。因为我的项目数据量比较少而且留有建表的程序,所以复制粘贴最简单了。

2020-07-28-8.34.19.png

最后一步,回到宝塔,记下数据库名、用户名和密码,这三个我们接下来的后端中是需要同步修改的。

放行程序端口

这一步特别重要!这一步特别重要!这一步特别重要!重要的事情说三遍,我就是以为自己的网站前后端跨域没做好整了几天的配置文件,最后发现是因为端口没放行才走不通的。关于端口放行需要修改两处地方!

2020-07-28-8.48.36.png

首先在宝塔界面打开安全栏,添加放行端口号。我这里后端程序用的端口号是 9988,前端程序用的端口号是 9999,所以需要放行这两个端口号。

2020-07-28-8.48.19.png

接下来打开阿里云服务器控制台,点开安全-防火墙,在这里也要放行之前的两个前后端程序用到的端口号!这真的是一个天大的坑啊,谁知道两个地方都要放行端口 =^= 浪费了我好几天的时间,真是血亏,大家一定不要踩。

后端准备

检查接口

2020-07-28-7.28.01.png

这是我的项目目录结构,第一次写项目可能包的分类不太标准,dao 层就是 mappermodel 层就是 entity ,我原先采用过 Jsp 写,但是写完登录页面就放弃了(页面布局改一下5秒,重启一次 Tomcat 30秒,这谁顶得住),后来想使用 MVC 的格式写,所以 pojo 改成了 model ,不过这些问题都不大。

我们首先点开 controller 层,查看每一个类名上是否有加上 Spring Boot 中的注解 @CrossOrigin,Controller 注解使用 @RestController,如果你是写 Jsp 的那么使用 @Controller@RestController 相当于 @Controller+@ResponseBody,但是视图解析器无法返回 JspHTML 页面。

@RestController()
@CrossOrigin
@RequestMapping("/login/")
public class IndexController extends BaseController {
    private static final String INDEX = "index";

    @Resource(name = "userService")
    private UserService userService;

    @GetMapping(value = "/{name}")
    @ResponseBody
    public String helloWorld(@PathVariable(name = "name") String name) {
        return "Hello " + name;
    }
}

就像这样,我的接口没有用 api 开头,不同的 Controller 使用了不同的映射头。这里是刚进入程序的登录接口,所以用的是 /loginService 的注入使用 @Resource,名称一一对应,不要随心所欲的写。然后给大家看一个简单的接口,用的是 /{name} 意思就是当用户发送不属于其他接口的 GET 请求时返回一个纯文字信息,比如我请求 /login/world,返回的 Response 就是 Hello world

测试接口

现在启动我们的 Spring,然后打开 Postman 测试接口是否能通。输入http://127.0.0.1:9988/login/world 其中 127.0.0.1 就是本地 IP ,可以理解为 localhost(本地域名) ,但有些不同。测试的时候是一样的,但是后面我们还会遇到这个坑。9988 是我给后端程序开放的端口号,我们之前也在服务器上放行过,接下来的配置也要改。/login/world 就是我上一节讲到的接口,是一个测试接口,我们看到响应体中确实输出了 Hello world。到这就可以确定我们后端的接口是可以走的通的,觉得不保险朋友的可以继续测试操作数据库的接口。

2020-07-28-8.40.52.png

修改配置

接口主要就这,相信大家早就已经能在本地调用接口了,我这不多说,如有需要可以另起文章来讲这个。因为我们要部署到服务器上,所以主要修改的是一些本地和远程不同的配置,所以我们打开资源包中配置文件夹下的 application.yml 文件修改配置(IDEA识别 yml 文件需安装 YAML 插件)。如果你的项目没有使用 Spring Boot ,那么就打开你的 application.properties 进行修改。

server:
  port: 9988
logging.level.root: INFO
################### Spring DataSource Configuration ##########################
spring:
  datasource:
    username: 用户名
    password: 密码
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///数据库名?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
  mvc:
#    view:
#      prefix: /static/pages/
#      suffix: .jsp
    static-path-pattern: /**
  resources:
    static-locations: classpath:/static/
################### Mybatis DataSource Configuration ##########################
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    cache-enabled: true
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: cn.kevin.ims.model
  type-handlers-package: cn.kevin.ims.handler

我的配置文件写的比较简单,但主要的都在。首先端口号 9988,第三次提到它了,再次注意一下这是后端程序的端口,你根据自己需要改,只要不和其他程序冲突即可。我们首先在阿里云和宝塔中放行了端口,然后又在 Postman 中测试了本地 IP + 端口号 + 接口映射。接下来改数据库配置,还记得之前让你记下的数据库名、用户名和密码吗,忘记的话再去宝塔中核对一下,然后填入配置文件里。特别提示!!!在 url 这一行一定这么写:

jdbc:mysql:///数据库名?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8

mysql 后面的三个横杠敲黑板划重点。三横杠代表 localhost 也就是本地域名,你在自己电脑使用本地域名,把程序放到服务器上用的还是服务器的本地域名,所以不要填其他内容,填服务器 IP127.0.0.1 都是不行的(如果有可行的朋友请留言告诉我,我在这试过很久都连不通,想不明白为什么)。

后端打包

错误检查已经OK了,包括跨域、接口、数据库配置等等,接下来就可以打包上传到服务器上了。对于打包有两种不同的形式,一种是 jar 包,内置了 Tomcat 服务器,可以直接使用 jar 命令启动,不过占内存很大。还有一种是 war 包,体积比较小,不过要手动配置 Tomcat 服务器并且将项目放到指定根目录下。因为我们的前端项目使用宝塔自动安装的 Nginx 服务器,为了避免再配置 Tomcat 服务器出现问题,我使用 jar 包的方式打包。打包前打开 pom.xml 文件查看打包配置有没有写错。

<packaging>jar</packaging>
<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

我只贴了主要的内容,一个就是设置打包为 jar 包,一个就是以 Maven 的方式为应用提供 SpringBoot 的支持。

2020-07-28-9.21.35.png

package 命令可以帮助我们把项目打包,如果已经打包过,第二次打包为了防止出错可以先使用 clean 命令清除之前打包生成的文件。

2020-07-28-9.39.23.png

生成的文件夹为 target ,我们把 XXX.jar 拖到桌面备用,这个就是我们需要的 jar 包。

上传并启动

接下来我们就可以把 jar 包上传至服务器并启动了。打开宝塔面板,进入网站根目录并上传文件。

2020-07-28-9.47.00.png

等待几秒钟即可完成,jar 包放那就不需要移动了,接下来我们使用远程登录工具来运行这个程序,因为宝塔面板不支持直接运行,我们可以使用 MacOS 的终端连接,或者使用阿里云服务器自带的远程连接,也可以使用像 Putty 这样的工具都行,怎么喜欢怎么来。这里我们直接用网页版的阿里云服务器控制台连接,大家记住下面几行代码即可:

# 0.获取管理员权限
sudo su root
# 1.前台模式启动 jar 包(该模式下无法断开服务连接)
java -jar XXXX.jar
# 2.后台模式启动 jar 包(后台启动后输出内容存入 log 文件中)
nohup java -jar XXXX.jar >XX.log 2>&1&
# 3.查看运行中的 java 程序(查询到的第一个数字就是进程号)
ps -ef|grep java
# 4.杀死进程(此处填进程号)
kill -9 xxxx
# 5.查看日志(这个可以使用宝塔编辑查看)
tail -f XXX.log

首先的首先就是获取管理员权限,否则无法进行一些高级操作。使用 cd 命令(这个命令应该不用解释了。。。)进入刚刚我们的 jar 包所放的目录。然后使用命令 2 启动,如果你只是想简单的测试一下可以使用命令 1,命令 2 的话适合测试完成软件上线之后使用。这里的 nohub 表示关闭标准输出,这样终端不会显示 Spring 启动的过程和 log 信息,2 代表标准错误输出(stderr),1 代表标准输出(stdout),>& 代表合并输出文件,最后的 & 表示把条命令放到后台执行。

如果想要关闭 Spring 的服务,可以先使用命令 3 查找启动的 jar 包的进程号(是进程不是端口哦,而且在启动 jar 包的时候也会给你进程号),然后使用命令 4 结束进程,这样第二次启动项目就不会显示端口已被使用了。

关于日志的话,一般我这种菜鸟也不会去看他,顶多使用宝塔面板直接查看,登服务器敲命令看属实有些麻烦了。

2020-07-28-10.33.44-1.png

现在再用 Postman 测试你的网站上的接口,把 127.0.0.1 改成你的域名,已经可以正常访问了。那么到这里,我们后端项目的部署全部完成。接下来开始部署前端项目,前端部署就方便很多了。

前端准备

2020-07-28-10.43.55.png

这是我前端项目的结构,可能脚手架版本不同,有些文件名和位置也不同。我们这里主要改两处地方,一个是 main.js 中的请求路径,一个是 vue.config.js 中的端口和打包方式。

检查 Axios 请求根路径

因为我们后端 Controller 已经设置了 CrossOrigin,而且我们是部署在同一台服务器上只是端口号不同,所以现在不存在跨域问题了,前端不需要在 vue.config.js 中配置跨域,只要改 Axios 请求的根路径。我们知道前端后端是通过接口来交互的,那么只要前端发送 Ajax 请求的时候确实是往后端接口发的就没有问题。

// 配置请求的根路径
axios.defaults.baseURL = 'http://XXXX:9988'
Vue.prototype.$http = axios

第一行中的 XXXX 是你服务器的公网 IP 地址,可以登录阿里云服务器控制台或者宝塔面板查看

第二行是在 Vue 的原型上启用全局 Axios 请求,后边项目直接使用 $http 就可以使用 Axios 请求了,根据自己项目决定,不写也没问题。

修改配置

接下来打开 vue.config.js 配置一下端口号打包和静态资源存储方式等,原版的配置很多,我这里就写主要的几个(有这几个就够了,不用整其他有的没的)。

module.exports = {
    // 打出来的包名叫 dist
  outputDir: 'dist',
  // 把所有静态资源放 static 中
  assetsDir: 'static',
  devServer: {
      // 服务器 host 就是本地 host
    host: 'localhost',
    // 前端程序端口号
    port: 9999,
    // 关闭 https
    https: false
  }
}

包名可以随便取,默认是 dist,然后设置一下 assetsDir,这样一些静态资源文件不会散开删除文件的时候可以少点几下鼠标devServer 里一个是 host,这个在本地和在服务器都是一样的,反正都是本地。端口号的话我用的是 9999,区别于后端的 9988,这两个端口一定要是在阿里云服务器和宝塔面板同时放行的端口号,并且不与其他应用冲突。然后关闭 https ,目前是用不到的。

之前因为没有开端口,误以为我的接口无法访问是因为没有做好跨域问题,查了很多帖子都说要在这里进行代理。我把代理的代码也贴出来,如果大家在后期部署完发现前台报 CROS 的错误,估计要么后端跨域没做好,要么就是前端缺了这个代理,再要不就是服务器上的 Nginx 配置出了问题。真心希望大家在跨域方面没有出现问题,不然真的头疼。

devServer: {
    host: 'localhost',
    port: 9999,
    https: false,
    proxy: {
        // 后端请求地址全部加上 api 前缀
      '/api': {
          // 需要处理跨域的地址和端口
        target: 'http://XXXX:XXXX/',
        // 关闭加密
        secure: false,
        // 开启跨域
        changeOrigin: true,
        // 把 api 前缀去掉
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }

前端打包

配置改完可以打包了,因为装好了 npm,所以可以直接使用命令打包(在项目根路径下,推荐直接在 IDEA 的命令行操作,或者开 vue-cli 在可视化界面打包也行)。

npm run build

2020-07-28-11.11.56.png

等待一段时间生成一个 dist 文件夹,这就是我们需要的包,也把他拖到桌面。

上传

和后端项目一样,将 dist 包上传至网站根目录中,然后进入 dist 文件夹,剪切里面的文件,回到根目录粘贴所有。这样 index.html 和静态资源都在根目录了。我们输入网址测试,发现可以进入 index 页面,输入用户名和密码登录试试,发现 Post 请求也成功发送至后端接口,并且在数据库中查询到了用户,登录成功!下面是我做的软件首页。

2020-07-28-11.23.01.png

就是一个简简单单的学生管理系统,6 个月,接近 1w 行代码,真的是不容易啊哈哈哈哈。这 6 个月,从 Java 开始学起,使用 JDBC 连接了数据库,做了个简单的用集合类存储的数据存储系统,后来改成使用文件进行存储,再后来学了 MySQL 的增删改查,改用数据库存储。这时候还没有停止,又入手了 SSM 三件套和 Spring Boot 完成了后端的所有接口。因为我打算是专做后端的,所以也没想到会写前端,偶然听说 Vue.js+Element UI 可以快速开发前端页面,于是畏畏缩缩开始了前端的学习。结果开发速度越来越快,到后来已经不需要看视频教程,完全自己写了。等到写的差不多,就开始着手服务器项目的部署,早早的就买了服务器和两个域名开始测试,期间又经历了很多失败,也没人能提供真正有用的帮助。

或许每个人开发中遇到的问题都各不相同,并不是每个人都会踩同样的坑。或许网络上各种帖子上的大佬觉得我这一个同域名不同端口的项目部署起来很简单,所以写了很多很复杂的东西。不过还是那句话,所有人都是从菜鸟开始成长的。我的这篇教程也面向那些刚刚完成项目,不太明白线上部署的同学们。

总结

这篇博文从我部署成功前后端分离项目开始回忆,给大家梳理了一下部署项目的前后端准备和服务器准备,包括配置文件的修改和常用的命令等等,希望能够帮助大家在部署项目方面少踩些坑。如果有更好的建议或者我讲错的地方欢迎评论交流,共同进步!

最后祝看完这篇文章的你部署项目一步到位 0 error!

最后修改:2020 年 08 月 11 日
随意