命令 | 解释 |
---|---|
磁盘命令 | |
pwd | 显示当前在哪个目录 |
clear | 清屏 |
ls | 查看目录(-a 显示全部、-l列表形式) |
ls -al | 展示所有("d"开头目录、"-"文件、"|"链接) |
cd .. | 切换到上一层 |
cd / | 切换到系统根目录 |
cd ~ | 切换到用户主目录 |
cd - | 切换到上一个所在目录 |
cd etc | 进入当前目录下得etc |
cd ../root | 进入当前上一级目录 |
文件操作 | |
touch | 创建文件命令 |
echo "内容" > a.txt | 添加内容到文件,会覆盖 |
echo "内容" >> a.txt | 添加内容到文件中,追加尾部 |
cat 文件 | 显示文件内容 |
cat a.txt >> b.txt | a文件追加到b文件 |
echo $变量 | 显示变量的值 |
文件夹操作 | |
mkdir 名称 | 创建名称的目录 |
mv a.txt b.txt | 移动文件a.txt 并改名为b.txt |
mv test tmp | 移动test到tmp |
cp a.txt b.txt | 复制a到b内 |
cp -r ./web/* ./test | 把web下所有文件及子目录复制到test下 |
rm a.txt | 删除当前文件,会询问 |
rm -f a.txt | 直接删除不会询问 |
rm -rf ./test/* | 递归删除test下所有内容 |
find / -name 'java' | 查询java |
find / -name '*redis' | 查找包含redis的 |
目录权限 | |
chmod u=rwx,g=rw,o=r a.txt | 修改文件权限 |
chmod 750 -R | 文件递归授权 |
chmod 777 -R | 文件目录递归授权 |
文件内容浏览 | |
cat a.txt | 查看a.txt文件全部内容 |
cat a.txt >> b.txt | 把a.txt文件输出到b.txt中 |
more 文件名 | 分页查看文件内容 |
less 文件名 | 分页查看文件内容(-N 显示行号、-m百分比)退出是Q |
head 文件 | 查看文件头部 |
tail -f 文件名 | 实时线持续查看文件内容 |
文件内容编辑 | |
vim 文件名 | 进入查看文件 |
文件内命令 | |
Esc切换模式 | 命令模式、编辑模式、底行模式 |
dd | 删除改行 |
yy | 复制当前行 |
p | 粘贴 |
ctrl-f | 整页翻页 |
i、o、a、insert | 进入编辑模式 |
wq | 底行模式下写入并退出 |
q! | 退出不保存 |
wq! | 强制保存并退出 |
set nu | 显示行号 |
set nu! | 取消显示行号 |
:数字 | 定位行号 |
/字符 | 搜索字符(n是下一个、shfit N上一个) |
noh | 清楚高亮 |
压缩命令 | |
tar -zcvf test.tar.gz test | 将test目录打成压缩包,压缩后文件没那个为test.tar.gz |
tar -xvf test.tar.gz | 将test.tar.gz进行解压 |
tar -xvf test.tar.gz -C /usr/local | 解压缩到指定目录 |
zip -r mydata.zip mydata | 压缩mydata目录 |
zip -r ab.zip a b.txt | 把a文件夹和b.txt压缩成为ab.zip |
unzip -d /a/b filename.zip | 将文件解压到/a/b目录内 |
ps -ef | 显示所有进程 |
kill -9 进程id(PID) | 结束进程 |
grep [option] | 匹配正则或者字符串 |
ifconfig | 查看本机网络信息 |
ping | 查看连接状态 |
netstat | 查看本机使用的端口号 |
linux软件都是用C/C++程序开发,所谓源码安装,是直接提供程序源代码,需要自行编译,然后生成目标可执行程序。类似提供的.java文件,需要自己编译.class,然后打包为jar,然后运行。源代码形式的特点:操作复杂、编译时间长、极易出现问题、依赖关系复杂,比较适合于专门做linux系统开发的人员。
绝大多数开源软件都是直接以原码形式发布的
源代码一般会被打成.tar.gz的归档压缩文件
源代码需要编译成为二进制形式之后才能够运行使用
源代码基本编译流程:
1).configure 检查编译环境;
2)make对源代码进行编译;
3)make insall 将生成的可执行文件安装到当前计算机中
RPM 是 LINUX 下的一种软件的可执行程序,你只要安装它就可以了。这种软件安装包通常是一个RPM包(Redhat Linux Packet Manager,就是Redhat的包管理器),后缀是.rpm。RPM是Red Hat公司随Redhat Linux推出了一个软件包管理器,通过它能够更加轻松容易地实现软件的安装。
安装软件:执行rpm -ivh rpm包名,如:rpm -ivh apache-1.3.6.i386.rpm
升级软件: 执行rpm -Uvh rpm包名。
卸载安装: 执行rpm -e rpm包名。
查询软件包的详细信息:执行rpm -qpi rpm包名
查询某个文件是属于那个rpm包的:执行rpm -qf rpm包名
查该软件包会向系统里面写入哪些文件:执行 rpm -qpl rpm包名
一般使用步骤如下:
rpm –i software.rpm(安装);
rpm -e software.rpm(卸载);
rpm –U software.rpm(升级形式安装);
rpm –ivh http://www.linuxcast.net/software.rpm(支持通过http\ftp协议形式安装)
rpm软件包形式的管理虽然方便,但是需要手工解决软件包的依赖关系。很多时候安装一个软件安装一个软件需要安装1个或者多个其他软件,手动解决时,很复杂,yum可以轻松解决这些问题。
yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及CentOS中的软件包管理器,简单理解Yum是rpm的前端程序。它能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软件包,无须繁琐地一次次下载、安装。
yum仓库用来存放所有的现有的.rpm包,当使用yum安装一个rpm包时,需要依赖关系,会自动在仓库中查找依赖软件并安装。仓库可以是本地的,也可以是HTTP、FTP、nfs形式使用的集中地、统一的网络仓库。
其特点总结如下:
自动解决依赖关系
可以对rpm进行分组,基于组进行安装操作
引入仓库概念,支持多个仓库
配置简单
常规使用如下:
# yum install 安装;
# yum remove卸载;
# yum update 升级制定软件
把需要的软件下载到linux主机,在主机上直接本地安装
安装软件介绍
服务/软件 | 端口 | 备注 |
---|---|---|
jdk8 | - | JAVA的编译和运行环境 |
mysql/mariadb | 3306 | 持久化关系型数据库 |
tomcat | 8080 | 服务器 |
nginx | 80 | 反向代理服务器 |
scp 命令上传 (命令是在Windows机器或mac机器上执行)
#scp 源码文件路径 目标文件路径
# 把本地文件上传到服务器 (当前Windows系统目录)
scp ./*.* [email protected]:~/soft
# 把远程服务器用户目录/soft下所有文件,下载到本地
scp [email protected]:~/soft/*.* ./
rpm安装,能自动配置环境变量。
1)查看当前linux系统是否已经安装java
输入 rpm -qa | grep java
如果有已经安装的jdk ,需要使用以下命令删除
2) 卸载JDK
rpm -e --nodeps
3)安装jdk
cd ~/soft
rpm -ivh jdk-8u181-linux-x64.rpm
4)java -version测试是否成功
java -version
展示以下内容代表OK
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎方面,使用XtraDB(英语:XtraDB)来代替MySQL的InnoDB
1)查看CentOS自带的mysql
输入 rpm -qa | grep mysql
2)将自带的mysql卸载
rpm -e --nodeps
3)yum安装
yum -y install mariadb-server
4)启动mysql
systemctl start mariadb
5)设置root密码
注:这只是设置root用户在本机(linux)登录时的密码
mysqladmin -u root password 'root'
6)进入mysql
mysql -u root -p
备注:输入密码:root
进入到数据库的执行命令行里面了。
7) 进入mysql,并执行下面sql
保证密码和本地一致
下面的话在mysql数据库里面里面执行
-- 查看当前的数据库
show databases;
-- 打开mysql
use mysql ;
-- 查看所有表
show tables;
-- 我们不用ipv6的地址,直接把host改为%,表示所有客户端都可以连接;同时设置密码为root
update user set host='%' ,password=password("root") where user='root' and host = '::1' ;
-- 刷新后才能生效
flush privileges;
退出数据库命令操作
exit;
开放端口号
# 开放端口命令
firewall-cmd --zone=public --add-port=3306/tcp --permanent
#重新加载配置
firewall-cmd --reload
测试远程连接
使用数据库客户端,输入VMIP地址,输入Mysql的用户名和密码,如图
1.使用IDEA数据库客户端插件
2.输入数据库连接信息
项目部署需要tomcat , 配置端口号。
下面需要使用uzip命令(根据当前系统情况而定,不是必须),先安装
#获取安装列表
yum list | grep zip/unzip
#提示输入时,请输入y
yum install zip
#提示输入时,请输入y
yum install unzip
解压tomcat压缩包到 /app
目录下
cd ~/soft
#解压缩到当前
unzip apache-tomcat-8.5.47.zip
#移动到 /usr/local下
mv apache-tomcat-8.5.47 /usr/local/
启动apache-tomcat-8.5.47
#确保启动文件有可执行权限,先修改权限
chmod 755 /usr/local/apache-tomcat-8.5.47/bin/*.sh
#启动
/usr/local/apache-tomcat-8.5.47/bin/startup.sh
开放8080端口
# 开端口命令
firewall-cmd --zone=public --add-port=8080/tcp --permanent
#重新加载配置
firewall-cmd --reload
测试tomcat
在浏览器输入:http://192.168.188.128:8080/
1.安装git【源码安装】
cd ~/soft
# 安装依赖环境
yum -y install zlib-devel curl-devel openssl-devel perl cpio expat-devel gettext-devel openssl zlib autoconf tk perl-ExtUtils-MakeMaker
# 解压缩到当前
tar -zxvf git_v2.4.0.tar.gz
# 进入目录
cd git-2.4.0
# 配置并编译
autoconf
# 检验相关依赖,设置安装路径
./configure --prefix=/usr/local/git
make && make install
默认安装在 /usr/local/bin,把/usr/local/bin放在系统环境变量或当前用户环境变量,操作如下:
路径:/usr/local/git/bin:
vim ~/.bash_profile #加入系统环境变量
source ~/.bash_profile #加载配置文件
git --version #查看版本
备注:这个路径一定写在系统路径的前面,可以覆盖系统默认的git。
2.安装maven【解压缩即可】
# 解压缩到/usr/local下
unzip -d /usr/local apache-maven-3.6.3-bin.zip
# 编辑配置文件,把 /usr/local/apache-maven-3.6.3,添加到系统环境变量
vim ~/.bash_profile #加入系统环境变量
source ~/.bash_profile #加载配置文件
# 查看maven版本
mvn -v
路径:/usr/local/apache-maven-3.6.3
Nginx* (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日,2011年6月1日,nginx 1.0.4发布。
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
安装前准备
#安装Nginx依赖环境,-y表示所有提示默认选择y
#nginx的http模块使用pcre来解析正则表达式,所以需要在linux上安装pcre库:
yum -y install pcre pcre-devel
#nginx使用zlib对http包的内容进行gzip,所以需要在linux上安装zlib库:
yum -y install zlib zlib-devel
#nginx不仅支持http协议,还支持https,所以需要在linux安装openssl库:
yum -y install openssl openssl-devel
# 安装gcc编译环境
yum -y install gcc gcc-c++ autoconf automake make
源码安装
#解压缩nginx
tar -xvf nginx-1.14.2.tar.gz
#进入nginx目录
cd nginx-1.14.2
#安装配置
./configure
#编译
make
# 安装就是把可执行文件复制到/usr/loca/nginx下
make install
> 安装成功之后,就会在/usr/local下多出了一个nginx目录.
- 使用Nginx
```shell
#进入nginx的sbin目录
cd /usr/local/nginx/sbin
#在sbin目录下启动
./nginx
#在sbin目录下停止----需要再用
./nginx -s stop
#在sbin目录下重写加载--需要再用
./nginx -s reload
#修改端口(默认端口80)---需要再用
vim /usr/local/nginx/conf/nginx.conf 配置文件
开端口命令
#开放端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
#重新加载配置
firewall-cmd --reload
#查看是否有nginx的线程是否存在
ps -ef | grep nginx
netstat -an -t -u | grep 80
在浏览器输入:http://192.168.188.128/
解压缩redis
tar -xvf redis-3.2.9.tar.gz -C /usr/local
make命令编译redis的C语言源码
注意:可以把编译后的可执行程序可移动到自定义目录
在redis 目录下创建bin目录,把编译后的服务器、客户端、配置文件copy到此目录下
cd /usr/local/redis-3.2.9
mkdir bin
cp ./src/redis-server ./bin
cp ./src/redis-cli ./bin
cp ./redis.conf ./bin
启动redis服务器
# 进入bin目录
cd bin
# 启动
./redis-server
其它指令和配置
#1. 后台运行 指令后面带 & 代表后台运行
./redis-server &
#2. 运行远程访问
# 使用vi编辑,打开redis.conf文件 (以下是在配置文件中修改)
#==============
# 注释如下这行,目前仅运行127.0.0.1访问
bind 127.0.0.1
# 开启密码访问模式
requirepass pass
# 开启守护进程,允许redis可以后台启动
daemonize yes
#===============
#3. 指定配置文件,启动redis
./redis-server redis.conf
#4. 启动redis客户端和关闭服务器
./redis-cli
./redis-cli shutdown
#5.开放端口
firewall-cmd --zone=public --add-port=6379/tcp --permanent
#重新加载配置
firewall-cmd --reload
#查看是否有nginx的线程是否存在
ps -ef | grep nginx
netstat -an -t -u | grep 6379
部署资料中的SpringBoot项目,部署前先把数据库安装好,然后再把项目的jar包上传到服务器中,然后运行jar包即可。
确认当前数据库状态
systemctl status mariadb
启动数据库
systemctl start mariadb
启动后再次通过systemctl status mariadb
命令查看,确保数据库已经启动
确保数据库已启动后,通过Idea连接此数据库。
注意,此处的连接地址,是虚拟机中CentOS的IP地址
执行资料中提供的sql文件,创建此项目需要的schema
执行后查看连接中的schema,确保执行成功
修改项目中配置文件的数据库和连接地址,修改为虚拟机中数据库的地址
修改后运行项目,确保访问页面可以正常访问数据,访问地址:http://localhost:8080/pages/books.html
执行打包命令,生成jar包
把jar包上传到虚拟机中
进入jar包所在路径,执行java -jar命令
此处java -jar 是前台启动,如果退出窗口的话会关闭java程序
如果需要后台启动需要执行后台启动命令
后台启动命令
nohup java -jar boot_books-1.0-SNAPSHOT.jar &
后台启动并输出日志命令
nohup java -jar boot_books-1.0-SNAPSHOT.jar &> books.log &
输入访问地址,测试程序是否部署成功,访问地址为虚拟机IP地址+端口号+地址
正向代理类似一个中转站,代理内部访问外部资源。
举个例子:
我是一个用户,我访问不了某网站,但是我能访问一个代理服务器,这个代理服务器呢,它能访问那个我不能访问的网站,于是我先连上代理服务器,告诉他我需要那个无法访问网站的内容,代理服务器去取回来,然后返回给我。从那个网站的角度来看,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。
注意:客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的IP地址,还有代理程序的端口。
总结来说:正向代理 是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。
正向代理的用途:
1. 访问原来无法访问的资源,如google
2. 可以做缓存,加速访问资源
3. 对客户端访问授权,上网进行认证
4. 代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息
反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。反向代理的作用
保证内网的安全,可以使用反向代理提供防火墙(WAF)功能,阻止web攻击。大型网站,通常将反向代理作为公网访问地址,Web服务器是内网。
负载均衡,通过反向代理服务器来优化网站的负载。当大量客户端请求代理服务器时,反向代理可以集中分发不同用户请求给不同的weab服务器进行处理请求。(本阶段不实现,负载均衡技术项目阶段讲解)
修改配置文件
vim /usr/local/nginx/conf/nginx.conf
以下是被修订过的nginx.conf,将所有访问到nginx80端口的路径是/开头的请求,都转发到webcase代表的反向代理机群,默认是请求其中一台。
http{
upstream bookssm{
server 127.0.0.1:8080;
#server 192.168.200.129:8080;
}
server {
listen 80;
server_name localhost;
location / {
root html;
#proxy_pass http://192.168.200.138:8080
proxy_pass http://bookssm;
index index.html index.htm;
}
}
}
http块 一个http处理模块,可进行http的相关参数配置,内可以包含多个server块;
upstream块 配置反向代理及负载均衡,可以写多个upstream块,是定义在server块前面。
server localhost:8080; localhost可以指向网络任何一台主机。
server块 包含在http{}内部,每一个server{}都是一个虚拟主机(站点)监听
listen 监听端口
server_name 用于与http请求header头部的Host匹配
location 路径配置,符合某个路径执行块内规则
/ 代表根下资源
root html 是根下的资源,可以从html目录获取。
index 默认页面(不输入网页时,默认访问页)
proxy_pass 反向代理,请求转发给 webcase所代表的主机群
重启服务器
/usr/local/nginx/sbin/nginx -s reload
测试访问
pwd 显示当前在哪个目录
clear 清屏
ls:查看目录
参数 -a 显示全部,包含隐藏
参数 -l 列表形式显示
ls -l 列表展示
“d”开头是目录,
“-” 开头是文件,
“l” 开头是链接文件
ls -a 查看隐藏文件
. 开头的是隐藏文件或目录
ls -la 列表展示,包含隐藏文件 简写命令是 ll -a 。
cd usr 切换到该目录下usr目录
cd .. 切换到上一层目录
cd / 切换到系统根目录
cd ~ (波浪号 tilde) 切换到用户主目录
cd - 切换到上一个所在目录
注意:
绝对路径: 从根开始的,都称为绝对路径
cd /etc: 进入根目录下的etc
相对路径:从当前开始的,都称为相对路径
cd etc: 进入当前目录下的etc :
cd ./etc 同上
cd ../root 进入当前上一级目录 ,.. 代表上一级目录
输入目录时,使用tab,系统会智能提示
touch:创建新文件命令 touch 文件名 默认创建的空文件。
echo "内容" > a.txt 添加内容到文件,会覆盖
echo "内容" >> a.txt 追加内容到文件,追加到尾部
cat 文件 显示文件内容
cat a.txt >> b.txt a文件追加到b文件
备注:
echo $变量 显示变量的值
linux操作系统命令格式: 命令 -[参数]
mkdir 目录名字 [目录名列表],效果如下:
mkdir a 在当前下创建a
mkdir test/a1 在 test下创建a1
mkdir b c d 在当前下同时创建 b、c、d目录
注意:不能跨级创建子目录
mv 文件或目录名 目标文件或目录名,效果如下:
文件操作 mv a.txt b.txt : b.txt不存在即为重命名,存在会提示是否覆盖
目录操作 mv test tmp :tmp不存在即为重命名,存在为移动效果
文件对目录 mv a.txt ./tmp 移动文件到指定目录
cp [参数] 源文件或目录,目标文件或目录
参数: -r 递归
单文件操作 cp a.txt a.txt.bak 在当前下复制一个文件
多文件操作 cp ./web/* ./test 把web下的所有文件复制到test下
递归操作 cp -r ./web/* ./test 把web下的所有文件及子目录复制到test下
rm [参数] 删除文件目录命令
参数: -r 递归 -f 忽略询问
rm a.txt 删除当前下的文件,会询问提示
rm -f a.txt 不询问直接删除
rm -rf ./test 递归删除test下的所有内容,包含test本身
rm -rf ./test/* 递归删除test下的所有内容,但是test不删除
注意:删除一个目录,必须是rm -rf,否则不能删除
find 搜索位置 -name 字符串
find / - name 'java' 查java
find / -name '*redis' 查找含有redis的
权限是Linux中的重要概念,每个文件/目录等都具有权限,通过ls -l命令我们可以 查看某个目录下的文件或目录的权限
示例:在随意某个目录下ls -l
文件的类型:
d:代表目录
-:代表文件
l:代表链接(可以认为是window中的快捷方式)
后面的9位分为3组,每3位置一组,分别代表属主的权限,与当前用户同组的 用户的权限,其他用户的权限
r:代表权限是可读,r也可以用数字4表示
w:代表权限是可写,w也可以用数字2表示
x:代表权限是可执行,x也可以用数字1表示
语法:chmod 数字或符号权限 [参数] 文件或目录
chmod u=rwx,g=rw,o=r aaa.txt
chmod 750 -R 文件或目录名 递归授权
chmod 755 文件或目录
chmod 777 -R 文件或目录
cat命令 查看文件,只能显示文件最后一屏
cat a.txt 查看文件全部内容
注意:
cat除了查看文件内容,还可以把文件内容进行合并
cat a.txt >> b.txt 把a.txt文件输出到b.txt中
比如:
echo 'aaa' > a.txt
echo 'bbb' > b.txt
cat a.txt >> b.txt
more命令查询文件:分页查看所有内容,带百分比
显示文件百分比,回车下一行,空格下一页,退出是Q
less命令查看文件:分页查看所有内容,带行号和百分比
箭头上下代表上一行,下一行,空格显示下一页,退出是Q
-N(大写) 显示行号
-m 百分比
head/tail命令查看文件,支持显示的文件行数
head 查看文件头部 内容
tail 查看文件尾部内容
-n 数字 代表行数
-f 实时持续查看文件内容
vim:文件名
适合快速修改纯文本文件,比如配置文件、属性文件、源文件等
vim编辑器有三种模式
命令模式、编辑模式、底行模式,按ESC,退出当前模式,进入命令模式。
命令模式
刚刚进入是命令模式,从命令模式可进入编辑模式或底行模式。
只接受命令关键字 其他字符不接受,通过输入相应的命令可以进入编辑模式
dd:删除当前行
yy:复制当前行
p:粘贴
整页翻页 ctrl-f、 f是forword , ctrl-b b就是backward
shift+$是移动到行尾,0是移动到行首
编辑模式
进入编辑模式命令:i,o,a或者insert
对文件进行内容编辑 任何字符都接受,内容编辑完毕之后 需要退回命令模式
退回到命令模式,按ESC键
底行模式
在命令模式下,输入冒号 : ,进入底行模式。
底行命令:
:wq,写入并退出,
:q! ,退出不保存
:set nu,显示行号
:set nu!,取消行号显示
:数字,定位行号
:/ 搜索字符,n是下一个,N是上一个
:noh 清除搜索高亮显示
vim编辑器使用过程关于vim使用过程:
vim 文件-------->命令模式--------->输入i---------->编辑模式----------->编辑文件----------->按下Esc--------->命令模式--------->按下:---------->底行模式----------->输入wq保存并退出/q!强制退出不保存
Linux中的打包文件一般是以.tar结尾的,压缩的命令一般是以.gz结尾的。而一般情况下打包和压缩是一起进行的,打包并压缩后的文件的后缀名一般.tar.gz。
参数:-z 调用gzip压缩命令压缩
参数:-c 打包文件
参数:-C 在指定的目录解压缩
参数:-v 显示命令的执行过程
参数:-f 指定文件名
参数:-x 解压缩
示例:将test目录打成压缩包,压缩后文件名为 test.tar.gz
tar -zcvf test.tar.gz test
示例:将test.tar.gz进行解压缩
tar -xvf test.tar.gz
tar -xvf test.tar.gz -C /usr/local 解压缩到指定的目录
zip -r mydata.zip mydata #压缩mydata目录
zip -r abc123.zip abc 123.txt #把abc文件夹和123.txt压缩成为abc123.zip
unzip -d /a/b filename.zip 将文件解压缩到/a/b目录里面
ps命令:查看进程
参数:-e 显示所有程序
参数:-f 显示UID,PPIP
ps -ef 显示所有进程
UID :程序被该 UID(用户ID) 所拥有
PID :就是这个程序的 ID
PPID :则是其上级父程序的ID**
C :CPU使用的资源百分比**
STIME :系统启动时间**
TTY :登入者的终端机位置**
TIME :使用掉的CPU时间。**
CMD :所下达的是什么指令**
kill命令:结束进程
参数:-9 强制杀死该进程
grep [option] 字符串或正则表达式 文件名
从指定文件,搜索匹配的字符串
-i 忽略大小写
示例:
grep -i test /etc/sudo.conf 中包含字符串“test”的内容,且忽略大小写
grep '^d' /etc/sudo.conf 查找以d开头的数据
A命令 |B命令 | C命令
将前一个命令的输出作为下一个命令的输入
可以任意组合,只要是上一级有内容输出,下一个管道就可以处理
ll | grep '^d' | grep '.d$'| grep '4月'
find / -name '*.log' | grep 'tomcat'
查看IP
ifconfig 查看本机网络卡信息
测试网络
ping 查看与某台主机的连接情况
查看端口
netstat 查看本机被使用的端口号
参数:-a 显示所有连接
参数:-n 以网络IP地址代替名称
-t 显示tcp, -u 显示udp连接情况
常用
netstat -an -t -u | grep '8080'
lsof -i tcp:3306
重启 reboot
关机 halt | shutdown
iptables是linux 系统自带的优秀且完全免费的基于包过滤的防火墙工具、它的功能十分强大、使用非常灵活、可以对流入、流出及流经服务器的数据包进行精细的控制。特别是它可以在一台非常低配置下跑的非常好。 centos系统,默认仅仅开放了22端口,其他端口需要使用iptables进行管理(开放、删除、保存规则等)
安装iptables
yum install iptables-services
service iptables save
配置开机启动
把启动防火墙服务的命令,加入到开机启动的配置文件中即可。
vim /etc/profile
查看与删除iptables中放行的规则
#查看iptables列表,显示列表编号
iptables -L -n --line-number
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080
2 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306
3 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
4 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
#删除iptables列表中 编号为1的规则
iptables -D INPUT 1
yum命令安装
yum -y install mysql-community-server
如果出现如图所示,请参考【手动获取rpm文件】:
需要下载205M的资源,需要根据网络情况,等待比较久的时间。
安装完毕如下:
手动获取rpm文件安装
在线获取rpm包
wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
安装下载的rpm文件
rpm -ivh mysql-community-release-el7-5.noarch.rpm
安装mysql-server
yum install mysql-server
启动mysql服务
service mysqld start
查看初始密码【5.7版本执行如下命令,5.6版本,默认密码是空】
grep "password" /var/log/mysqld.log
登录mysql
mysql -u root -p
输入初始密码,可以复制密码,并粘贴到输入密码的位置
设置root密码
修改安全策略 (mysql5.7不允许设置比较简单的密码策略)
set global validate_password_policy=0;
set global validate_password_length=1;
2. 设置密码: set password = password('123456');
3. 授权远程连接
默认情况下mysql为安全起见,不支持远程登录mysql,所以需要设置开启远程登录mysql的权限
grant all privileges on *.* to 'root' @'%' identified by '123456';
flush privileges;
SET PASSWORD FOR 'root'@'%'= PASSWORD('123456');
tar -xvf 解开压缩包到指定目录
tar -xvf jdk-8u211-linux-x64.tar.gz -C /usr/local
编辑配置文件,并配置环境变量
全局配置或当前用户配置,二选一即可。
全局配置文件: vim /etc/profile 或 用户配置文件 vim ~/.bash_profile 推荐前者。
vim /etc/profile
将以下代码复制到profile文件中的末尾。
#set java environment
JAVA_HOME=/usr/local/jdk1.8.0_211/
CLASSPATH=.:$JAVA_HOME/lib.tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
保存并退出
加载环境变量
source /etc/profile 或 source .bash_profile ,推荐前者。
source /etc/profile
不出现任何提示,说明环境加载成功。
测试环境
输入 java或javac ,出现如下提示即为环境配置成功
如果出现:
1. 拉取代码
在Git仓库平台增加服务端的ssh公钥
在服务端机器生成密钥对,使用ssh命令,生成的密钥默认放在用户目录的.ssh目录。
#生成密钥,输入完成命令,默认回车即可。
ssh-keygen -t rsa -C "[email protected]"
# 查看用户目录下的隐藏目录
ls -a ~/
# 查看.ssh目录下的密钥
ls ~/.ssh/
# 查看公钥信息
cat .ssh/id_rsa.pub
-C "[email protected]" 如果省略默认是当前主机名称
复制生成后的 ssh key,通过仓库主页 「管理」->「部署公钥管理」->「添加部署公钥」 ,添加生成的 public key 添加到仓库中。
使用SSH方式,克隆Git仓库代码
cd ~ #切换到用户目录
git clone [email protected]:mobapp/webcase.git
cd ~/webcase
#git clone [email protected]:mobapp/study_springmvc_ssm.git #SSH方式克隆代码
#cd study_springmvc_ssm # 进入项目根目录
git branch # 查看当前分支,默认是master分支
git pull # 拉取最新代码 [第1次不用]
git checkout master # 切换到主分支 [第1次不用]
2. 项目打包
使用mvn命令,自动打包当前项目,默认生成在工程目录的target下
cd ~/webcase
mvn clean package -Dmaven.test.skip=true
备注:第1次打包,会非常慢,因为需要下载依赖库,可以把本地已经下载好的仓库直接放在用户目录的.m2下。
1.上传本地maven仓库到服务器m2目录下
2.解压缩本地仓库
cd ~/.m2
unzip -o repository
备注:-o 覆盖解压缩
3.重新打包
cd ~/webcase
mvn clean package -Dmaven.test.skip=true
3. 项目部署
把War把部署到Tomcat
把生成的war包移动或复制到tomcat webapps目录下即可,注意文件名就是应用的名称。
# 把war包copy到webapp是目录下,并取名为springssm.war
# \cp 是强制覆盖,一般第2次部署时,是不需要确认的,直接覆盖
# cp 如果遇到重名,会提示覆盖
#\cp ~/study_springmvc_ssm/target/springmvc_ssm.war /usr/local/apache-tomcat-8.5.47/webapps/springssm.war
\cp ./target/webcase.war /usr/local/apache-tomcat-8.5.47/webapps/
#启动Tomcat 默认不用重启是可以的
/usr/local/apache-tomcat-8.5.47/bin/startup.sh
# 查看访问日志
tail -f /usr/local/apache-tomcat-8.5.47/logs/localhost_access_log.2022-04-24.txt
访问测试
http://192.168.200.138:8080/webcase/login.html
1. 拉取代码
cd ~ #切换到用户目录
git clone [email protected]:mobapp/spring-boot-mybatis.git #SSH方式克隆代码
cd spring-boot-mybatis # 进入项目根目录
git branch # 查看当前分支,默认是master分支
git pull # 拉取最新代码 [第1次不用]
git checkout master # 切换到主分支 [第1次不用]
2. 项目打包
mvn clean package -Dmaven.test.skip=true
3. 项目启动
启动mysql数据库【前面已启动】
安装项目数据库【前面已安装,本项目与之前项目用的同一数据库】
初始化项目的工作目录
# 在当前创建工作目录
mkdir ~/springmvcboot
# 进入工作目录
cd ~/springmvcboot
启动项目
# 强制负责编译之后的jar包到工作目录
\cp ~/spring-boot-mybatis/target/springboot_ssm.jar ~/springmvcboot
# 后台启动boot项目
nohup java -jar springboot_ssm.jar --server.port=8088 --spring.profiles.active=pro >springboot_ssm_out.log 2>&1 &
# 查看启动日志
tail -f springboot_ssm_out.log
# 开放端口
firewall-cmd --zone=public --add-port=6379/tcp --permanent
#重新加载配置
firewall-cmd --reload
nohup:不挂断地运行命令,退出帐户之后继续运行相应的进程。
springboot_ssm_out.log:是nohup把command的输出重定向到当前目录的指定的文件中.
即输出内容不打印到屏幕上,而是输出到”日志文件名.log”文件中。
2>&1 2就是标准错误,1是标准输出
该命令相当于把标准错误重定向到标准输出么。这里&相当于标准错误等效于标准输出,即把标准错误和标准输出同时输出到指定的“日志文件名.log”文件中。
访问测试
http://192.168.200.138:8088/user/queryAll
注意boot项目,默认是发布在web的根目录下的。SSM项目只要发布到webapps/ROOT下才发布到根目录
部署之前的综合案例,部署前先把数据库安装好,然后再把项目的war包copy到tomcat安装目录即可。
1. 初始化项目数据库
msyql客户端工具连接VM中的mysql
在客户端工具中初始化数据库脚本
CREATE SCHEMA `ssm_db` DEFAULT CHARACTER SET utf8mb4;
use `ssm_db`;
-- ----------------------------
-- Table structure for tbl_book
-- ----------------------------
DROP TABLE IF EXISTS `tbl_book`;
CREATE TABLE `tbl_book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of tbl_book
-- ----------------------------
INSERT INTO `tbl_book` VALUES (1, '计算机理论', 'Spring实战 第5版', 'Spring入门经典教程,深入理解Spring原理技术内幕');
INSERT INTO `tbl_book` VALUES (2, '计算机理论', 'Spring 5核心原理与30个类手写实战', '十年沉淀之作,手写Spring精华思想');
INSERT INTO `tbl_book` VALUES (3, '计算机理论', 'Spring 5 设计模式', '深入Spring源码剖析Spring源码中蕴含的10大设计模式');
INSERT INTO `tbl_book` VALUES (4, '计算机理论', 'Spring MVC+MyBatis开发从入门到项目实战', '全方位解析面向Web应用的轻量级框架,带你成为Spring MVC开发高手');
INSERT INTO `tbl_book` VALUES (5, '计算机理论', '轻量级Java Web企业应用实战', '源码级剖析Spring框架,适合已掌握Java基础的读者');
INSERT INTO `tbl_book` VALUES (6, '计算机理论', 'Java核心技术 卷I 基础知识(原书第11版)', 'Core Java 第11版,Jolt大奖获奖作品,针对Java SE9、10、11全面更新');
INSERT INTO `tbl_book` VALUES (7, '计算机理论', '深入理解Java虚拟机', '5个维度全面剖析JVM,大厂面试知识点全覆盖');
INSERT INTO `tbl_book` VALUES (8, '计算机理论', 'Java编程思想(第4版)', 'Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉');
INSERT INTO `tbl_book` VALUES (9, '计算机理论', '零基础学Java(全彩版)', '零基础自学编程的入门图书,由浅入深,详解Java语言的编程思想和核心技术');
INSERT INTO `tbl_book` VALUES (10, '市场营销', '直播就该这么做:主播高效沟通实战指南', '李子柒、李佳琦、薇娅成长为网红的秘密都在书中');
INSERT INTO `tbl_book` VALUES (11, '市场营销', '直播销讲实战一本通', '和秋叶一起学系列网络营销书籍');
INSERT INTO `tbl_book` VALUES (12, '市场营销', '直播带货:淘宝、天猫直播从新手到高手', '一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
以下是使用IDEA,初始化数据库:
2. 部署项目war包
使用IDEA打war包并上传到服务器
打包
上传到服务器(注意:IP写自己的服务器)
停止当前的tomat服务器
/usr/local/apache-tomcat-8.5.47/bin/shutdown.sh
上传war包到tomcat目录的webapps目录下
(注意:IP写自己的服务器)
scp book_ssm.war [email protected]:/app/apache-tomcat-8.5.47/webapps
备注:SCP会自动覆盖之前上传的文件,Tomcat自动解压缩覆盖之前的文件
启动Tomcat服务器
/usr/local/apache-tomcat-8.5.47/bin/startup.sh
浏览器测试
http://192.168.188.128:8080/book_ssm/pages/books-tomcat.html
如果显示不正常,请查看日志:
tail -f /usr/local/apache-tomcat-8.5.47/logs/catalina.out
前后端分离开发
Yapi
Swagger
项目部署
当前项目中,前端代码和后端代码混合在一起,是存在问题的,存在什么问题呢?
主要存在以下几点问题:
1). 开发人员同时负责前端和后端代码开发,分工不明确
2). 开发效率低
3). 前后端代码混合在一个工程中,不便于管理
4). 对开发人员要求高(既会前端,又会后端),人员招聘困难
为了解决上述提到的问题,现在比较主流的开发方式,就是前后端分离开发,前端人员开发前端的代码,后端开发人员开发服务端的业务功能,分工明确,各司其职。我们本章节,就是需要将之前的项目进行优化改造,变成前后端分离开发的项目。
前后端分离开发,就是在项目开发过程中,对于前端代码的开发由专门的前端开发人员负责,后端代码则由后端开发人员负责,这样可以做到分工明确、各司其职,提高开发效率,前后端代码并行开发,可以加快项目开发进度。
目前,前后端分离开发方式已经被越来越多的公司所采用,成为当前项目开发的主流开发方式。
前后端分离开发后,从工程结构上也会发生变化,即前后端代码不再混合在同一个maven工程中,而是分为 前端工程 和 后端工程 。
前后端分离之后,不仅工程结构变化,后期项目上线部署时,与之前也不同:
1). 之前: 前后端代码都混合在一起,我们只需要将前端和后端的代码统一打成jar包,直接运行就可以了。
2). 现在: 拆分为前后端分离的项目后,最终部署时,后端工程会打成一个jar包,运行在Tomcat中(springboot内嵌的tomcat)。前端工程的静态资源,会直接部署在Nginx中进行访问。
前后端分离开发后,面临一个问题,就是前端开发人员和后端开发人员如何进行配合来共同开发一个项目?可以按照如下流程进行:
1). 定制接口: 这里所说的接口不是我们之前在service, mapper层定义的interface; 这里的接口(API接口)就是一个http的请求地址,主要就是去定义:请求路径、请求方式、请求参数、响应数据等内容。(具体接口文档描述的信息, 如上图)
2). 前后端并行开发: 依据定义好的接口信息,前端人员开发前端的代码,服务端人员开发服务端的接口; 在开发中前后端都需要进行测试,后端需要通过对应的工具来进行接口的测试,前端需要根据接口定义的参数进行Mock数据模拟测试。
3). 联调: 当前后端都开发完毕并且自测通过之后,就可以进行前后端的联调测试了,在这一阶段主要就是校验接口的参数格式。
4). 提测: 前后端联调测试通过之后,就可以将项目部署到测试服务器,进行自动化测试了。
1). 开发工具
Visual Studio Code (简称VsCode)
Hbuilder
2). 技术框架
A. Node.js: Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。(类似于java语言中的JDK)。
B. Vue : 目前最火的的一个前端javaScript框架。
C. ElementUI: 一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库,通过ElementUI组件可以快速构建项目页面。
D. Mock: 生成随机数据,拦截 Ajax 请求,前端可以借助于Mock生成测试数据进行功能测试。
E. Webpack: webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler),分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Sass,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
YApi 是高效、易用、功能强大的 api 管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护 API,YApi 还为用户提供了优秀的交互体验,开发人员只需利用平台提供的接口数据写入工具以及简单的点击操作就可以实现接口的管理。
YApi让接口开发更简单高效,让接口的管理更具可读性、可维护性,让团队协作更合理。
源码地址: https://github.com/YMFE/yapi
官方文档: YApi 接口管理平台
要使用YApi,项目组需要自己进行部署,在本项目中我们可以使用课程提供的平台进行测试。L
域名: https://mock-java.itheima.net/
2.2.1 准备
注册账号,登录平台
2.2.2 定义接口
登录到Yapi平台之后,我们可以创建项目,在项目下创建接口分类,在对应的分类中添加接口。
1). 创建项目
2). 添加分类
在当前项目中,有针对于员工、菜品、套餐、订单的操作,我们在进行接口维护时,可以针对接口进行分类,如果没有对应的分类,我们自己添加分类。
3). 添加接口
接口基本信息录入之后,添加提交,就可以看到该接口的基本信息:
但是目前,接口中我们并未指定请求参数,响应数据等信息,我们可以进一步点击编辑,对该接口 详情进行编辑处理。
4). 运行接口
Yapi也提供了接口测试功能,当我们接口编辑完毕后,后端服务的代码开发完毕,启动服务,就可以使用Yapi进行接口测试了。
注意: 由于菜品分页查询接口,是需要登录后才可以访问的,所以在测试该接口时,需要先请求员工管理接口中的登录接口,登录完成后,再访问该接口。
插件安装(运行时,如果是谷歌浏览器需要安排调试插件):
插件安装,可参考:chrome 安装 yapi 扩展教程 - 掘金,使用的插件已在资料中。
在Yapi平台中,将接口文档定义好了之后,前后端开发人员就需要根据接口文档中关于接口的描述进行前端和后端功能的开发。
2.2.3 导出接口文档
在Yapi平台中我们不仅可以在线阅读文档,还可以将Yapi中维护的文档直接导出来,可以导出md,json,html格式,在导出时自行选择即可 。
而在导出的html文件或md文件中,主要描述的就是接口的基本信息, 包括: 请求路径、请求方式、接口描述、请求参数、返回数据等信息。展示形式如下:
2.2.4 导入接口文档
上述我们讲解了接口文档的导出,我们也可以将外部的接口文档导入到Yapi的平台中,这样我们就不用一个接口一个接口的添加了。我们可以将课程资料中提供的json格式的接口文档直接导入Yapi平台中来。
导入过程中出现的确认弹窗,选择"确认"。
导入成功之后,我们就可以在Yapi平台查看到已导入的接口。
官网:API Documentation & Design Tools for Teams | Swagger
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。功能主要包含以下几点:
A. 使得前后端分离开发更加方便,有利于团队协作
B. 接口文档在线自动生成,降低后端开发人员编写接口文档的负担
C. 接口功能测试
使用Swagger只需要按照它的规范去定义接口及接口相关的信息,再通过Swagger衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,以及在线接口调试页面等等。
直接使用Swagger, 需要按照Swagger的规范定义接口, 实际上就是编写Json文件,编写起来比较繁琐、并不方便, 。而在项目中使用,我们一般会选择一些现成的框架来简化文档的编写,而这些框架是基于Swagger的,如knife4j。knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。而我们要使用kinfe4j,需要在pom.xml中引入如下依赖即可:
com.github.xiaoymin
knife4j-spring-boot-starter
3.0.2
接下来,我们就将我们的项目集成Knife4j,来自动生成接口文档。这里我们还是需要再创建一个新的分支v1.2,在该分支中进行knife4j的集成,集成测试完毕之后,没有问题,我们再将v1.2分支合并到master。
使用knife4j,主要需要操作以下几步:
1). 导入knife4j的maven坐标
com.github.xiaoymin
knife4j-spring-boot-starter
3.0.2
2). 导入knife4j相关配置类并设置静态资源访问
这里我们就不需要再创建一个新的配置类了,我们直接在WebMvcConfig配置类中声明即可。
A. 在该配置类中加上两个注解 @EnableSwagger2 @EnableKnife4j ,开启Swagger和Knife4j的功能。
B. 在配置类中声明一个Docket类型的bean, 通过该bean来指定生成文档的信息。
C. 由于Swagger生成的在线文档中,涉及到很多静态资源,这些静态资源需要添加静态资源映射,否则接口文档页面无法访问。因此需要在 WebMvcConfig类中的addResourceHandlers方法中增加如下配置。
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.List;
@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Autowired
private ObjectMapper objectMapper;
/**
* 设置静态资源映射
* 由于Swagger生成的在线文档中,涉及到很多静态资源,这些静态资源需要添加静态资源映射,否则接口文档页面无法访问。因此需要在 WebMvcConfig类中的addResourceHandlers方法中增加如下配置。
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开始进行静态资源映射...");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
/**
* 扩展mvc框架的消息转换器
* @param converters
*/
@Override
protected void extendMessageConverters(List> converters) {
log.info("扩展消息转换器...");
//创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,底层使用Jackson将Java对象转为json
//messageConverter.setObjectMapper(new JacksonObjectMapper());
messageConverter.setObjectMapper(objectMapper);
//将上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0,messageConverter);
}
@Bean
public Docket createRestApi() {
// 文档类型
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.itheima.reggie.controller"))
.paths(PathSelectors.any())
.build();
}
// // springfox.documentation.service.ApiInfo
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("瑞吉外卖")
.version("1.0")
.description("瑞吉外卖接口文档")
.build();
}
}
注意: Docket声明时,指定的有一个包扫描的路径,该路径指定的是Controller所在包的路径。因为Swagger在生成接口文档时,就是根据这里指定的包路径,自动的扫描该包下的@Controller, @RestController, @RequestMapping等SpringMVC的注解,依据这些注解来生成对应的接口文档。
3). 在LoginCheckFilter中设置不需要处理的请求路径
需要将Swagger及Knife4j相关的静态资源直接放行,无需登录即可访问,否则我们就需要登录之后,才可以访问接口文档的页面。
在原有的不需要处理的请求路径中,再增加如下链接:
"/doc.html",
"/webjars/**",
"/swagger-resources",
"/v2/api-docs"
经过上面的集成配置之后,我们的项目集成Swagger及Knife4j就已经完成了,接下来我们可以重新启动项目,访问接口文档,访问链接为: http://localhost:8080/doc.html
我们可以看到,在所有的Controller中提供的所有的业务增删改查的接口,全部都已经自动生成了,我们通过接口文档可以看到请求的url、请求方式、请求参数、请求实例、响应的参数,响应的示例。 并且呢,我们也可以通过这份在线的接口文档,对接口进行测试。
注意: 由于我们服务端的Controller中的业务增删改查的方法,都是必须登录之后才可以访问的,所以,我们在测试时候,也是需要先访问登录接口。登录完成之后,我们可以再访问其他接口进行测试。
我们不仅可以在浏览器浏览生成的接口文档,Knife4j还支持离线文档,对接口文档进行下载,支持下载的格式有:markdown、html、word、openApi。
3.4.1 问题说明
在上面我们直接访问Knife4j的接口文档页面,可以查看到所有的接口文档信息,但是我们发现,这些接口文档分类及接口描述都是Controller的类名(驼峰命名转换而来)及方法名,而且在接口文档中,所有的请求参数,响应数据,都没有中文的描述,并不知道里面参数的含义,接口文档的可读性很差。
3.4.2 注解介绍
为了解决上述的问题,Swagger提供了很多的注解,通过这些注解,我们可以更好更清晰的描述我们的接口,包含接口的请求参数、响应数据、数据模型等。核心的注解,主要包含以下几个:
注解 | 位置 | 说明 |
---|---|---|
@Api | 类 | 加载Controller类上,表示对类的说明 |
@ApiModel | 类(通常是实体类) | 描述实体类的作用 |
@ApiModelProperty | 属性 | 描述实体类的属性 |
@ApiOperation | 方法 | 说明方法的用途、作用 |
@ApiImplicitParams | 方法 | 表示一组参数说明 |
@ApiImplicitParam | 方法 | 用在@ApiImplicitParams注解中,指定一个请求参数的各个方面的属性 |
3.4.3 注解测试
1). 实体类
可以通过 @ApiModel , @ApiModelProperty 来描述实体类及属性
@Data
@ApiModel("套餐")
public class Setmeal implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键")
private Long id;
//分类id
@ApiModelProperty("分类id")
private Long categoryId;
//套餐名称
@ApiModelProperty("套餐名称")
private String name;
//套餐价格
@ApiModelProperty("套餐价格")
private BigDecimal price;
//状态 0:停用 1:启用
@ApiModelProperty("状态")
private Integer status;
//编码
@ApiModelProperty("套餐编号")
private String code;
//描述信息
@ApiModelProperty("描述信息")
private String description;
//图片
@ApiModelProperty("图片")
private String image;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
2). 响应实体R
@Data
@ApiModel("返回结果")
public class R<T> implements Serializable{
@ApiModelProperty("编码")
private Integer code; //编码:1成功,0和其它数字为失败
@ApiModelProperty("错误信息")
private String msg; //错误信息
@ApiModelProperty("数据")
private T data; //数据
@ApiModelProperty("动态数据")
private Map map = new HashMap(); //动态数据
//省略静态方法 ....
}
3). Controller类及其中的方法
描述Controller、方法及其方法参数,可以通过注解: @Api, @APIOperation, @ApiImplicitParams, @ApiImplicitParam
@RestController
@RequestMapping("/setmeal")
@Slf4j
@Api(tags = "套餐相关接口")
public class SetmealController {
@Autowired
private SetmealService setmealService;
@Autowired
private CategoryService categoryService;
@Autowired
private SetmealDishService setmealDishService;
/**
* 新增套餐
* @param setmealDto
* @return
*/
@PostMapping
@CacheEvict(value = "setmealCache",allEntries = true)
@ApiOperation(value = "新增套餐接口")
public R<String> save(@RequestBody SetmealDto setmealDto){
log.info("套餐信息:{}",setmealDto);
setmealService.saveWithDish(setmealDto);
return R.success("新增套餐成功");
}
/**
* 套餐分页查询
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
@ApiOperation(value = "套餐分页查询接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "page",value = "页码",required = true),
@ApiImplicitParam(name = "pageSize",value = "每页记录数",required = true),
@ApiImplicitParam(name = "name",value = "套餐名称",required = false)
})
public R<Page> page(int page,int pageSize,String name){
//分页构造器对象
Page<Setmeal> pageInfo = new Page<>(page,pageSize);
Page<SetmealDto> dtoPage = new Page<>();
LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
//添加查询条件,根据name进行like模糊查询
queryWrapper.like(name != null,Setmeal::getName,name);
//添加排序条件,根据更新时间降序排列
queryWrapper.orderByDesc(Setmeal::getUpdateTime);
setmealService.page(pageInfo,queryWrapper);
//对象拷贝
BeanUtils.copyProperties(pageInfo,dtoPage,"records");
List<Setmeal> records = pageInfo.getRecords();
List<SetmealDto> list = records.stream().map((item) -> {
SetmealDto setmealDto = new SetmealDto();
//对象拷贝
BeanUtils.copyProperties(item,setmealDto);
//分类id
Long categoryId = item.getCategoryId();
//根据分类id查询分类对象
Category category = categoryService.getById(categoryId);
if(category != null){
//分类名称
String categoryName = category.getName();
setmealDto.setCategoryName(categoryName);
}
return setmealDto;
}).collect(Collectors.toList());
dtoPage.setRecords(list);
return R.success(dtoPage);
}
/**
* 删除套餐
* @param ids
* @return
*/
@DeleteMapping
@CacheEvict(value = "setmealCache",allEntries = true)
@ApiOperation(value = "套餐删除接口")
public R<String> delete(@RequestParam List<Long> ids){
log.info("ids:{}",ids);
setmealService.removeWithDish(ids);
return R.success("套餐数据删除成功");
}
/**
* 根据条件查询套餐数据
* @param setmeal
* @return
*/
@GetMapping("/list")
@Cacheable(value = "setmealCache",key = "#setmeal.categoryId + '_' + #setmeal.status")
@ApiOperation(value = "套餐条件查询接口")
public R<List<Setmeal>> list(Setmeal setmeal){
LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(setmeal.getCategoryId() != null,Setmeal::getCategoryId,setmeal.getCategoryId());
queryWrapper.eq(setmeal.getStatus() != null,Setmeal::getStatus,setmeal.getStatus());
queryWrapper.orderByDesc(Setmeal::getUpdateTime);
List<Setmeal> list = setmealService.list(queryWrapper);
return R.success(list);
}
}
4). 重启服务测试
我们上述通过Swagger的注解,对实体类及实体类中的属性,以及Controller和Controller的方法进行描述,接下来,我们重新启动服务,然后看一下自动生成的接口文档有何变化。
在接口文档的页面中,我们可以看到接口的中文描述,清晰的看到每一个接口是做什么的,接口方法参数什么含义,参数是否是必填的,响应结果的参数是什么含义等,都可以清楚的描述出来。
总之,我们要想清晰的描述一个接口,就需要借助于Swagger给我们提供的注解。
在本章节,我们要做的是项目的部署,包含前端项目的部署,及后端项目的部署。
PC端: 主要是为餐厅的员工及管理员使用的后台管理系统,对分类、菜品、套餐信息进行维护。
移动端: 可以基于微信公众号或小程序实现,我们课上并未实现,这部分的工作是前端开发人员需要开发的。
防火墙:硬件产品,让访问服务器更加安全
前端部署服务器: Nginx(反向代理)
后端部署服务器: 项目部署服务器
具体的服务器的软件安装如下:
服务器 | 软件 | 名称 |
---|---|---|
Nginx服务器 | Nginx(部署前端项目、配置反向代理) | |
项目部署服务器 | JDK1.8、Git、Maven | |
数据库服务器 | MySQL数据库 | |
Redis服务器 | Redis(缓存中间件) |
以上需要的软件安装,可以参考
1). 在服务器A中安装Nginx,将课程资料中的静态资源目录上传到Nginx的html目录下
将整个目录上传至/usr/local/nginx/html目录下
上传完成后,如图所示
执行解压缩命令
unzip html.zip
2). 修改Nginx配置文件nginx.conf
将nginx.conf配置文件中,将原有的监听80, 82, 8080端口号 的虚拟主机注释掉,引入如下的配置信息:
upstream boot{
# 200.1 宿主机
server 192.168.200.138:8080;
#server 192.168.200.129:8080;
}
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html;
}
# http://192.168.188.128/api/employee/login
# 会被这个配置拦截住
location ^~ /api/ {
# 重定向的操作
# /employee/login
rewrite ^/api/(.*)$ /$1 break;
# http://192.168.200.138:8080/employee/login
proxy_pass http://boot;
}
location = /50x.html {
root html;
}
}
3). 通过nginx访问前端工程
http://192.168.200.138/backend/page/login/login.html
前端工程部署完成之后,我们可以正常的访问到系统的登录页面,点击登录按钮,可以看到服务端发起的请求,请求信息如下:
而大家知道,在我们之前开发的工程中,是没有/api这个前缀的,那这个时候,在不修改服务端代码的情况下,如何处理该请求呢?
实际上,通过nginx的就可以轻松解决这个问题。
在上述我们配置的nginx.conf中,除了配置了静态资源的加载目录以外,我们还配置了一段反向代理的配置,配置信息如下:
upstream boot{
# 200.1 宿主机
server 192.168.200.138:8080;
#server 192.168.200.129:8080;
}
location ^~ /api/ {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://boot;
}
这一段配置代表,如果请求当前nginx,并且请求的路径如果是 /api/ 开头,将会被该location处理。而在该location中,主要配置了两块儿信息: rewrite(url重写) 和 proxy_pass(反向代理)。 接下来我们就来解析一下这两项的配置。
1). 路径重写rewrite
rewrite ^/api/(.*)$ /$1 break;
这里写的是一个正则表达式,代表如果请求路径是以 /api/
开头,后面的请求路径任意,此时将原始的url路径重写为 /$1
,这里的$1
指代的就是通配符 .* 这一块的内容。比如:
/api/employee/login ------> ^/api/(.*)$ --------> 此时 (.*) 匹配的就是 employee/login ------> 最终重写为/$1 : /employee/login
2). 反向代理
proxy_pass http://boot;
boot是一个虚拟名称的代表,代表是就是前面定义的upstream boot 。boot 代表是一个机器的集群。可以根据负载策略随机选择一台。如果仅有一台直接转发到这台主机。
路径重写后的请求,将会转发到后端的 http://192.168.200.138:8080 服务器中。
SpringBoot项目部署的核心思路与步骤:
环境安装:部署环境的安装
拉取代码:通过git命令,克隆并拉取仓库的代码,默认是master分支(发布时都用此分支)
编译打包:通过maven命令,对项目代码进行编译打包,输出jar包
启动项目:把输出的jar包复制到工作目录(运维人员指定的目录),并在后台启动。
测试后端接口:使用postman测试接口是否正常访问。
脚本部署与发布:如果经常修改项目,需要重新打包上线,建议直接使用脚本
1.环境安装
A. 确认JDK环境
B. 确认Git环境
C. 确认Maven环境
2.拉取代码
# 进入用户目录
cd ~
# 克隆代码 ,克隆后默认检查的master分支
git clone git@gitee.com:mobapp/reggie_take_out.git
# 进入项目目录
cd ~/reggie_take_out
# 拉取代码(第1次克隆后,已经拉取过了,可以不执行)
git pull
如果克隆时出现如下提示:
说明需要把把当前服务器的SSH公钥放在gitee服务器上,才可以通过SSH协议拉取仓库的代码。
3.编译项目
1.进入仓库目录根目录,执行编译命令
# 进入项目目录
cd ~/reggie_take_out
mvn clean package -Dmaven.test.skip=true
正常编译如下:
备注:在执行mvn打包时,需要下载项目用的依赖仓库,如果网速很慢,这个过程会花费很长时间,如图所示:
建议ctrl+c强行终止,然后把本地的maven仓库或提供的mvn仓库,上传到服务器mvn默认仓库。
2.解压缩mvn仓库(编译失败,才执行此步骤)
mvn默认仓库是在用户目录下,以.m2开头
把git仓库放在.m2下
cd ~/soft
# 解压到当前目录
unzip git仓库.zip
# 把解压的文件复制到 .m2下
cp -rf ./git仓库/*.* ~/.m2/
解压缩上传的仓库,覆盖默认仓库
cd ~/.m2
unzip -o repository.zip
4.启动项目
启动之前先启动nginx、mysql、redis
备注:mysql数据库,需要安装reggie项目;redis暂时可以远程连接。
创建工作目录,把jar复制到工作目录
cd ~/
mkdir reggie_project
# reggie_take_out目录与自己的项目对应
# reggie_take_out-1.0-SNAPSHOT.jar文件 与自己的项目对应
\cp ~/reggie_take_out/target/reggie_take_out-1.0-SNAPSHOT.jar ~/reggie_project/
后台启动jar包
cd ~/reggie_project/
#reggie_take_out-1.0-SNAPSHOT.jar 与自己的项目名称对应
nohup java -jar reggie_take_out-1.0-SNAPSHOT.jar &> reggie_take_out.log &
# 查看启动日志
tail -f reggie_take_out.log
5.测试后端接口
测试登录
测试发送验证码(主要是测试Redis)
nohup java -jar -Dspring.profiles.active=pro reggie_take_out-1.0-SNAPSHOT.jar &> reggie_take_out.log &
6.脚本部署与发布
1.把脚本上传到工作目录
将资料中提供的start-reggie.sh和stop-reggie.sh文件上传到服务器工作目录
备注:.sh文件的将多个命令合并在一起的批处理命令。
2.设置脚本执行权限
cd ~/reggie_project/
chmod 755 *.sh
3) 执行start-reggie.sh脚本文件,自动部署项目
执行完shell脚本之后,我们可以通过 ps -ef|grep java 指令,查看服务是否启动。
查看启动日志
tail -f reggie_take_out.log
4). 访问系统测试
http://192.168.200.138/backend/page/login/login.html
在上述的测试中,我们发现菜品的图片无法正常展示。原因是因为,在我们的配置文件中,图片信息依然是从 D:/img 中加载的,但是在Linux服务器中,是不存在D盘的。
1). 修改文件存储目录,并提交代码
将文件存储目录修改为:
reggie:
path: /usr/local/img/
2). 执行shell脚本,进行自动化部署
3).访问测试
http://192.168.200.138/backend/index.html
MySQL主从复制
读写分离案例
项目实现读写分离
Nginx-概述
Nginx-命令
Nginx-应用
1). 存在的问题
在前面基础功能实现的过程中,我们后台管理系统及移动端的用户,在进行数据访问时,都是直接操作数据库MySQL的。结构如下图:
而在当前,MySQL服务器只有一台,那么就可能会存在如下问题:
1). 读和写所有压力都由一台数据库承担,压力大
2). 数据库服务器磁盘损坏则数据丢失,单点故障
2). 解决方案
为了解决上述提到的两个问题,我们可以准备两台MySQL,一台主(Master)服务器,一台从(Slave)服务器,主库的数据变更,需要同步到从库中(主从复制)。而用户在访问我们项目时,如果是写操作(insert、update、delete),则直接操作主库;如果是读(select)操作,则直接操作从库(在这种读写分离的结构中,从库是可以有多个的),这种结构我们称为 读写分离 。
今天我们就需要实现上述的架构,来解决业务开发中所存在的问题。
MySQL数据库默认是支持主从复制的,不需要借助于其他的技术,我们只需要在数据库中简单的配置即可。接下来,我们就从以下的几个方面,来介绍一下主从复制:
MySQL主从复制是一个异步的复制过程,底层是基于Mysql数据库自带的 二进制日志 功能。就是一台或多台MySQL数据库(slave,即从库)从另一台MySQL数据库(master,即主库)进行日志的复制,然后再解析日志并应用到自身,最终实现 从库 的数据和 主库 的数据保持一致。MySQL主从复制是MySQL数据库自带功能,无需借助第三方工具。
二进制日志:
二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但是不包括数据查询语句。此日志对于灾难时的数据恢复起着极其重要的作用,MySQL的主从复制, 就是通过该binlog实现的。默认MySQL是未开启该日志的。
MySQL的主从复制原理如下:
MySQL复制过程分成三步:
1). MySQL master 将数据变更写入二进制日志( binary log)
2). slave将master的binary log拷贝到它的中继日志(relay log)
3). slave重做中继日志中的事件,将数据变更反映它自己的数据
1.2.1 准备工作
提前准备两台服务器,并且在服务器中安装MySQL,服务器的信息如下:
数据库 | IP | 数据库版本 |
---|---|---|
Master | 192.168.200.200 | 5.7.25 |
Slave | 192.168.200.201 | 5.7.25 |
并在两台服务器上做如下准备工作:
注意:如果已放开相应的端口号,就不需要再执行此操作了
1). 防火墙开放3306端口号
# 放开3306端口
firewall-cmd --zone=public --add-port=3306/tcp --permanent
# 重新加载配置
firewall-cmd --reload
# 显示当前放开的端口号
firewall-cmd --zone=public --list-ports
2). 并将两台数据库服务器启动起来:
注意:此处根据自己安装的数据库启动
如果数据库已启动,就不需要再执行此操作了
启动Mariadb
systemctl start mariadb
启动MySQL
systemctl start mysqld
登录MySQL,验证是否正常启动
1.2.2 主库配置
服务器: 192.168.200.200
1). 修改Mysql数据库的配置文件/etc/my.cnf
在最下面增加配置:
log-bin=mysql-bin #[必须]启用二进制日志
server-id=200 #[必须]服务器唯一ID(唯一即可)
2). 重启Mysql(Mariadb)服务
执行指令:
此处根据自己安装的数据库启动
重启Mariadb
systemctl restart mariadb
重启MySql
systemctl restart mysqld
3). 创建数据同步的用户并授权
登录mysql
mysql -u root -p
并执行如下指令,创建用户并授权:
GRANT REPLICATION SLAVE ON *.* to 'xiaoming'@'%' identified by 'Root@123456';
注:上面SQL的作用是创建一个用户 xiaoming ,密码为 Root@123456 ,并且给xiaoming用户授予REPLICATION SLAVE权限。常用于建立复制时所需要用到的用户权限,也就是slave必须被master授权具有该权限的用户,才能通过该用户复制。
MySQL密码复杂程度说明:
目前mysql5.7默认密码校验策略等级为 MEDIUM , 该等级要求密码组成为: 数字、小写字母、大写字母 、特殊字符、长度至少8位
4). 登录Mysql数据库,查看master同步状态
执行下面SQL,记录下结果中File和Position的值
show master status;
注:上面SQL的作用是查看Master的状态,执行完此SQL后不要再执行任何操作
1.2.3 从库配置
服务器: 192.168.200.201
1). 修改Mysql数据库的配置文件/etc/my.cnf
server-id=201 #[必须]服务器唯一ID
2). 重启Mysql(Mariadb)服务
执行指令:
注意:此处根据自己安装的数据库启动
重启Mariadb
systemctl restart mariadb
重启MySql
systemctl restart mysqld
3). 登录Mysql数据库,设置主库地址及同步位置
change master to master_host='192.168.188.128',master_user='xiaoming',master_password='Root@123456',master_log_file='mysql-bin.000001',master_log_pos=396;
start slave;
参数说明:
A. master_host : 主库的IP地址
B. master_user : 访问主库进行主从复制的用户名(上面在主库创建的)
C. master_password : 访问主库进行主从复制的用户名对应的密码
D. master_log_file : 从哪个日志文件开始同步(上述查询master状态中展示的有)
E. master_log_pos : 从指定日志文件的哪个位置开始同步(上述查询master状态中展示的有)
4). 查看从数据库的状态
show slave status;
然后通过状态信息中的 Slave_IO_running 和 Slave_SQL_running 可以看出主从同步是否就绪,如果这两个参数全为Yes,表示主从同步已经配置完成。
MySQL命令行技巧:
\G : 在MySQL的sql语句后加上\G,表示将查询结果进行按列打印,可以使每个字段打印到单独的行。即将查到的结构旋转90度变成纵向;
主从复制的环境,已经搭建好了,接下来,我们可以通过Navicat连接上两台MySQL服务器,进行测试。测试时,我们只需要在主库Master执行操作,查看从库Slave中是否将数据同步过去即可。
1). 在master中创建数据库itcast, 刷新slave查看是否可以同步过去
2). 在master的itcast数据下创建user表, 刷新slave查看是否可以同步过去
3). 在master的user表中插入一条数据, 刷新slave查看是否可以同步过去
面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。
通过读写分离,就可以降低单台数据库的访问压力, 提高访问效率,也可以避免单机故障。
主从复制的结构,我们在第一节已经完成了,那么我们在项目中,如何通过java代码来完成读写分离呢,如何在执行select的时候查询从库,而在执行insert、update、delete的时候,操作主库呢?这个时候,我们就需要介绍一个新的技术 ShardingJDBC。
Sharding-JDBC定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
使用Sharding-JDBC可以在程序中轻松的实现数据库读写分离。
Sharding-JDBC具有以下几个特点:
1). 适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
2). 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
3). 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。
依赖:
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC1
在主库中创建一个数据库rw, 并且创建一张表, 该数据库及表结构创建完毕后会自动同步至从数据库,SQL语句如下:
create database rw default charset utf8mb4;
use rw;
CREATE TABLE `user` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`address` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO user (name, age, address) VALUES ('张三', 100, '昌平');
INSERT INTO user (name, age, address) VALUES ('李四', 0, '顺义');
INSERT INTO user (name, age, address) VALUES ('星越L', 21, '北京');
我们本案例主要是演示一下读写分离操作,对于基本的增删改查的业务操作,我们就不再去编写了,我们可以直接导入资料中提供的demo工程(rw_demo),在demo工程中,我们已经完成了user的增删改查操作,具体的工程结构如下:
1). 在pom.xml中增加shardingJdbc的maven坐标
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC1
2). 在application.yml中增加配置
spring:
main:
# 如果当前项目中存在同名的bean,后定义的bean会覆盖先定义的
allow-bean-definition-overriding: true
shardingsphere:
datasource:
names:
master,slave
# 主数据源
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.200.200:3306/rw?characterEncoding=utf-8
username: root
password: root
# 从数据源
slave:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.200.201:3306/rw?characterEncoding=utf-8
username: root
password: root
masterslave:
# 读写分离配置
load-balance-algorithm-type: round_robin #轮询
# 最终的数据源名称
name: dataSource
# 主库数据源名称
master-data-source-name: master
# 从库数据源名称列表,多个逗号分隔
slave-data-source-names: slave
props:
sql:
show: true #开启SQL显示,默认false
配置解析:
如果不配置该项,项目启动之后将会报错:
报错信息表明,在声明 org.apache.shardingsphere.shardingjdbc.spring.boot 包下的SpringBootConfiguration中的dataSource这个bean时出错, 原因是有一个同名的 dataSource 的bean在com.alibaba.druid.spring.boot.autoconfigure包下的DruidDataSourceAutoConfigure类加载时已经声明了。
而我们需要用到的是 shardingjdbc包下的dataSource,所以我们需要配置上述属性,让后加载的覆盖先加载的。
我们使用shardingjdbc来实现读写分离,直接通过上述简单的配置就可以了。配置完毕之后,我们就可以重启服务,通过postman来访问controller的方法,来完成用户信息的增删改查,我们可以通过debug及日志的方式来查看每一次执行增删改查操作,使用的是哪个数据源,连接的是哪个数据库。
1). 保存数据
控制台输出日志,可以看到操作master主库:
2). 修改数据
控制台输出日志,可以看到操作master主库:
3). 查询数据
控制台输出日志,可以看到操作slave主库:
4). 删除数据
控制台输出日志,可以看到操作master主库:
直接使用我们前面在虚拟机中搭建的主从复制的数据库环境即可。在主库中创建瑞吉外卖项目的业务数据库reggie, 并导入相关表结构和数据(我们可以将自己之前在本地开发时使用的数据库数据导出, 然后导入到服务器中的主库即可)。
1). 将自己本地的reggie数据库的数据导出SQL文件
这样做的话,我们之前自己开发时,添加的测试数据都还在的,便于测试。
2). 在主数据库master中,创建数据库reggie,并导入该SQL文件
master中创建数据库,会自动同步至slave从库
在master的reggie中导入sql文件
目前默认git中有两个分支master 和 v1.0 ,我们接下来进行读写分离的优化,就不在master和v1.0分支来操作了,我们需要在git上创建一个单独的分支v1.1,读写分离的优化,我们就在该分支上进行操作。具体创建分支的操作,和前面演示的一致。
当前创建的v1.1分支,是基于master分支创建出来的,所以目前master分支的代码, 和v1.1分支的代码是完全一样的,接下来把v1.1的代码也推送至远程仓库。
1). 在项目的pom.xml增加依赖
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC1
2). 在项目的application.yml中配置数据源相关信息
spring:
main:
allow-bean-definition-overriding: true
shardingsphere:
datasource:
names:
master,slave
# 主数据源
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.200.200:3306/reggie?characterEncoding=utf-8
username: root
password: root
# 从数据源
slave:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.200.201:3306/reggie?characterEncoding=utf-8
username: root
password: root
masterslave:
# 读写分离配置
load-balance-algorithm-type: round_robin #轮询
# 最终的数据源名称
name: dataSource
# 主库数据源名称
master-data-source-name: master
# 从库数据源名称列表,多个逗号分隔
slave-data-source-names: slave
props:
sql:
show: true #开启SQL显示,默认false
配置完毕之后,我们启动项目进行测试,直接访问系统管理后台的页面,然后执行相关业务操作,看控制台输出的日志信息即可。
查询操作:
更新操作:
插入操作:
删除操作:
读写分离的功能我们已经实现完毕了,那么接下来,我们就可以将当前分支v1.1代码提交并推送到远程仓库。
然后,再将v1.1的代码,合并到master分支,然后推送至远程仓库。
Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx的网站有:百度、京东、新浪、网易、腾讯、淘宝等。
Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。
官网:nginx news
4.2.1 下载
在Nginx的官网的下载页面中(nginx: download),就展示了当前Nginx版本,并提供了下载的连接。 如下:
在本项目中,我们所学习的Nginx选择的是稳定版本的1.16这个版本,我们可以直接从官网下载,当然在我们的课程资料中也已经提供了该版本的安装包。
4.2.2 安装
1). 安装依赖包
由于nginx是基于c语言开发的,所以需要安装c语言的编译环境,及正则表达式库等第三方依赖库。
yum -y install gcc pcre-devel zlib-devel openssl openssl-devel
2). 下载Nginx安装包
yum install wget
wget https://nginx.org/download/nginx-1.16.1.tar.gz
wget :
wget命令用来从指定的URL下载文件。wget非常稳定,它在带宽很窄的情况下和不稳定网络中有很强的适应性,如果是由于网络的原因下载失败,wget会不断的尝试,直到整个文件下载完毕。如果是服务器打断下载过程,它会再次联到服务器上从停止的地方继续下载。
执行完wget指令后,就会在当前所在目录看到下载下来的文件。
3). 解压nginx压缩包
tar -zxvf nginx-1.16.1.tar.gz
4). 配置Nginx编译环境
cd nginx-1.16.1
./configure --prefix=/usr/local/nginx
说明:
--prefix 指定的目录,就是我们安装Nginx的目录。
5). 编译&安装
make & make install
安装完Nginx后,我们可以切换到Nginx的安装目录(/usr/local/nginx),先来熟悉一下Nginx的目录结构,如下图:
备注:
上述我们用到的一个指令 tree,该指令可以将我们指定的目录以树状结构展示出来。如果没有这个指令,可以通过以下指令进行安装。
yum install tree
重点目录和文件如下:
目录/文件 | 说明 | 备注 |
---|---|---|
conf | 配置文件的存放目录 | |
conf/nginx.conf | Nginx的核心配置文件 | conf下有很多nginx的配置文件,我们主要操作这个核心配置文件 |
html | 存放静态资源(html, css, ) | 部署到Nginx的静态资源都可以放在html目录中 |
logs | 存放nginx日志(访问日志、错误日志等) | |
sbin/nginx | 二进制文件,用于启动、停止Nginx服务 |
Nginx中,我们的二进制可执行文件(nginx)存放在sbin目录下,虽然只有一个可执行文件,但是我们可以通过该指令配合不同的参数达到更加强大的功能。接下来,我们就演示一下Nginx常见指令, 在执行下面的指令时,都需要在/usr/local/nginx/sbin/目录下执行。
1). 查看版本
./nginx -v
2). 检查配置文件
修改了nginx.conf核心配置文件之后,在启动Nginx服务之前,可以先检查一下conf/nginx.conf文件配置的是否有错误,命令如下:
./nginx -t
3). 启动
./nginx
启动之后,我们可以通过ps -ef指令来查看nginx的进程是否存在。
注意: nginx服务启动后,默认就会有两个进程。
启动之后,我们可以直接访问Nginx的80端口, http://192.168.200.200
注意:
要想正常访问Nginx,需要关闭防火墙或开放指定端口号,执行的指令如下:
A. 关闭防火墙
systemctl stop firewalld
B. 开放80端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --reload
4). 停止
./nginx -s stop
停止之后,我们可以查看nginx的进程:
ps -ef|grep nginx
5). 重新加载
当修改了Nginx配置文件后,需要重新加载才能生效,可以使用下面命令重新加载配置文件:
./nginx -s reload
介绍了并安装了Nginx之后,本章节将要讲解的是Nginx的使用,我们主要从以下四个方面进行讲解。
nginx的配置文件(conf/nginx.conf)整体上分为三部分: 全局块、events块、http块。这三块的分别配置什么样的信息呢,看下表:
区域 | 职责 |
---|---|
全局块 | 配置和nginx运行相关的全局配置 |
events块 | 配置和网络连接相关的配置 |
http块 | 配置代理、缓存、日志记录、虚拟主机等配置 |
具体结构图如下:
在全局块、events块以及http块中,我们经常配置的是http块。
在http块中可以包含多个server块,每个server块可以配置多个location块。
6.2.1 介绍
Nginx可以作为静态web服务器来部署静态资源。这里所说的静态资源是指在服务端真实存在,并且能够直接展示的一些文件,比如常见的html页面、css文件、js文件、图片、视频等资源。
相对于Tomcat,Nginx处理静态资源的能力更加高效,所以在生产环境下,一般都会将静态资源部署到Nginx中。
将静态资源部署到Nginx非常简单,只需要将文件复制到Nginx安装目录下的html目录中即可。
server {
listen 80; #监听端口
server_name localhost; #服务器名称
location / { #匹配客户端请求url
root html; #指定静态资源根目录
index index.html; #指定默认首页
}
}
命令 | 解释 |
---|---|
磁盘命令 | |
pwd | 显示当前在哪个目录 |
clear | 清屏 |
ls | 查看目录(-a 显示全部、-l列表形式) |
ls -al | 展示所有("d"开头目录、"-"文件、"|"链接) |
cd .. | 切换到上一层 |
cd / | 切换到系统根目录 |
cd ~ | 切换到用户主目录 |
cd - | 切换到上一个所在目录 |
cd etc | 进入当前目录下得etc |
cd ../root | 进入当前上一级目录 |
文件操作 | |
touch | 创建文件命令 |
echo "内容" > a.txt | 添加内容到文件,会覆盖 |
echo "内容" >> a.txt | 添加内容到文件中,追加尾部 |
cat 文件 | 显示文件内容 |
cat a.txt >> b.txt | a文件追加到b文件 |
echo $变量 | 显示变量的值 |
文件夹操作 | |
mkdir 名称 | 创建名称的目录 |
mv a.txt b.txt | 移动文件a.txt 并改名为b.txt |
mv test tmp | 移动test到tmp |
cp a.txt b.txt | 复制a到b内 |
cp -r ./web/* ./test | 把web下所有文件及子目录复制到test下 |
rm a.txt | 删除当前文件,会询问 |
rm -f a.txt | 直接删除不会询问 |
rm -rf ./test/* | 递归删除test下所有内容 |
find / -name 'java' | 查询java |
find / -name '*redis' | 查找包含redis的 |
目录权限 | |
chmod u=rwx,g=rw,o=r a.txt | 修改文件权限 |
chmod 750 -R | 文件递归授权 |
chmod 777 -R | 文件目录递归授权 |
文件内容浏览 | |
cat a.txt | 查看a.txt文件全部内容 |
cat a.txt >> b.txt | 把a.txt文件输出到b.txt中 |
more 文件名 | 分页查看文件内容 |
less 文件名 | 分页查看文件内容(-N 显示行号、-m百分比)退出是Q |
head 文件 | 查看文件头部 |
tail -f 文件名 | 实时线持续查看文件内容 |
文件内容编辑 | |
vim 文件名 | 进入查看文件 |
文件内命令 | |
Esc切换模式 | 命令模式、编辑模式、底行模式 |
dd | 删除改行 |
yy | 复制当前行 |
p | 粘贴 |
ctrl-f | 整页翻页 |
i、o、a、insert | 进入编辑模式 |
wq | 底行模式下写入并退出 |
q! | 退出不保存 |
wq! | 强制保存并退出 |
set nu | 显示行号 |
set nu! | 取消显示行号 |
:数字 | 定位行号 |
/字符 | 搜索字符(n是下一个、shfit N上一个) |
noh | 清楚高亮 |
压缩命令 | |
tar -zcvf test.tar.gz test | 将test目录打成压缩包,压缩后文件没那个为test.tar.gz |
tar -xvf test.tar.gz | 将test.tar.gz进行解压 |
tar -xvf test.tar.gz -C /usr/local | 解压缩到指定目录 |
zip -r mydata.zip mydata | 压缩mydata目录 |
zip -r ab.zip a b.txt | 把a文件夹和b.txt压缩成为ab.zip |
unzip -d /a/b filename.zip | 将文件解压到/a/b目录内 |
ps -ef | 显示所有进程 |
kill -9 进程id(PID) | 结束进程 |
grep [option] | 匹配正则或者字符串 |
ifconfig | 查看本机网络信息 |
ping | 查看连接状态 |
netstat | 查看本机使用的端口号 |
linux软件都是用C/C++程序开发,所谓源码安装,是直接提供程序源代码,需要自行编译,然后生成目标可执行程序。类似提供的.java文件,需要自己编译.class,然后打包为jar,然后运行。源代码形式的特点:操作复杂、编译时间长、极易出现问题、依赖关系复杂,比较适合于专门做linux系统开发的人员。
绝大多数开源软件都是直接以原码形式发布的
源代码一般会被打成.tar.gz的归档压缩文件
源代码需要编译成为二进制形式之后才能够运行使用
源代码基本编译流程:
1).configure 检查编译环境;
2)make对源代码进行编译;
3)make insall 将生成的可执行文件安装到当前计算机中
RPM 是 LINUX 下的一种软件的可执行程序,你只要安装它就可以了。这种软件安装包通常是一个RPM包(Redhat Linux Packet Manager,就是Redhat的包管理器),后缀是.rpm。RPM是Red Hat公司随Redhat Linux推出了一个软件包管理器,通过它能够更加轻松容易地实现软件的安装。
安装软件:执行rpm -ivh rpm包名,如:rpm -ivh apache-1.3.6.i386.rpm
升级软件: 执行rpm -Uvh rpm包名。
卸载安装: 执行rpm -e rpm包名。
查询软件包的详细信息:执行rpm -qpi rpm包名
查询某个文件是属于那个rpm包的:执行rpm -qf rpm包名
查该软件包会向系统里面写入哪些文件:执行 rpm -qpl rpm包名
一般使用步骤如下:
rpm –i software.rpm(安装);
rpm -e software.rpm(卸载);
rpm –U software.rpm(升级形式安装);
rpm –ivh http://www.linuxcast.net/software.rpm(支持通过http\ftp协议形式安装)
rpm软件包形式的管理虽然方便,但是需要手工解决软件包的依赖关系。很多时候安装一个软件安装一个软件需要安装1个或者多个其他软件,手动解决时,很复杂,yum可以轻松解决这些问题。
yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及CentOS中的软件包管理器,简单理解Yum是rpm的前端程序。它能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软件包,无须繁琐地一次次下载、安装。
yum仓库用来存放所有的现有的.rpm包,当使用yum安装一个rpm包时,需要依赖关系,会自动在仓库中查找依赖软件并安装。仓库可以是本地的,也可以是HTTP、FTP、nfs形式使用的集中地、统一的网络仓库。
其特点总结如下:
自动解决依赖关系
可以对rpm进行分组,基于组进行安装操作
引入仓库概念,支持多个仓库
配置简单
常规使用如下:
# yum install 安装;
# yum remove卸载;
# yum update 升级制定软件
把需要的软件下载到linux主机,在主机上直接本地安装
安装软件介绍
服务/软件 | 端口 | 备注 |
---|---|---|
jdk8 | - | JAVA的编译和运行环境 |
mysql/mariadb | 3306 | 持久化关系型数据库 |
tomcat | 8080 | 服务器 |
nginx | 80 | 反向代理服务器 |
scp 命令上传 (命令是在Windows机器或mac机器上执行)
#scp 源码文件路径 目标文件路径
# 把本地文件上传到服务器 (当前Windows系统目录)
scp ./*.* [email protected]:~/soft
# 把远程服务器用户目录/soft下所有文件,下载到本地
scp [email protected]:~/soft/*.* ./
rpm安装,能自动配置环境变量。
1)查看当前linux系统是否已经安装java
输入 rpm -qa | grep java
如果有已经安装的jdk ,需要使用以下命令删除
2) 卸载JDK
rpm -e --nodeps
3)安装jdk
cd ~/soft
rpm -ivh jdk-8u181-linux-x64.rpm
4)java -version测试是否成功
java -version
展示以下内容代表OK
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎方面,使用XtraDB(英语:XtraDB)来代替MySQL的InnoDB
1)查看CentOS自带的mysql
输入 rpm -qa | grep mysql
2)将自带的mysql卸载
rpm -e --nodeps
3)yum安装
yum -y install mariadb-server
4)启动mysql
systemctl start mariadb
5)设置root密码
注:这只是设置root用户在本机(linux)登录时的密码
mysqladmin -u root password 'root'
6)进入mysql
mysql -u root -p
备注:输入密码:root
进入到数据库的执行命令行里面了。
7) 进入mysql,并执行下面sql
保证密码和本地一致
下面的话在mysql数据库里面里面执行
-- 查看当前的数据库
show databases;
-- 打开mysql
use mysql ;
-- 查看所有表
show tables;
-- 我们不用ipv6的地址,直接把host改为%,表示所有客户端都可以连接;同时设置密码为root
update user set host='%' ,password=password("root") where user='root' and host = '::1' ;
-- 刷新后才能生效
flush privileges;
退出数据库命令操作
exit;
开放端口号
# 开放端口命令
firewall-cmd --zone=public --add-port=3306/tcp --permanent
#重新加载配置
firewall-cmd --reload
测试远程连接
使用数据库客户端,输入VMIP地址,输入Mysql的用户名和密码,如图
1.使用IDEA数据库客户端插件
2.输入数据库连接信息
项目部署需要tomcat , 配置端口号。
下面需要使用uzip命令(根据当前系统情况而定,不是必须),先安装
#获取安装列表
yum list | grep zip/unzip
#提示输入时,请输入y
yum install zip
#提示输入时,请输入y
yum install unzip
解压tomcat压缩包到 /app
目录下
cd ~/soft
#解压缩到当前
unzip apache-tomcat-8.5.47.zip
#移动到 /usr/local下
mv apache-tomcat-8.5.47 /usr/local/
启动apache-tomcat-8.5.47
#确保启动文件有可执行权限,先修改权限
chmod 755 /usr/local/apache-tomcat-8.5.47/bin/*.sh
#启动
/usr/local/apache-tomcat-8.5.47/bin/startup.sh
开放8080端口
# 开端口命令
firewall-cmd --zone=public --add-port=8080/tcp --permanent
#重新加载配置
firewall-cmd --reload
测试tomcat
在浏览器输入:http://192.168.188.128:8080/
1.安装git【源码安装】
cd ~/soft
# 安装依赖环境
yum -y install zlib-devel curl-devel openssl-devel perl cpio expat-devel gettext-devel openssl zlib autoconf tk perl-ExtUtils-MakeMaker
# 解压缩到当前
tar -zxvf git_v2.4.0.tar.gz
# 进入目录
cd git-2.4.0
# 配置并编译
autoconf
# 检验相关依赖,设置安装路径
./configure --prefix=/usr/local/git
make && make install
默认安装在 /usr/local/bin,把/usr/local/bin放在系统环境变量或当前用户环境变量,操作如下:
路径:/usr/local/git/bin:
vim ~/.bash_profile #加入系统环境变量
source ~/.bash_profile #加载配置文件
git --version #查看版本
备注:这个路径一定写在系统路径的前面,可以覆盖系统默认的git。
2.安装maven【解压缩即可】
# 解压缩到/usr/local下
unzip -d /usr/local apache-maven-3.6.3-bin.zip
# 编辑配置文件,把 /usr/local/apache-maven-3.6.3,添加到系统环境变量
vim ~/.bash_profile #加入系统环境变量
source ~/.bash_profile #加载配置文件
# 查看maven版本
mvn -v
路径:/usr/local/apache-maven-3.6.3
Nginx* (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日,2011年6月1日,nginx 1.0.4发布。
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
安装前准备
#安装Nginx依赖环境,-y表示所有提示默认选择y
#nginx的http模块使用pcre来解析正则表达式,所以需要在linux上安装pcre库:
yum -y install pcre pcre-devel
#nginx使用zlib对http包的内容进行gzip,所以需要在linux上安装zlib库:
yum -y install zlib zlib-devel
#nginx不仅支持http协议,还支持https,所以需要在linux安装openssl库:
yum -y install openssl openssl-devel
# 安装gcc编译环境
yum -y install gcc gcc-c++ autoconf automake make
源码安装
#解压缩nginx
tar -xvf nginx-1.14.2.tar.gz
#进入nginx目录
cd nginx-1.14.2
#安装配置
./configure
#编译
make
# 安装就是把可执行文件复制到/usr/loca/nginx下
make install
> 安装成功之后,就会在/usr/local下多出了一个nginx目录.
- 使用Nginx
```shell
#进入nginx的sbin目录
cd /usr/local/nginx/sbin
#在sbin目录下启动
./nginx
#在sbin目录下停止----需要再用
./nginx -s stop
#在sbin目录下重写加载--需要再用
./nginx -s reload
#修改端口(默认端口80)---需要再用
vim /usr/local/nginx/conf/nginx.conf 配置文件
开端口命令
#开放端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
#重新加载配置
firewall-cmd --reload
#查看是否有nginx的线程是否存在
ps -ef | grep nginx
netstat -an -t -u | grep 80
在浏览器输入:http://192.168.188.128/
解压缩redis
tar -xvf redis-3.2.9.tar.gz -C /usr/local
make命令编译redis的C语言源码
注意:可以把编译后的可执行程序可移动到自定义目录
在redis 目录下创建bin目录,把编译后的服务器、客户端、配置文件copy到此目录下
cd /usr/local/redis-3.2.9
mkdir bin
cp ./src/redis-server ./bin
cp ./src/redis-cli ./bin
cp ./redis.conf ./bin
启动redis服务器
# 进入bin目录
cd bin
# 启动
./redis-server
其它指令和配置
#1. 后台运行 指令后面带 & 代表后台运行
./redis-server &
#2. 运行远程访问
# 使用vi编辑,打开redis.conf文件 (以下是在配置文件中修改)
#==============
# 注释如下这行,目前仅运行127.0.0.1访问
bind 127.0.0.1
# 开启密码访问模式
requirepass pass
# 开启守护进程,允许redis可以后台启动
daemonize yes
#===============
#3. 指定配置文件,启动redis
./redis-server redis.conf
#4. 启动redis客户端和关闭服务器
./redis-cli
./redis-cli shutdown
#5.开放端口
firewall-cmd --zone=public --add-port=6379/tcp --permanent
#重新加载配置
firewall-cmd --reload
#查看是否有nginx的线程是否存在
ps -ef | grep nginx
netstat -an -t -u | grep 6379
部署资料中的SpringBoot项目,部署前先把数据库安装好,然后再把项目的jar包上传到服务器中,然后运行jar包即可。
确认当前数据库状态
systemctl status mariadb
启动数据库
systemctl start mariadb
启动后再次通过systemctl status mariadb
命令查看,确保数据库已经启动
确保数据库已启动后,通过Idea连接此数据库。
注意,此处的连接地址,是虚拟机中CentOS的IP地址
执行资料中提供的sql文件,创建此项目需要的schema
执行后查看连接中的schema,确保执行成功
修改项目中配置文件的数据库和连接地址,修改为虚拟机中数据库的地址
修改后运行项目,确保访问页面可以正常访问数据,访问地址:http://localhost:8080/pages/books.html
执行打包命令,生成jar包
把jar包上传到虚拟机中
进入jar包所在路径,执行java -jar命令
此处java -jar 是前台启动,如果退出窗口的话会关闭java程序
如果需要后台启动需要执行后台启动命令
后台启动命令
nohup java -jar boot_books-1.0-SNAPSHOT.jar &
后台启动并输出日志命令
nohup java -jar boot_books-1.0-SNAPSHOT.jar &> books.log &
输入访问地址,测试程序是否部署成功,访问地址为虚拟机IP地址+端口号+地址
正向代理类似一个中转站,代理内部访问外部资源。
举个例子:
我是一个用户,我访问不了某网站,但是我能访问一个代理服务器,这个代理服务器呢,它能访问那个我不能访问的网站,于是我先连上代理服务器,告诉他我需要那个无法访问网站的内容,代理服务器去取回来,然后返回给我。从那个网站的角度来看,只在代理服务器来取内容的时候有一次记录,有时候并不知道是用户的请求,也隐藏了用户的资料,这取决于代理告不告诉网站。
注意:客户端必须设置正向代理服务器,当然前提是要知道正向代理服务器的IP地址,还有代理程序的端口。
总结来说:正向代理 是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端必须要进行一些特别的设置才能使用正向代理。
正向代理的用途:
1. 访问原来无法访问的资源,如google
2. 可以做缓存,加速访问资源
3. 对客户端访问授权,上网进行认证
4. 代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息
反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。反向代理的作用
保证内网的安全,可以使用反向代理提供防火墙(WAF)功能,阻止web攻击。大型网站,通常将反向代理作为公网访问地址,Web服务器是内网。
负载均衡,通过反向代理服务器来优化网站的负载。当大量客户端请求代理服务器时,反向代理可以集中分发不同用户请求给不同的weab服务器进行处理请求。(本阶段不实现,负载均衡技术项目阶段讲解)
修改配置文件
vim /usr/local/nginx/conf/nginx.conf
以下是被修订过的nginx.conf,将所有访问到nginx80端口的路径是/开头的请求,都转发到webcase代表的反向代理机群,默认是请求其中一台。
http{
upstream bookssm{
server 127.0.0.1:8080;
#server 192.168.200.129:8080;
}
server {
listen 80;
server_name localhost;
location / {
root html;
#proxy_pass http://192.168.200.138:8080
proxy_pass http://bookssm;
index index.html index.htm;
}
}
}
http块 一个http处理模块,可进行http的相关参数配置,内可以包含多个server块;
upstream块 配置反向代理及负载均衡,可以写多个upstream块,是定义在server块前面。
server localhost:8080; localhost可以指向网络任何一台主机。
server块 包含在http{}内部,每一个server{}都是一个虚拟主机(站点)监听
listen 监听端口
server_name 用于与http请求header头部的Host匹配
location 路径配置,符合某个路径执行块内规则
/ 代表根下资源
root html 是根下的资源,可以从html目录获取。
index 默认页面(不输入网页时,默认访问页)
proxy_pass 反向代理,请求转发给 webcase所代表的主机群
重启服务器
/usr/local/nginx/sbin/nginx -s reload
测试访问
pwd 显示当前在哪个目录
clear 清屏
ls:查看目录
参数 -a 显示全部,包含隐藏
参数 -l 列表形式显示
ls -l 列表展示
“d”开头是目录,
“-” 开头是文件,
“l” 开头是链接文件
ls -a 查看隐藏文件
. 开头的是隐藏文件或目录
ls -la 列表展示,包含隐藏文件 简写命令是 ll -a 。
cd usr 切换到该目录下usr目录
cd .. 切换到上一层目录
cd / 切换到系统根目录
cd ~ (波浪号 tilde) 切换到用户主目录
cd - 切换到上一个所在目录
注意:
绝对路径: 从根开始的,都称为绝对路径
cd /etc: 进入根目录下的etc
相对路径:从当前开始的,都称为相对路径
cd etc: 进入当前目录下的etc :
cd ./etc 同上
cd ../root 进入当前上一级目录 ,.. 代表上一级目录
输入目录时,使用tab,系统会智能提示
touch:创建新文件命令 touch 文件名 默认创建的空文件。
echo "内容" > a.txt 添加内容到文件,会覆盖
echo "内容" >> a.txt 追加内容到文件,追加到尾部
cat 文件 显示文件内容
cat a.txt >> b.txt a文件追加到b文件
备注:
echo $变量 显示变量的值
linux操作系统命令格式: 命令 -[参数]
mkdir 目录名字 [目录名列表],效果如下:
mkdir a 在当前下创建a
mkdir test/a1 在 test下创建a1
mkdir b c d 在当前下同时创建 b、c、d目录
注意:不能跨级创建子目录
mv 文件或目录名 目标文件或目录名,效果如下:
文件操作 mv a.txt b.txt : b.txt不存在即为重命名,存在会提示是否覆盖
目录操作 mv test tmp :tmp不存在即为重命名,存在为移动效果
文件对目录 mv a.txt ./tmp 移动文件到指定目录
cp [参数] 源文件或目录,目标文件或目录
参数: -r 递归
单文件操作 cp a.txt a.txt.bak 在当前下复制一个文件
多文件操作 cp ./web/* ./test 把web下的所有文件复制到test下
递归操作 cp -r ./web/* ./test 把web下的所有文件及子目录复制到test下
rm [参数] 删除文件目录命令
参数: -r 递归 -f 忽略询问
rm a.txt 删除当前下的文件,会询问提示
rm -f a.txt 不询问直接删除
rm -rf ./test 递归删除test下的所有内容,包含test本身
rm -rf ./test/* 递归删除test下的所有内容,但是test不删除
注意:删除一个目录,必须是rm -rf,否则不能删除
find 搜索位置 -name 字符串
find / - name 'java' 查java
find / -name '*redis' 查找含有redis的
权限是Linux中的重要概念,每个文件/目录等都具有权限,通过ls -l命令我们可以 查看某个目录下的文件或目录的权限
示例:在随意某个目录下ls -l
文件的类型:
d:代表目录
-:代表文件
l:代表链接(可以认为是window中的快捷方式)
后面的9位分为3组,每3位置一组,分别代表属主的权限,与当前用户同组的 用户的权限,其他用户的权限
r:代表权限是可读,r也可以用数字4表示
w:代表权限是可写,w也可以用数字2表示
x:代表权限是可执行,x也可以用数字1表示
语法:chmod 数字或符号权限 [参数] 文件或目录
chmod u=rwx,g=rw,o=r aaa.txt
chmod 750 -R 文件或目录名 递归授权
chmod 755 文件或目录
chmod 777 -R 文件或目录
cat命令 查看文件,只能显示文件最后一屏
cat a.txt 查看文件全部内容
注意:
cat除了查看文件内容,还可以把文件内容进行合并
cat a.txt >> b.txt 把a.txt文件输出到b.txt中
比如:
echo 'aaa' > a.txt
echo 'bbb' > b.txt
cat a.txt >> b.txt
more命令查询文件:分页查看所有内容,带百分比
显示文件百分比,回车下一行,空格下一页,退出是Q
less命令查看文件:分页查看所有内容,带行号和百分比
箭头上下代表上一行,下一行,空格显示下一页,退出是Q
-N(大写) 显示行号
-m 百分比
head/tail命令查看文件,支持显示的文件行数
head 查看文件头部 内容
tail 查看文件尾部内容
-n 数字 代表行数
-f 实时持续查看文件内容
vim:文件名
适合快速修改纯文本文件,比如配置文件、属性文件、源文件等
vim编辑器有三种模式
命令模式、编辑模式、底行模式,按ESC,退出当前模式,进入命令模式。
命令模式
刚刚进入是命令模式,从命令模式可进入编辑模式或底行模式。
只接受命令关键字 其他字符不接受,通过输入相应的命令可以进入编辑模式
dd:删除当前行
yy:复制当前行
p:粘贴
整页翻页 ctrl-f、 f是forword , ctrl-b b就是backward
shift+$是移动到行尾,0是移动到行首
编辑模式
进入编辑模式命令:i,o,a或者insert
对文件进行内容编辑 任何字符都接受,内容编辑完毕之后 需要退回命令模式
退回到命令模式,按ESC键
底行模式
在命令模式下,输入冒号 : ,进入底行模式。
底行命令:
:wq,写入并退出,
:q! ,退出不保存
:set nu,显示行号
:set nu!,取消行号显示
:数字,定位行号
:/ 搜索字符,n是下一个,N是上一个
:noh 清除搜索高亮显示
vim编辑器使用过程关于vim使用过程:
vim 文件-------->命令模式--------->输入i---------->编辑模式----------->编辑文件----------->按下Esc--------->命令模式--------->按下:---------->底行模式----------->输入wq保存并退出/q!强制退出不保存
Linux中的打包文件一般是以.tar结尾的,压缩的命令一般是以.gz结尾的。而一般情况下打包和压缩是一起进行的,打包并压缩后的文件的后缀名一般.tar.gz。
参数:-z 调用gzip压缩命令压缩
参数:-c 打包文件
参数:-C 在指定的目录解压缩
参数:-v 显示命令的执行过程
参数:-f 指定文件名
参数:-x 解压缩
示例:将test目录打成压缩包,压缩后文件名为 test.tar.gz
tar -zcvf test.tar.gz test
示例:将test.tar.gz进行解压缩
tar -xvf test.tar.gz
tar -xvf test.tar.gz -C /usr/local 解压缩到指定的目录
zip -r mydata.zip mydata #压缩mydata目录
zip -r abc123.zip abc 123.txt #把abc文件夹和123.txt压缩成为abc123.zip
unzip -d /a/b filename.zip 将文件解压缩到/a/b目录里面
ps命令:查看进程
参数:-e 显示所有程序
参数:-f 显示UID,PPIP
ps -ef 显示所有进程
UID :程序被该 UID(用户ID) 所拥有
PID :就是这个程序的 ID
PPID :则是其上级父程序的ID**
C :CPU使用的资源百分比**
STIME :系统启动时间**
TTY :登入者的终端机位置**
TIME :使用掉的CPU时间。**
CMD :所下达的是什么指令**
kill命令:结束进程
参数:-9 强制杀死该进程
grep [option] 字符串或正则表达式 文件名
从指定文件,搜索匹配的字符串
-i 忽略大小写
示例:
grep -i test /etc/sudo.conf 中包含字符串“test”的内容,且忽略大小写
grep '^d' /etc/sudo.conf 查找以d开头的数据
A命令 |B命令 | C命令
将前一个命令的输出作为下一个命令的输入
可以任意组合,只要是上一级有内容输出,下一个管道就可以处理
ll | grep '^d' | grep '.d$'| grep '4月'
find / -name '*.log' | grep 'tomcat'
查看IP
ifconfig 查看本机网络卡信息
测试网络
ping 查看与某台主机的连接情况
查看端口
netstat 查看本机被使用的端口号
参数:-a 显示所有连接
参数:-n 以网络IP地址代替名称
-t 显示tcp, -u 显示udp连接情况
常用
netstat -an -t -u | grep '8080'
lsof -i tcp:3306
重启 reboot
关机 halt | shutdown
iptables是linux 系统自带的优秀且完全免费的基于包过滤的防火墙工具、它的功能十分强大、使用非常灵活、可以对流入、流出及流经服务器的数据包进行精细的控制。特别是它可以在一台非常低配置下跑的非常好。 centos系统,默认仅仅开放了22端口,其他端口需要使用iptables进行管理(开放、删除、保存规则等)
安装iptables
yum install iptables-services
service iptables save
配置开机启动
把启动防火墙服务的命令,加入到开机启动的配置文件中即可。
vim /etc/profile
查看与删除iptables中放行的规则
#查看iptables列表,显示列表编号
iptables -L -n --line-number
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080
2 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306
3 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
4 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
#删除iptables列表中 编号为1的规则
iptables -D INPUT 1
yum命令安装
yum -y install mysql-community-server
如果出现如图所示,请参考【手动获取rpm文件】:
需要下载205M的资源,需要根据网络情况,等待比较久的时间。
安装完毕如下:
手动获取rpm文件安装
在线获取rpm包
wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
安装下载的rpm文件
rpm -ivh mysql-community-release-el7-5.noarch.rpm
安装mysql-server
yum install mysql-server
启动mysql服务
service mysqld start
查看初始密码【5.7版本执行如下命令,5.6版本,默认密码是空】
grep "password" /var/log/mysqld.log
登录mysql
mysql -u root -p
输入初始密码,可以复制密码,并粘贴到输入密码的位置
设置root密码
修改安全策略 (mysql5.7不允许设置比较简单的密码策略)
set global validate_password_policy=0;
set global validate_password_length=1;
2. 设置密码: set password = password('123456');
3. 授权远程连接
默认情况下mysql为安全起见,不支持远程登录mysql,所以需要设置开启远程登录mysql的权限
grant all privileges on *.* to 'root' @'%' identified by '123456';
flush privileges;
SET PASSWORD FOR 'root'@'%'= PASSWORD('123456');
tar -xvf 解开压缩包到指定目录
tar -xvf jdk-8u211-linux-x64.tar.gz -C /usr/local
编辑配置文件,并配置环境变量
全局配置或当前用户配置,二选一即可。
全局配置文件: vim /etc/profile 或 用户配置文件 vim ~/.bash_profile 推荐前者。
vim /etc/profile
将以下代码复制到profile文件中的末尾。
#set java environment
JAVA_HOME=/usr/local/jdk1.8.0_211/
CLASSPATH=.:$JAVA_HOME/lib.tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
保存并退出
加载环境变量
source /etc/profile 或 source .bash_profile ,推荐前者。
source /etc/profile
不出现任何提示,说明环境加载成功。
测试环境
输入 java或javac ,出现如下提示即为环境配置成功
如果出现:
1. 拉取代码
在Git仓库平台增加服务端的ssh公钥
在服务端机器生成密钥对,使用ssh命令,生成的密钥默认放在用户目录的.ssh目录。
#生成密钥,输入完成命令,默认回车即可。
ssh-keygen -t rsa -C "[email protected]"
# 查看用户目录下的隐藏目录
ls -a ~/
# 查看.ssh目录下的密钥
ls ~/.ssh/
# 查看公钥信息
cat .ssh/id_rsa.pub
-C "[email protected]" 如果省略默认是当前主机名称
复制生成后的 ssh key,通过仓库主页 「管理」->「部署公钥管理」->「添加部署公钥」 ,添加生成的 public key 添加到仓库中。
使用SSH方式,克隆Git仓库代码
cd ~ #切换到用户目录
git clone [email protected]:mobapp/webcase.git
cd ~/webcase
#git clone [email protected]:mobapp/study_springmvc_ssm.git #SSH方式克隆代码
#cd study_springmvc_ssm # 进入项目根目录
git branch # 查看当前分支,默认是master分支
git pull # 拉取最新代码 [第1次不用]
git checkout master # 切换到主分支 [第1次不用]
2. 项目打包
使用mvn命令,自动打包当前项目,默认生成在工程目录的target下
cd ~/webcase
mvn clean package -Dmaven.test.skip=true
备注:第1次打包,会非常慢,因为需要下载依赖库,可以把本地已经下载好的仓库直接放在用户目录的.m2下。
1.上传本地maven仓库到服务器m2目录下
2.解压缩本地仓库
cd ~/.m2
unzip -o repository
备注:-o 覆盖解压缩
3.重新打包
cd ~/webcase
mvn clean package -Dmaven.test.skip=true
3. 项目部署
把War把部署到Tomcat
把生成的war包移动或复制到tomcat webapps目录下即可,注意文件名就是应用的名称。
# 把war包copy到webapp是目录下,并取名为springssm.war
# \cp 是强制覆盖,一般第2次部署时,是不需要确认的,直接覆盖
# cp 如果遇到重名,会提示覆盖
#\cp ~/study_springmvc_ssm/target/springmvc_ssm.war /usr/local/apache-tomcat-8.5.47/webapps/springssm.war
\cp ./target/webcase.war /usr/local/apache-tomcat-8.5.47/webapps/
#启动Tomcat 默认不用重启是可以的
/usr/local/apache-tomcat-8.5.47/bin/startup.sh
# 查看访问日志
tail -f /usr/local/apache-tomcat-8.5.47/logs/localhost_access_log.2022-04-24.txt
访问测试
http://192.168.200.138:8080/webcase/login.html
1. 拉取代码
cd ~ #切换到用户目录
git clone [email protected]:mobapp/spring-boot-mybatis.git #SSH方式克隆代码
cd spring-boot-mybatis # 进入项目根目录
git branch # 查看当前分支,默认是master分支
git pull # 拉取最新代码 [第1次不用]
git checkout master # 切换到主分支 [第1次不用]
2. 项目打包
mvn clean package -Dmaven.test.skip=true
3. 项目启动
启动mysql数据库【前面已启动】
安装项目数据库【前面已安装,本项目与之前项目用的同一数据库】
初始化项目的工作目录
# 在当前创建工作目录
mkdir ~/springmvcboot
# 进入工作目录
cd ~/springmvcboot
启动项目
# 强制负责编译之后的jar包到工作目录
\cp ~/spring-boot-mybatis/target/springboot_ssm.jar ~/springmvcboot
# 后台启动boot项目
nohup java -jar springboot_ssm.jar --server.port=8088 --spring.profiles.active=pro >springboot_ssm_out.log 2>&1 &
# 查看启动日志
tail -f springboot_ssm_out.log
# 开放端口
firewall-cmd --zone=public --add-port=6379/tcp --permanent
#重新加载配置
firewall-cmd --reload
nohup:不挂断地运行命令,退出帐户之后继续运行相应的进程。
springboot_ssm_out.log:是nohup把command的输出重定向到当前目录的指定的文件中.
即输出内容不打印到屏幕上,而是输出到”日志文件名.log”文件中。
2>&1 2就是标准错误,1是标准输出
该命令相当于把标准错误重定向到标准输出么。这里&相当于标准错误等效于标准输出,即把标准错误和标准输出同时输出到指定的“日志文件名.log”文件中。
访问测试
http://192.168.200.138:8088/user/queryAll
注意boot项目,默认是发布在web的根目录下的。SSM项目只要发布到webapps/ROOT下才发布到根目录
部署之前的综合案例,部署前先把数据库安装好,然后再把项目的war包copy到tomcat安装目录即可。
1. 初始化项目数据库
msyql客户端工具连接VM中的mysql
在客户端工具中初始化数据库脚本
CREATE SCHEMA `ssm_db` DEFAULT CHARACTER SET utf8mb4;
use `ssm_db`;
-- ----------------------------
-- Table structure for tbl_book
-- ----------------------------
DROP TABLE IF EXISTS `tbl_book`;
CREATE TABLE `tbl_book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 13 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of tbl_book
-- ----------------------------
INSERT INTO `tbl_book` VALUES (1, '计算机理论', 'Spring实战 第5版', 'Spring入门经典教程,深入理解Spring原理技术内幕');
INSERT INTO `tbl_book` VALUES (2, '计算机理论', 'Spring 5核心原理与30个类手写实战', '十年沉淀之作,手写Spring精华思想');
INSERT INTO `tbl_book` VALUES (3, '计算机理论', 'Spring 5 设计模式', '深入Spring源码剖析Spring源码中蕴含的10大设计模式');
INSERT INTO `tbl_book` VALUES (4, '计算机理论', 'Spring MVC+MyBatis开发从入门到项目实战', '全方位解析面向Web应用的轻量级框架,带你成为Spring MVC开发高手');
INSERT INTO `tbl_book` VALUES (5, '计算机理论', '轻量级Java Web企业应用实战', '源码级剖析Spring框架,适合已掌握Java基础的读者');
INSERT INTO `tbl_book` VALUES (6, '计算机理论', 'Java核心技术 卷I 基础知识(原书第11版)', 'Core Java 第11版,Jolt大奖获奖作品,针对Java SE9、10、11全面更新');
INSERT INTO `tbl_book` VALUES (7, '计算机理论', '深入理解Java虚拟机', '5个维度全面剖析JVM,大厂面试知识点全覆盖');
INSERT INTO `tbl_book` VALUES (8, '计算机理论', 'Java编程思想(第4版)', 'Java学习必读经典,殿堂级著作!赢得了全球程序员的广泛赞誉');
INSERT INTO `tbl_book` VALUES (9, '计算机理论', '零基础学Java(全彩版)', '零基础自学编程的入门图书,由浅入深,详解Java语言的编程思想和核心技术');
INSERT INTO `tbl_book` VALUES (10, '市场营销', '直播就该这么做:主播高效沟通实战指南', '李子柒、李佳琦、薇娅成长为网红的秘密都在书中');
INSERT INTO `tbl_book` VALUES (11, '市场营销', '直播销讲实战一本通', '和秋叶一起学系列网络营销书籍');
INSERT INTO `tbl_book` VALUES (12, '市场营销', '直播带货:淘宝、天猫直播从新手到高手', '一本教你如何玩转直播的书,10堂课轻松实现带货月入3W+');
以下是使用IDEA,初始化数据库:
2. 部署项目war包
使用IDEA打war包并上传到服务器
打包
上传到服务器(注意:IP写自己的服务器)
停止当前的tomat服务器
/usr/local/apache-tomcat-8.5.47/bin/shutdown.sh
上传war包到tomcat目录的webapps目录下
(注意:IP写自己的服务器)
scp book_ssm.war [email protected]:/app/apache-tomcat-8.5.47/webapps
备注:SCP会自动覆盖之前上传的文件,Tomcat自动解压缩覆盖之前的文件
启动Tomcat服务器
/usr/local/apache-tomcat-8.5.47/bin/startup.sh
浏览器测试
http://192.168.188.128:8080/book_ssm/pages/books-tomcat.html
如果显示不正常,请查看日志:
tail -f /usr/local/apache-tomcat-8.5.47/logs/catalina.out
前后端分离开发
Yapi
Swagger
项目部署
当前项目中,前端代码和后端代码混合在一起,是存在问题的,存在什么问题呢?
主要存在以下几点问题:
1). 开发人员同时负责前端和后端代码开发,分工不明确
2). 开发效率低
3). 前后端代码混合在一个工程中,不便于管理
4). 对开发人员要求高(既会前端,又会后端),人员招聘困难
为了解决上述提到的问题,现在比较主流的开发方式,就是前后端分离开发,前端人员开发前端的代码,后端开发人员开发服务端的业务功能,分工明确,各司其职。我们本章节,就是需要将之前的项目进行优化改造,变成前后端分离开发的项目。
前后端分离开发,就是在项目开发过程中,对于前端代码的开发由专门的前端开发人员负责,后端代码则由后端开发人员负责,这样可以做到分工明确、各司其职,提高开发效率,前后端代码并行开发,可以加快项目开发进度。
目前,前后端分离开发方式已经被越来越多的公司所采用,成为当前项目开发的主流开发方式。
前后端分离开发后,从工程结构上也会发生变化,即前后端代码不再混合在同一个maven工程中,而是分为 前端工程 和 后端工程 。
前后端分离之后,不仅工程结构变化,后期项目上线部署时,与之前也不同:
1). 之前: 前后端代码都混合在一起,我们只需要将前端和后端的代码统一打成jar包,直接运行就可以了。
2). 现在: 拆分为前后端分离的项目后,最终部署时,后端工程会打成一个jar包,运行在Tomcat中(springboot内嵌的tomcat)。前端工程的静态资源,会直接部署在Nginx中进行访问。
前后端分离开发后,面临一个问题,就是前端开发人员和后端开发人员如何进行配合来共同开发一个项目?可以按照如下流程进行:
1). 定制接口: 这里所说的接口不是我们之前在service, mapper层定义的interface; 这里的接口(API接口)就是一个http的请求地址,主要就是去定义:请求路径、请求方式、请求参数、响应数据等内容。(具体接口文档描述的信息, 如上图)
2). 前后端并行开发: 依据定义好的接口信息,前端人员开发前端的代码,服务端人员开发服务端的接口; 在开发中前后端都需要进行测试,后端需要通过对应的工具来进行接口的测试,前端需要根据接口定义的参数进行Mock数据模拟测试。
3). 联调: 当前后端都开发完毕并且自测通过之后,就可以进行前后端的联调测试了,在这一阶段主要就是校验接口的参数格式。
4). 提测: 前后端联调测试通过之后,就可以将项目部署到测试服务器,进行自动化测试了。
1). 开发工具
Visual Studio Code (简称VsCode)
Hbuilder
2). 技术框架
A. Node.js: Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。(类似于java语言中的JDK)。
B. Vue : 目前最火的的一个前端javaScript框架。
C. ElementUI: 一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库,通过ElementUI组件可以快速构建项目页面。
D. Mock: 生成随机数据,拦截 Ajax 请求,前端可以借助于Mock生成测试数据进行功能测试。
E. Webpack: webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler),分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Sass,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
YApi 是高效、易用、功能强大的 api 管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护 API,YApi 还为用户提供了优秀的交互体验,开发人员只需利用平台提供的接口数据写入工具以及简单的点击操作就可以实现接口的管理。
YApi让接口开发更简单高效,让接口的管理更具可读性、可维护性,让团队协作更合理。
源码地址: GitHub - YMFE/yapi: YApi 是一个可本地部署的、打通前后端及QA的、可视化的接口管理平台
官方文档: YApi 接口管理平台
要使用YApi,项目组需要自己进行部署,在本项目中我们可以使用课程提供的平台进行测试。L
域名: https://mock-java.itheima.net/
2.2.1 准备
注册账号,登录平台
2.2.2 定义接口
登录到Yapi平台之后,我们可以创建项目,在项目下创建接口分类,在对应的分类中添加接口。
1). 创建项目
2). 添加分类
在当前项目中,有针对于员工、菜品、套餐、订单的操作,我们在进行接口维护时,可以针对接口进行分类,如果没有对应的分类,我们自己添加分类。
3). 添加接口
接口基本信息录入之后,添加提交,就可以看到该接口的基本信息:
但是目前,接口中我们并未指定请求参数,响应数据等信息,我们可以进一步点击编辑,对该接口 详情进行编辑处理。
4). 运行接口
Yapi也提供了接口测试功能,当我们接口编辑完毕后,后端服务的代码开发完毕,启动服务,就可以使用Yapi进行接口测试了。
注意: 由于菜品分页查询接口,是需要登录后才可以访问的,所以在测试该接口时,需要先请求员工管理接口中的登录接口,登录完成后,再访问该接口。
插件安装(运行时,如果是谷歌浏览器需要安排调试插件):
插件安装,可参考:chrome 安装 yapi 扩展教程 - 掘金,使用的插件已在资料中。
在Yapi平台中,将接口文档定义好了之后,前后端开发人员就需要根据接口文档中关于接口的描述进行前端和后端功能的开发。
2.2.3 导出接口文档
在Yapi平台中我们不仅可以在线阅读文档,还可以将Yapi中维护的文档直接导出来,可以导出md,json,html格式,在导出时自行选择即可 。
而在导出的html文件或md文件中,主要描述的就是接口的基本信息, 包括: 请求路径、请求方式、接口描述、请求参数、返回数据等信息。展示形式如下:
2.2.4 导入接口文档
上述我们讲解了接口文档的导出,我们也可以将外部的接口文档导入到Yapi的平台中,这样我们就不用一个接口一个接口的添加了。我们可以将课程资料中提供的json格式的接口文档直接导入Yapi平台中来。
导入过程中出现的确认弹窗,选择"确认"。
导入成功之后,我们就可以在Yapi平台查看到已导入的接口。
官网:API Documentation & Design Tools for Teams | Swagger
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。功能主要包含以下几点:
A. 使得前后端分离开发更加方便,有利于团队协作
B. 接口文档在线自动生成,降低后端开发人员编写接口文档的负担
C. 接口功能测试
使用Swagger只需要按照它的规范去定义接口及接口相关的信息,再通过Swagger衍生出来的一系列项目和工具,就可以做到生成各种格式的接口文档,以及在线接口调试页面等等。
直接使用Swagger, 需要按照Swagger的规范定义接口, 实际上就是编写Json文件,编写起来比较繁琐、并不方便, 。而在项目中使用,我们一般会选择一些现成的框架来简化文档的编写,而这些框架是基于Swagger的,如knife4j。knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。而我们要使用kinfe4j,需要在pom.xml中引入如下依赖即可:
com.github.xiaoymin
knife4j-spring-boot-starter
3.0.2
接下来,我们就将我们的项目集成Knife4j,来自动生成接口文档。这里我们还是需要再创建一个新的分支v1.2,在该分支中进行knife4j的集成,集成测试完毕之后,没有问题,我们再将v1.2分支合并到master。
使用knife4j,主要需要操作以下几步:
1). 导入knife4j的maven坐标
com.github.xiaoymin
knife4j-spring-boot-starter
3.0.2
2). 导入knife4j相关配置类并设置静态资源访问
这里我们就不需要再创建一个新的配置类了,我们直接在WebMvcConfig配置类中声明即可。
A. 在该配置类中加上两个注解 @EnableSwagger2 @EnableKnife4j ,开启Swagger和Knife4j的功能。
B. 在配置类中声明一个Docket类型的bean, 通过该bean来指定生成文档的信息。
C. 由于Swagger生成的在线文档中,涉及到很多静态资源,这些静态资源需要添加静态资源映射,否则接口文档页面无法访问。因此需要在 WebMvcConfig类中的addResourceHandlers方法中增加如下配置。
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.List;
@Slf4j
@Configuration
@EnableSwagger2
@EnableKnife4j
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Autowired
private ObjectMapper objectMapper;
/**
* 设置静态资源映射
* 由于Swagger生成的在线文档中,涉及到很多静态资源,这些静态资源需要添加静态资源映射,否则接口文档页面无法访问。因此需要在 WebMvcConfig类中的addResourceHandlers方法中增加如下配置。
* @param registry
*/
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
log.info("开始进行静态资源映射...");
registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
/**
* 扩展mvc框架的消息转换器
* @param converters
*/
@Override
protected void extendMessageConverters(List> converters) {
log.info("扩展消息转换器...");
//创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,底层使用Jackson将Java对象转为json
//messageConverter.setObjectMapper(new JacksonObjectMapper());
messageConverter.setObjectMapper(objectMapper);
//将上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0,messageConverter);
}
@Bean
public Docket createRestApi() {
// 文档类型
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.itheima.reggie.controller"))
.paths(PathSelectors.any())
.build();
}
// // springfox.documentation.service.ApiInfo
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("瑞吉外卖")
.version("1.0")
.description("瑞吉外卖接口文档")
.build();
}
}
注意: Docket声明时,指定的有一个包扫描的路径,该路径指定的是Controller所在包的路径。因为Swagger在生成接口文档时,就是根据这里指定的包路径,自动的扫描该包下的@Controller, @RestController, @RequestMapping等SpringMVC的注解,依据这些注解来生成对应的接口文档。
3). 在LoginCheckFilter中设置不需要处理的请求路径
需要将Swagger及Knife4j相关的静态资源直接放行,无需登录即可访问,否则我们就需要登录之后,才可以访问接口文档的页面。
在原有的不需要处理的请求路径中,再增加如下链接:
"/doc.html",
"/webjars/**",
"/swagger-resources",
"/v2/api-docs"
经过上面的集成配置之后,我们的项目集成Swagger及Knife4j就已经完成了,接下来我们可以重新启动项目,访问接口文档,访问链接为: http://localhost:8080/doc.html
我们可以看到,在所有的Controller中提供的所有的业务增删改查的接口,全部都已经自动生成了,我们通过接口文档可以看到请求的url、请求方式、请求参数、请求实例、响应的参数,响应的示例。 并且呢,我们也可以通过这份在线的接口文档,对接口进行测试。
注意: 由于我们服务端的Controller中的业务增删改查的方法,都是必须登录之后才可以访问的,所以,我们在测试时候,也是需要先访问登录接口。登录完成之后,我们可以再访问其他接口进行测试。
我们不仅可以在浏览器浏览生成的接口文档,Knife4j还支持离线文档,对接口文档进行下载,支持下载的格式有:markdown、html、word、openApi。
3.4.1 问题说明
在上面我们直接访问Knife4j的接口文档页面,可以查看到所有的接口文档信息,但是我们发现,这些接口文档分类及接口描述都是Controller的类名(驼峰命名转换而来)及方法名,而且在接口文档中,所有的请求参数,响应数据,都没有中文的描述,并不知道里面参数的含义,接口文档的可读性很差。
3.4.2 注解介绍
为了解决上述的问题,Swagger提供了很多的注解,通过这些注解,我们可以更好更清晰的描述我们的接口,包含接口的请求参数、响应数据、数据模型等。核心的注解,主要包含以下几个:
注解 | 位置 | 说明 |
---|---|---|
@Api | 类 | 加载Controller类上,表示对类的说明 |
@ApiModel | 类(通常是实体类) | 描述实体类的作用 |
@ApiModelProperty | 属性 | 描述实体类的属性 |
@ApiOperation | 方法 | 说明方法的用途、作用 |
@ApiImplicitParams | 方法 | 表示一组参数说明 |
@ApiImplicitParam | 方法 | 用在@ApiImplicitParams注解中,指定一个请求参数的各个方面的属性 |
3.4.3 注解测试
1). 实体类
可以通过 @ApiModel , @ApiModelProperty 来描述实体类及属性
@Data
@ApiModel("套餐")
public class Setmeal implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键")
private Long id;
//分类id
@ApiModelProperty("分类id")
private Long categoryId;
//套餐名称
@ApiModelProperty("套餐名称")
private String name;
//套餐价格
@ApiModelProperty("套餐价格")
private BigDecimal price;
//状态 0:停用 1:启用
@ApiModelProperty("状态")
private Integer status;
//编码
@ApiModelProperty("套餐编号")
private String code;
//描述信息
@ApiModelProperty("描述信息")
private String description;
//图片
@ApiModelProperty("图片")
private String image;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
2). 响应实体R
@Data
@ApiModel("返回结果")
public class R<T> implements Serializable{
@ApiModelProperty("编码")
private Integer code; //编码:1成功,0和其它数字为失败
@ApiModelProperty("错误信息")
private String msg; //错误信息
@ApiModelProperty("数据")
private T data; //数据
@ApiModelProperty("动态数据")
private Map map = new HashMap(); //动态数据
//省略静态方法 ....
}
3). Controller类及其中的方法
描述Controller、方法及其方法参数,可以通过注解: @Api, @APIOperation, @ApiImplicitParams, @ApiImplicitParam
@RestController
@RequestMapping("/setmeal")
@Slf4j
@Api(tags = "套餐相关接口")
public class SetmealController {
@Autowired
private SetmealService setmealService;
@Autowired
private CategoryService categoryService;
@Autowired
private SetmealDishService setmealDishService;
/**
* 新增套餐
* @param setmealDto
* @return
*/
@PostMapping
@CacheEvict(value = "setmealCache",allEntries = true)
@ApiOperation(value = "新增套餐接口")
public R<String> save(@RequestBody SetmealDto setmealDto){
log.info("套餐信息:{}",setmealDto);
setmealService.saveWithDish(setmealDto);
return R.success("新增套餐成功");
}
/**
* 套餐分页查询
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
@ApiOperation(value = "套餐分页查询接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "page",value = "页码",required = true),
@ApiImplicitParam(name = "pageSize",value = "每页记录数",required = true),
@ApiImplicitParam(name = "name",value = "套餐名称",required = false)
})
public R<Page> page(int page,int pageSize,String name){
//分页构造器对象
Page<Setmeal> pageInfo = new Page<>(page,pageSize);
Page<SetmealDto> dtoPage = new Page<>();
LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
//添加查询条件,根据name进行like模糊查询
queryWrapper.like(name != null,Setmeal::getName,name);
//添加排序条件,根据更新时间降序排列
queryWrapper.orderByDesc(Setmeal::getUpdateTime);
setmealService.page(pageInfo,queryWrapper);
//对象拷贝
BeanUtils.copyProperties(pageInfo,dtoPage,"records");
List<Setmeal> records = pageInfo.getRecords();
List<SetmealDto> list = records.stream().map((item) -> {
SetmealDto setmealDto = new SetmealDto();
//对象拷贝
BeanUtils.copyProperties(item,setmealDto);
//分类id
Long categoryId = item.getCategoryId();
//根据分类id查询分类对象
Category category = categoryService.getById(categoryId);
if(category != null){
//分类名称
String categoryName = category.getName();
setmealDto.setCategoryName(categoryName);
}
return setmealDto;
}).collect(Collectors.toList());
dtoPage.setRecords(list);
return R.success(dtoPage);
}
/**
* 删除套餐
* @param ids
* @return
*/
@DeleteMapping
@CacheEvict(value = "setmealCache",allEntries = true)
@ApiOperation(value = "套餐删除接口")
public R<String> delete(@RequestParam List<Long> ids){
log.info("ids:{}",ids);
setmealService.removeWithDish(ids);
return R.success("套餐数据删除成功");
}
/**
* 根据条件查询套餐数据
* @param setmeal
* @return
*/
@GetMapping("/list")
@Cacheable(value = "setmealCache",key = "#setmeal.categoryId + '_' + #setmeal.status")
@ApiOperation(value = "套餐条件查询接口")
public R<List<Setmeal>> list(Setmeal setmeal){
LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(setmeal.getCategoryId() != null,Setmeal::getCategoryId,setmeal.getCategoryId());
queryWrapper.eq(setmeal.getStatus() != null,Setmeal::getStatus,setmeal.getStatus());
queryWrapper.orderByDesc(Setmeal::getUpdateTime);
List<Setmeal> list = setmealService.list(queryWrapper);
return R.success(list);
}
}
4). 重启服务测试
我们上述通过Swagger的注解,对实体类及实体类中的属性,以及Controller和Controller的方法进行描述,接下来,我们重新启动服务,然后看一下自动生成的接口文档有何变化。
在接口文档的页面中,我们可以看到接口的中文描述,清晰的看到每一个接口是做什么的,接口方法参数什么含义,参数是否是必填的,响应结果的参数是什么含义等,都可以清楚的描述出来。
总之,我们要想清晰的描述一个接口,就需要借助于Swagger给我们提供的注解。
在本章节,我们要做的是项目的部署,包含前端项目的部署,及后端项目的部署。
PC端: 主要是为餐厅的员工及管理员使用的后台管理系统,对分类、菜品、套餐信息进行维护。
移动端: 可以基于微信公众号或小程序实现,我们课上并未实现,这部分的工作是前端开发人员需要开发的。
防火墙:硬件产品,让访问服务器更加安全
前端部署服务器: Nginx(反向代理)
后端部署服务器: 项目部署服务器
具体的服务器的软件安装如下:
服务器 | 软件 | 名称 |
---|---|---|
Nginx服务器 | Nginx(部署前端项目、配置反向代理) | |
项目部署服务器 | JDK1.8、Git、Maven | |
数据库服务器 | MySQL数据库 | |
Redis服务器 | Redis(缓存中间件) |
以上需要的软件安装,可以参考
1). 在服务器A中安装Nginx,将课程资料中的静态资源目录上传到Nginx的html目录下
将整个目录上传至/usr/local/nginx/html目录下
上传完成后,如图所示
执行解压缩命令
unzip html.zip
2). 修改Nginx配置文件nginx.conf
将nginx.conf配置文件中,将原有的监听80, 82, 8080端口号 的虚拟主机注释掉,引入如下的配置信息:
upstream boot{
# 200.1 宿主机
server 192.168.200.138:8080;
#server 192.168.200.129:8080;
}
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html;
}
# http://192.168.188.128/api/employee/login
# 会被这个配置拦截住
location ^~ /api/ {
# 重定向的操作
# /employee/login
rewrite ^/api/(.*)$ /$1 break;
# http://192.168.200.138:8080/employee/login
proxy_pass http://boot;
}
location = /50x.html {
root html;
}
}
3). 通过nginx访问前端工程
http://192.168.200.138/backend/page/login/login.html
前端工程部署完成之后,我们可以正常的访问到系统的登录页面,点击登录按钮,可以看到服务端发起的请求,请求信息如下:
而大家知道,在我们之前开发的工程中,是没有/api这个前缀的,那这个时候,在不修改服务端代码的情况下,如何处理该请求呢?
实际上,通过nginx的就可以轻松解决这个问题。
在上述我们配置的nginx.conf中,除了配置了静态资源的加载目录以外,我们还配置了一段反向代理的配置,配置信息如下:
upstream boot{
# 200.1 宿主机
server 192.168.200.138:8080;
#server 192.168.200.129:8080;
}
location ^~ /api/ {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://boot;
}
这一段配置代表,如果请求当前nginx,并且请求的路径如果是 /api/ 开头,将会被该location处理。而在该location中,主要配置了两块儿信息: rewrite(url重写) 和 proxy_pass(反向代理)。 接下来我们就来解析一下这两项的配置。
1). 路径重写rewrite
rewrite ^/api/(.*)$ /$1 break;
这里写的是一个正则表达式,代表如果请求路径是以 /api/
开头,后面的请求路径任意,此时将原始的url路径重写为 /$1
,这里的$1
指代的就是通配符 .* 这一块的内容。比如:
/api/employee/login ------> ^/api/(.*)$ --------> 此时 (.*) 匹配的就是 employee/login ------> 最终重写为/$1 : /employee/login
2). 反向代理
proxy_pass http://boot;
boot是一个虚拟名称的代表,代表是就是前面定义的upstream boot 。boot 代表是一个机器的集群。可以根据负载策略随机选择一台。如果仅有一台直接转发到这台主机。
路径重写后的请求,将会转发到后端的 http://192.168.200.138:8080 服务器中。
SpringBoot项目部署的核心思路与步骤:
环境安装:部署环境的安装
拉取代码:通过git命令,克隆并拉取仓库的代码,默认是master分支(发布时都用此分支)
编译打包:通过maven命令,对项目代码进行编译打包,输出jar包
启动项目:把输出的jar包复制到工作目录(运维人员指定的目录),并在后台启动。
测试后端接口:使用postman测试接口是否正常访问。
脚本部署与发布:如果经常修改项目,需要重新打包上线,建议直接使用脚本
1.环境安装
A. 确认JDK环境
B. 确认Git环境
C. 确认Maven环境
2.拉取代码
# 进入用户目录
cd ~
# 克隆代码 ,克隆后默认检查的master分支
git clone git@gitee.com:mobapp/reggie_take_out.git
# 进入项目目录
cd ~/reggie_take_out
# 拉取代码(第1次克隆后,已经拉取过了,可以不执行)
git pull
如果克隆时出现如下提示:
说明需要把把当前服务器的SSH公钥放在gitee服务器上,才可以通过SSH协议拉取仓库的代码。
3.编译项目
1.进入仓库目录根目录,执行编译命令
# 进入项目目录
cd ~/reggie_take_out
mvn clean package -Dmaven.test.skip=true
正常编译如下:
备注:在执行mvn打包时,需要下载项目用的依赖仓库,如果网速很慢,这个过程会花费很长时间,如图所示:
建议ctrl+c强行终止,然后把本地的maven仓库或提供的mvn仓库,上传到服务器mvn默认仓库。
2.解压缩mvn仓库(编译失败,才执行此步骤)
mvn默认仓库是在用户目录下,以.m2开头
把git仓库放在.m2下
cd ~/soft
# 解压到当前目录
unzip git仓库.zip
# 把解压的文件复制到 .m2下
cp -rf ./git仓库/*.* ~/.m2/
解压缩上传的仓库,覆盖默认仓库
cd ~/.m2
unzip -o repository.zip
4.启动项目
启动之前先启动nginx、mysql、redis
备注:mysql数据库,需要安装reggie项目;redis暂时可以远程连接。
创建工作目录,把jar复制到工作目录
cd ~/
mkdir reggie_project
# reggie_take_out目录与自己的项目对应
# reggie_take_out-1.0-SNAPSHOT.jar文件 与自己的项目对应
\cp ~/reggie_take_out/target/reggie_take_out-1.0-SNAPSHOT.jar ~/reggie_project/
后台启动jar包
cd ~/reggie_project/
#reggie_take_out-1.0-SNAPSHOT.jar 与自己的项目名称对应
nohup java -jar reggie_take_out-1.0-SNAPSHOT.jar &> reggie_take_out.log &
# 查看启动日志
tail -f reggie_take_out.log
5.测试后端接口
测试登录
测试发送验证码(主要是测试Redis)
nohup java -jar -Dspring.profiles.active=pro reggie_take_out-1.0-SNAPSHOT.jar &> reggie_take_out.log &
6.脚本部署与发布
1.把脚本上传到工作目录
将资料中提供的start-reggie.sh和stop-reggie.sh文件上传到服务器工作目录
备注:.sh文件的将多个命令合并在一起的批处理命令。
2.设置脚本执行权限
cd ~/reggie_project/
chmod 755 *.sh
3) 执行start-reggie.sh脚本文件,自动部署项目
执行完shell脚本之后,我们可以通过 ps -ef|grep java 指令,查看服务是否启动。
查看启动日志
tail -f reggie_take_out.log
4). 访问系统测试
http://192.168.200.138/backend/page/login/login.html
在上述的测试中,我们发现菜品的图片无法正常展示。原因是因为,在我们的配置文件中,图片信息依然是从 D:/img 中加载的,但是在Linux服务器中,是不存在D盘的。
1). 修改文件存储目录,并提交代码
将文件存储目录修改为:
reggie:
path: /usr/local/img/
2). 执行shell脚本,进行自动化部署
3).访问测试
http://192.168.200.138/backend/index.html
MySQL主从复制
读写分离案例
项目实现读写分离
Nginx-概述
Nginx-命令
Nginx-应用
1). 存在的问题
在前面基础功能实现的过程中,我们后台管理系统及移动端的用户,在进行数据访问时,都是直接操作数据库MySQL的。结构如下图:
而在当前,MySQL服务器只有一台,那么就可能会存在如下问题:
1). 读和写所有压力都由一台数据库承担,压力大
2). 数据库服务器磁盘损坏则数据丢失,单点故障
2). 解决方案
为了解决上述提到的两个问题,我们可以准备两台MySQL,一台主(Master)服务器,一台从(Slave)服务器,主库的数据变更,需要同步到从库中(主从复制)。而用户在访问我们项目时,如果是写操作(insert、update、delete),则直接操作主库;如果是读(select)操作,则直接操作从库(在这种读写分离的结构中,从库是可以有多个的),这种结构我们称为 读写分离 。
今天我们就需要实现上述的架构,来解决业务开发中所存在的问题。
MySQL数据库默认是支持主从复制的,不需要借助于其他的技术,我们只需要在数据库中简单的配置即可。接下来,我们就从以下的几个方面,来介绍一下主从复制:
MySQL主从复制是一个异步的复制过程,底层是基于Mysql数据库自带的 二进制日志 功能。就是一台或多台MySQL数据库(slave,即从库)从另一台MySQL数据库(master,即主库)进行日志的复制,然后再解析日志并应用到自身,最终实现 从库 的数据和 主库 的数据保持一致。MySQL主从复制是MySQL数据库自带功能,无需借助第三方工具。
二进制日志:
二进制日志(BINLOG)记录了所有的 DDL(数据定义语言)语句和 DML(数据操纵语言)语句,但是不包括数据查询语句。此日志对于灾难时的数据恢复起着极其重要的作用,MySQL的主从复制, 就是通过该binlog实现的。默认MySQL是未开启该日志的。
MySQL的主从复制原理如下:
MySQL复制过程分成三步:
1). MySQL master 将数据变更写入二进制日志( binary log)
2). slave将master的binary log拷贝到它的中继日志(relay log)
3). slave重做中继日志中的事件,将数据变更反映它自己的数据
1.2.1 准备工作
提前准备两台服务器,并且在服务器中安装MySQL,服务器的信息如下:
数据库 | IP | 数据库版本 |
---|---|---|
Master | 192.168.200.200 | 5.7.25 |
Slave | 192.168.200.201 | 5.7.25 |
并在两台服务器上做如下准备工作:
注意:如果已放开相应的端口号,就不需要再执行此操作了
1). 防火墙开放3306端口号
# 放开3306端口
firewall-cmd --zone=public --add-port=3306/tcp --permanent
# 重新加载配置
firewall-cmd --reload
# 显示当前放开的端口号
firewall-cmd --zone=public --list-ports
2). 并将两台数据库服务器启动起来:
注意:此处根据自己安装的数据库启动
如果数据库已启动,就不需要再执行此操作了
启动Mariadb
systemctl start mariadb
启动MySQL
systemctl start mysqld
登录MySQL,验证是否正常启动
1.2.2 主库配置
服务器: 192.168.200.200
1). 修改Mysql数据库的配置文件/etc/my.cnf
在最下面增加配置:
log-bin=mysql-bin #[必须]启用二进制日志
server-id=200 #[必须]服务器唯一ID(唯一即可)
2). 重启Mysql(Mariadb)服务
执行指令:
此处根据自己安装的数据库启动
重启Mariadb
systemctl restart mariadb
重启MySql
systemctl restart mysqld
3). 创建数据同步的用户并授权
登录mysql
mysql -u root -p
并执行如下指令,创建用户并授权:
GRANT REPLICATION SLAVE ON *.* to 'xiaoming'@'%' identified by 'Root@123456';
注:上面SQL的作用是创建一个用户 xiaoming ,密码为 Root@123456 ,并且给xiaoming用户授予REPLICATION SLAVE权限。常用于建立复制时所需要用到的用户权限,也就是slave必须被master授权具有该权限的用户,才能通过该用户复制。
MySQL密码复杂程度说明:
目前mysql5.7默认密码校验策略等级为 MEDIUM , 该等级要求密码组成为: 数字、小写字母、大写字母 、特殊字符、长度至少8位
4). 登录Mysql数据库,查看master同步状态
执行下面SQL,记录下结果中File和Position的值
show master status;
注:上面SQL的作用是查看Master的状态,执行完此SQL后不要再执行任何操作
1.2.3 从库配置
服务器: 192.168.200.201
1). 修改Mysql数据库的配置文件/etc/my.cnf
server-id=201 #[必须]服务器唯一ID
2). 重启Mysql(Mariadb)服务
执行指令:
注意:此处根据自己安装的数据库启动
重启Mariadb
systemctl restart mariadb
重启MySql
systemctl restart mysqld
3). 登录Mysql数据库,设置主库地址及同步位置
change master to master_host='192.168.188.128',master_user='xiaoming',master_password='Root@123456',master_log_file='mysql-bin.000001',master_log_pos=396;
start slave;
参数说明:
A. master_host : 主库的IP地址
B. master_user : 访问主库进行主从复制的用户名(上面在主库创建的)
C. master_password : 访问主库进行主从复制的用户名对应的密码
D. master_log_file : 从哪个日志文件开始同步(上述查询master状态中展示的有)
E. master_log_pos : 从指定日志文件的哪个位置开始同步(上述查询master状态中展示的有)
4). 查看从数据库的状态
show slave status;
然后通过状态信息中的 Slave_IO_running 和 Slave_SQL_running 可以看出主从同步是否就绪,如果这两个参数全为Yes,表示主从同步已经配置完成。
MySQL命令行技巧:
\G : 在MySQL的sql语句后加上\G,表示将查询结果进行按列打印,可以使每个字段打印到单独的行。即将查到的结构旋转90度变成纵向;
主从复制的环境,已经搭建好了,接下来,我们可以通过Navicat连接上两台MySQL服务器,进行测试。测试时,我们只需要在主库Master执行操作,查看从库Slave中是否将数据同步过去即可。
1). 在master中创建数据库itcast, 刷新slave查看是否可以同步过去
2). 在master的itcast数据下创建user表, 刷新slave查看是否可以同步过去
3). 在master的user表中插入一条数据, 刷新slave查看是否可以同步过去
面对日益增加的系统访问量,数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说,将数据库拆分为主库和从库,主库负责处理事务性的增删改操作,从库负责处理查询操作,能够有效的避免由数据更新导致的行锁,使得整个系统的查询性能得到极大的改善。
通过读写分离,就可以降低单台数据库的访问压力, 提高访问效率,也可以避免单机故障。
主从复制的结构,我们在第一节已经完成了,那么我们在项目中,如何通过java代码来完成读写分离呢,如何在执行select的时候查询从库,而在执行insert、update、delete的时候,操作主库呢?这个时候,我们就需要介绍一个新的技术 ShardingJDBC。
Sharding-JDBC定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
使用Sharding-JDBC可以在程序中轻松的实现数据库读写分离。
Sharding-JDBC具有以下几个特点:
1). 适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
2). 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
3). 支持任意实现JDBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库。
依赖:
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC1
在主库中创建一个数据库rw, 并且创建一张表, 该数据库及表结构创建完毕后会自动同步至从数据库,SQL语句如下:
create database rw default charset utf8mb4;
use rw;
CREATE TABLE `user` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`address` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO user (name, age, address) VALUES ('张三', 100, '昌平');
INSERT INTO user (name, age, address) VALUES ('李四', 0, '顺义');
INSERT INTO user (name, age, address) VALUES ('星越L', 21, '北京');
我们本案例主要是演示一下读写分离操作,对于基本的增删改查的业务操作,我们就不再去编写了,我们可以直接导入资料中提供的demo工程(rw_demo),在demo工程中,我们已经完成了user的增删改查操作,具体的工程结构如下:
1). 在pom.xml中增加shardingJdbc的maven坐标
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC1
2). 在application.yml中增加配置
spring:
main:
# 如果当前项目中存在同名的bean,后定义的bean会覆盖先定义的
allow-bean-definition-overriding: true
shardingsphere:
datasource:
names:
master,slave
# 主数据源
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.200.200:3306/rw?characterEncoding=utf-8
username: root
password: root
# 从数据源
slave:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.200.201:3306/rw?characterEncoding=utf-8
username: root
password: root
masterslave:
# 读写分离配置
load-balance-algorithm-type: round_robin #轮询
# 最终的数据源名称
name: dataSource
# 主库数据源名称
master-data-source-name: master
# 从库数据源名称列表,多个逗号分隔
slave-data-source-names: slave
props:
sql:
show: true #开启SQL显示,默认false
配置解析:
如果不配置该项,项目启动之后将会报错:
报错信息表明,在声明 org.apache.shardingsphere.shardingjdbc.spring.boot 包下的SpringBootConfiguration中的dataSource这个bean时出错, 原因是有一个同名的 dataSource 的bean在com.alibaba.druid.spring.boot.autoconfigure包下的DruidDataSourceAutoConfigure类加载时已经声明了。
而我们需要用到的是 shardingjdbc包下的dataSource,所以我们需要配置上述属性,让后加载的覆盖先加载的。
我们使用shardingjdbc来实现读写分离,直接通过上述简单的配置就可以了。配置完毕之后,我们就可以重启服务,通过postman来访问controller的方法,来完成用户信息的增删改查,我们可以通过debug及日志的方式来查看每一次执行增删改查操作,使用的是哪个数据源,连接的是哪个数据库。
1). 保存数据
控制台输出日志,可以看到操作master主库:
2). 修改数据
控制台输出日志,可以看到操作master主库:
3). 查询数据
控制台输出日志,可以看到操作slave主库:
4). 删除数据
控制台输出日志,可以看到操作master主库:
直接使用我们前面在虚拟机中搭建的主从复制的数据库环境即可。在主库中创建瑞吉外卖项目的业务数据库reggie, 并导入相关表结构和数据(我们可以将自己之前在本地开发时使用的数据库数据导出, 然后导入到服务器中的主库即可)。
1). 将自己本地的reggie数据库的数据导出SQL文件
这样做的话,我们之前自己开发时,添加的测试数据都还在的,便于测试。
2). 在主数据库master中,创建数据库reggie,并导入该SQL文件
master中创建数据库,会自动同步至slave从库
在master的reggie中导入sql文件
目前默认git中有两个分支master 和 v1.0 ,我们接下来进行读写分离的优化,就不在master和v1.0分支来操作了,我们需要在git上创建一个单独的分支v1.1,读写分离的优化,我们就在该分支上进行操作。具体创建分支的操作,和前面演示的一致。
当前创建的v1.1分支,是基于master分支创建出来的,所以目前master分支的代码, 和v1.1分支的代码是完全一样的,接下来把v1.1的代码也推送至远程仓库。
1). 在项目的pom.xml增加依赖
org.apache.shardingsphere
sharding-jdbc-spring-boot-starter
4.0.0-RC1
2). 在项目的application.yml中配置数据源相关信息
spring:
main:
allow-bean-definition-overriding: true
shardingsphere:
datasource:
names:
master,slave
# 主数据源
master:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.200.200:3306/reggie?characterEncoding=utf-8
username: root
password: root
# 从数据源
slave:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.200.201:3306/reggie?characterEncoding=utf-8
username: root
password: root
masterslave:
# 读写分离配置
load-balance-algorithm-type: round_robin #轮询
# 最终的数据源名称
name: dataSource
# 主库数据源名称
master-data-source-name: master
# 从库数据源名称列表,多个逗号分隔
slave-data-source-names: slave
props:
sql:
show: true #开启SQL显示,默认false
配置完毕之后,我们启动项目进行测试,直接访问系统管理后台的页面,然后执行相关业务操作,看控制台输出的日志信息即可。
查询操作:
更新操作:
插入操作:
删除操作:
读写分离的功能我们已经实现完毕了,那么接下来,我们就可以将当前分支v1.1代码提交并推送到远程仓库。
然后,再将v1.1的代码,合并到master分支,然后推送至远程仓库。
Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx的网站有:百度、京东、新浪、网易、腾讯、淘宝等。
Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。
官网:nginx news
4.2.1 下载
在Nginx的官网的下载页面中(nginx: download),就展示了当前Nginx版本,并提供了下载的连接。 如下:
在本项目中,我们所学习的Nginx选择的是稳定版本的1.16这个版本,我们可以直接从官网下载,当然在我们的课程资料中也已经提供了该版本的安装包。
4.2.2 安装
1). 安装依赖包
由于nginx是基于c语言开发的,所以需要安装c语言的编译环境,及正则表达式库等第三方依赖库。
yum -y install gcc pcre-devel zlib-devel openssl openssl-devel
2). 下载Nginx安装包
yum install wget
wget https://nginx.org/download/nginx-1.16.1.tar.gz
wget :
wget命令用来从指定的URL下载文件。wget非常稳定,它在带宽很窄的情况下和不稳定网络中有很强的适应性,如果是由于网络的原因下载失败,wget会不断的尝试,直到整个文件下载完毕。如果是服务器打断下载过程,它会再次联到服务器上从停止的地方继续下载。
执行完wget指令后,就会在当前所在目录看到下载下来的文件。
3). 解压nginx压缩包
tar -zxvf nginx-1.16.1.tar.gz
4). 配置Nginx编译环境
cd nginx-1.16.1
./configure --prefix=/usr/local/nginx
说明:
--prefix 指定的目录,就是我们安装Nginx的目录。
5). 编译&安装
make & make install
安装完Nginx后,我们可以切换到Nginx的安装目录(/usr/local/nginx),先来熟悉一下Nginx的目录结构,如下图:
备注:
上述我们用到的一个指令 tree,该指令可以将我们指定的目录以树状结构展示出来。如果没有这个指令,可以通过以下指令进行安装。
yum install tree
重点目录和文件如下:
目录/文件 | 说明 | 备注 |
---|---|---|
conf | 配置文件的存放目录 | |
conf/nginx.conf | Nginx的核心配置文件 | conf下有很多nginx的配置文件,我们主要操作这个核心配置文件 |
html | 存放静态资源(html, css, ) | 部署到Nginx的静态资源都可以放在html目录中 |
logs | 存放nginx日志(访问日志、错误日志等) | |
sbin/nginx | 二进制文件,用于启动、停止Nginx服务 |
Nginx中,我们的二进制可执行文件(nginx)存放在sbin目录下,虽然只有一个可执行文件,但是我们可以通过该指令配合不同的参数达到更加强大的功能。接下来,我们就演示一下Nginx常见指令, 在执行下面的指令时,都需要在/usr/local/nginx/sbin/目录下执行。
1). 查看版本
./nginx -v
2). 检查配置文件
修改了nginx.conf核心配置文件之后,在启动Nginx服务之前,可以先检查一下conf/nginx.conf文件配置的是否有错误,命令如下:
./nginx -t
3). 启动
./nginx
启动之后,我们可以通过ps -ef指令来查看nginx的进程是否存在。
注意: nginx服务启动后,默认就会有两个进程。
启动之后,我们可以直接访问Nginx的80端口, http://192.168.200.200
注意:
要想正常访问Nginx,需要关闭防火墙或开放指定端口号,执行的指令如下:
A. 关闭防火墙
systemctl stop firewalld
B. 开放80端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
firewall-cmd --reload
4). 停止
./nginx -s stop
停止之后,我们可以查看nginx的进程:
ps -ef|grep nginx
5). 重新加载
当修改了Nginx配置文件后,需要重新加载才能生效,可以使用下面命令重新加载配置文件:
./nginx -s reload
介绍了并安装了Nginx之后,本章节将要讲解的是Nginx的使用,我们主要从以下四个方面进行讲解。
nginx的配置文件(conf/nginx.conf)整体上分为三部分: 全局块、events块、http块。这三块的分别配置什么样的信息呢,看下表:
区域 | 职责 |
---|---|
全局块 | 配置和nginx运行相关的全局配置 |
events块 | 配置和网络连接相关的配置 |
http块 | 配置代理、缓存、日志记录、虚拟主机等配置 |
具体结构图如下:
在全局块、events块以及http块中,我们经常配置的是http块。
在http块中可以包含多个server块,每个server块可以配置多个location块。
6.2.1 介绍
Nginx可以作为静态web服务器来部署静态资源。这里所说的静态资源是指在服务端真实存在,并且能够直接展示的一些文件,比如常见的html页面、css文件、js文件、图片、视频等资源。
相对于Tomcat,Nginx处理静态资源的能力更加高效,所以在生产环境下,一般都会将静态资源部署到Nginx中。
将静态资源部署到Nginx非常简单,只需要将文件复制到Nginx安装目录下的html目录中即可。
server {
listen 80; #监听端口
server_name localhost; #服务器名称
location / { #匹配客户端请求url
root html; #指定静态资源根目录
index index.html; #指定默认首页
}
}
6.2.2 测试
在资料中,我们提供了一个静态的html文件,我们需要将这个文件部署到nginx中,然后通过nginx访问html静态资源。
1). 将静态资源上传到 /usr/local/nginx/html 目录
2). 启动nginx
3). 访问
http://192.168.200.200/hello.html
http://192.168.200.200 , 访问该地址,访问的是nginx的默认首页
4). 配置首页
如果我们需要将hello.html作为nginx的首页,可以修改location的index指令,配置为hello.html,如下:
配置完毕后,我们可以通过指令,来检查配置文件是否配置正确: nginx -t
配置文件修改了,我们需要重新加载一下,才可以生效:
nginx -s reload
5). 访问
http://192.168.200.200
6.3.1 概念介绍
1). 正向代理
正向代理服务器是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。
正向代理一般是在客户端设置代理服务器,通过代理服务器转发请求,最终访问到目标服务器。
2). 反向代理
反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源,反向代理服务器负责将请求转发给目标服务器。用户不需要知道目标服务器的地址,也无须在用户端作任何设定,对于用户来说,访问反向代理服务器是完全无感知的。
那么在本小节,我们就是要使用nginx来作为反向代理服务器使用。 在nginx中,我们可以在nginx.conf中配置反向代理:
server {
listen 82;
server_name localhost;
location / {
proxy_pass http://192.168.200.201:8080; #反向代理配置,将请求转发到指定服务
}
}
上述配置的含义为: 当我们访问nginx的82端口时,根据反向代理配置,会将请求转发到 http://192.168.200.201:8080 对应的服务上。
6.3.2 测试
需求: 在192.168.200.201这台服务器中部署了java应用,运行端口为8080,并提供了一个可访问的链接 /hello。现在我们需要在访问nginx的82端口时,通过nginx将请求转发到192.168.200.201:8080的服务。
1). 在192.168.200.201部署服务并启动
将资料中提供的 helloworld-1.0-SNAPSHOT.jar 上传到服务器端,并通过指令 java -jar helloworld-1.0-SNAPSHOT.jar 运行服务。
2). 在192.168.200.200中的nginx.conf中配置反向代理
进入nginx的安装目录,并编辑配置文件nginx.conf:
cd /usr/local/nginx/conf/
vim nginx.conf
在http块中,再添加一个server块虚拟主机的配置,监听82端口,并配置反向代理proxy_pass:
server {
listen 82;
server_name localhost;
location / {
proxy_pass http://192.168.200.201:8080; #反向代理配置,将请求转发到指定服务
}
}
3). 检查配置文件,并重新加载
nginx -t
nginx -s reload
4). 访问
注意: 在访问82端口时,有可能访问不通,原因是以为防火墙中没有开放端口号。我们可以通过两种方式来解决该问题:
A. 关闭防火墙
systemctl stop firewalld
B. 开发指定端口
firewall-cmd --zone=public --add-port=82/tcp --permanent
firewall-cmd --reload
6.4.1 概念介绍
早期的网站流量和业务功能都比较简单,单台服务器就可以满足基本需求,但是随着互联网的发展,业务流量越来越大并且业务逻辑也越来越复杂,单台服务器的性能及单点故障问题就凸显出来了,因此需要多台服务器组成应用集群,进行性能的水平扩展以及避免单点故障出现。
应用集群:将同一应用部署到多台机器上,组成应用集群,接收负载均衡器分发的请求,进行业务处理并返回响应数据
负载均衡器:将用户请求根据对应的负载均衡算法分发到应用集群中的一台服务器进行处理
此处的负载均衡器,我们将会使用Nginx来实现,而Nginx的负载均衡是基于反向代理的,只不过此时所代理的服务器不是一台,而是多台。
6.4.2 测试
1). 将资料中提供的两个jar包,上传到192.168.200.201服务器上
jar | 运行端口 | 请求链接 | 响应数据 |
---|---|---|---|
8080 | /hello | 8080 | |
8081 | /hello | 8081 |
我们在测试时,并没有那么多服务器,我们可以在一台服务器中启动多个服务,运行在不同的端口号上进行测试。
2). 运行上传上来的两个jar包,运行端口分别是 8080 , 8081
由于我们执行 java -jar 指令会占用前台窗口,所以我们可以开启两个窗口进行测试。
3). 在nginx中配置负载均衡
打开nginx的配置文件nginx.conf并增加如下配置:
#upstream指令可以定义一组服务器
upstream targetserver{
server 192.168.200.201:8080;
server 192.168.200.201:8081;
}
server {
listen 8888;
server_name localhost;
location / {
proxy_pass http://targetserver;
}
}
具体的配置位置如下:
4). 重新加载nginx配置文件,访问
nginx -s reload
测试时,我们直接访问nginx的8080端口(http://192.168.200.200:8080), 此时nginx会根据负载均衡策略,将请求转发到后面的两台服务器。
在上述的测试过程中,我们看到请求均衡的转发到了8080和8081,因为模式的负载均衡策略是轮询。
注意: 上述所有涉及到的端口号,都需要在对应的服务器的防火墙中开放,或者彻底关闭防火墙
6.4.3 负载均衡策略
处理上述默认的轮询策略以外,在Nginx中还提供了其他的负载均衡策略,如下:
名称 | 说明 | 特点 |
---|---|---|
轮询 | 默认方式 | |
weight | 权重方式 | 根据权重分发请求,权重大的分配到请求的概率大 |
ip_hash | 依据ip分配方式 | 根据客户端请求的IP地址计算hash值, 根据hash值来分发请求, 同一个IP发起的请求, 会发转发到同一个服务器上 |
least_conn | 依据最少连接方式 | 哪个服务器当前处理的连接少, 请求优先转发到这台服务器 |
url_hash | 依据url分配方式 | 根据客户端请求url的hash值,来分发请求, 同一个url请求, 会发转发到同一个服务器上 |
fair | 依据响应时间方式 | 优先把请求分发给处理请求时间短的服务器 |
权重的配置:
#upstream指令可以定义一组服务器
upstream targetserver{
server 192.168.200.201:8080 weight=10;
server 192.168.200.201:8081 weight=5;
}
上述配置的weight权重是相对的,在上述的配置中,效果就是,在大数据量的请求下,最终8080接收的请求数是8081的两倍。
MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎方面,使用XtraDB(英语:XtraDB)来代替MySQL的InnoDB
1)查看CentOS自带的mysql
输入 rpm -qa | grep mysql
2)将自带的mysql卸载
rpm -e --nodeps
3)yum安装
yum -y install mariadb-server
4)启动mysql
systemctl start mariadb
5)设置root密码
注:这只是设置root用户在本机(linux)登录时的密码
mysqladmin -u root password 'root'
6)进入mysql
mysql -u root -p
备注:输入密码:root
进入到数据库的执行命令行里面了。
7) 进入mysql,并执行下面sql
保证密码和本地一致
下面的话在mysql数据库里面里面执行
-- 查看当前的数据库
show databases;
-- 打开mysql
use mysql ;
-- 查看所有表
show tables;
-- 我们不用ipv6的地址,直接把host改为%,表示所有客户端都可以连接;同时设置密码为root
update user set host='%' ,password=password("root") where user='root' and host = '::1' ;
-- 刷新后才能生效
flush privileges;
退出数据库命令操作
exit;
开放端口号 (Linux命令)
# 开放端口命令
firewall-cmd --zone=public --add-port=3306/tcp --permanent
#重新加载配置
firewall-cmd --reload
在上述我们在使用nginx命令在进行服务的启动、停止、重新加载时,都需要用到一个指令nginx,而这个指令是在nginx/sbin目录下的,我们每一次使用这个指令都需要切换到sbin目录才可以,使用相对繁琐。那么我们能不能在任意目录下都可以执行该指令来操作nginx呢?答案是可以的,配置nginx的环境变量即可。
通过vim编辑器,打开/etc/profile文件, 在PATH环境变量中增加nginx的sbin目录,如下:
修改完配置文件之后,需要执行 source /etc/profile 使文件生效。 接下来,我们就可以在任意目录下执行nginx的指令了,如:
6.2.2 测试
在资料中,我们提供了一个静态的html文件,我们需要将这个文件部署到nginx中,然后通过nginx访问htmLl静态资源。
1). 将静态资源上传到 /usr/local/nginx/html 目录
2). 启动nginx
3). 访问
http://192.168.200.200/hello.html
http://192.168.200.200 , 访问该地址,访问的是nginx的默认首页
4). 配置首页
如果我们需要将hello.html作为nginx的首页,可以修改location的index指令,配置为hello.html,如下:
配置完毕后,我们可以通过指令,来检查配置文件是否配置正确: nginx -t
配置文件修改了,我们需要重新加载一下,才可以生效:
nginx -s reload
5). 访问
http://192.168.200.200
6.3.1 概念介绍
1). 正向代理
正向代理服务器是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。
正向代理的典型用途是为在防火墙内的局域网客户端提供访问Internet的途径。
正向代理一般是在客户端设置代理服务器,通过代理服务器转发请求,最终访问到目标服务器。
2). 反向代理
反向代理服务器位于用户与目标服务器之间,但是对于用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源,反向代理服务器负责将请求转发给目标服务器。用户不需要知道目标服务器的地址,也无须在用户端作任何设定,对于用户来说,访问反向代理服务器是完全无感知的。
那么在本小节,我们就是要使用nginx来作为反向代理服务器使用。 在nginx中,我们可以在nginx.conf中配置反向代理:
server {
listen 82;
server_name localhost;
location / {
proxy_pass http://192.168.200.201:8080; #反向代理配置,将请求转发到指定服务
}
}
上述配置的含义为: 当我们访问nginx的82端口时,根据反向代理配置,会将请求转发到 http://192.168.200.201:8080 对应的服务上。
6.3.2 测试
需求: 在192.168.200.201这台服务器中部署了java应用,运行端口为8080,并提供了一个可访问的链接 /hello。现在我们需要在访问nginx的82端口时,通过nginx将请求转发到192.168.200.201:8080的服务。
1). 在192.168.200.201部署服务并启动
将资料中提供的 helloworld-1.0-SNAPSHOT.jar 上传到服务器端,并通过指令 java -jar helloworld-1.0-SNAPSHOT.jar 运行服务。
2). 在192.168.200.200中的nginx.conf中配置反向代理
进入nginx的安装目录,并编辑配置文件nginx.conf:
cd /usr/local/nginx/conf/
vim nginx.conf
在http块中,再添加一个server块虚拟主机的配置,监听82端口,并配置反向代理proxy_pass:
server {
listen 82;
server_name localhost;
location / {
proxy_pass http://192.168.200.201:8080; #反向代理配置,将请求转发到指定服务
}
}
3). 检查配置文件,并重新加载
nginx -t
nginx -s reload
4). 访问
注意: 在访问82端口时,有可能访问不通,原因是以为防火墙中没有开放端口号。我们可以通过两种方式来解决该问题:
A. 关闭防火墙
systemctl stop firewalld
B. 开发指定端口
firewall-cmd --zone=public --add-port=82/tcp --permanent
firewall-cmd --reload
6.4.1 概念介绍
早期的网站流量和业务功能都比较简单,单台服务器就可以满足基本需求,但是随着互联网的发展,业务流量越来越大并且业务逻辑也越来越复杂,单台服务器的性能及单点故障问题就凸显出来了,因此需要多台服务器组成应用集群,进行性能的水平扩展以及避免单点故障出现。
应用集群:将同一应用部署到多台机器上,组成应用集群,接收负载均衡器分发的请求,进行业务处理并返回响应数据
负载均衡器:将用户请求根据对应的负载均衡算法分发到应用集群中的一台服务器进行处理
此处的负载均衡器,我们将会使用Nginx来实现,而Nginx的负载均衡是基于反向代理的,只不过此时所代理的服务器不是一台,而是多台。
6.4.2 测试
1). 将资料中提供的两个jar包,上传到192.168.200.201服务器上
jar | 运行端口 | 请求链接 | 响应数据 |
---|---|---|---|
8080 | /hello | 8080 | |
8081 | /hello | 8081 |
我们在测试时,并没有那么多服务器,我们可以在一台服务器中启动多个服务,运行在不同的端口号上进行测试。
2). 运行上传上来的两个jar包,运行端口分别是 8080 , 8081
由于我们执行 java -jar 指令会占用前台窗口,所以我们可以开启两个窗口进行测试。
3). 在nginx中配置负载均衡
打开nginx的配置文件nginx.conf并增加如下配置:
#upstream指令可以定义一组服务器
upstream targetserver{
server 192.168.200.201:8080;
server 192.168.200.201:8081;
}
server {
listen 8888;
server_name localhost;
location / {
proxy_pass http://targetserver;
}
}
具体的配置位置如下:
4). 重新加载nginx配置文件,访问
nginx -s reload
测试时,我们直接访问nginx的8080端口(http://192.168.200.200:8080), 此时nginx会根据负载均衡策略,将请求转发到后面的两台服务器。
在上述的测试过程中,我们看到请求均衡的转发到了8080和8081,因为模式的负载均衡策略是轮询。
注意: 上述所有涉及到的端口号,都需要在对应的服务器的防火墙中开放,或者彻底关闭防火墙
6.4.3 负载均衡策略
处理上述默认的轮询策略以外,在Nginx中还提供了其他的负载均衡策略,如下:
名称 | 说明 | 特点 |
---|---|---|
轮询 | 默认方式 | |
weight | 权重方式 | 根据权重分发请求,权重大的分配到请求的概率大 |
ip_hash | 依据ip分配方式 | 根据客户端请求的IP地址计算hash值, 根据hash值来分发请求, 同一个IP发起的请求, 会发转发到同一个服务器上 |
least_conn | 依据最少连接方式 | 哪个服务器当前处理的连接少, 请求优先转发到这台服务器 |
url_hash | 依据url分配方式 | 根据客户端请求url的hash值,来分发请求, 同一个url请求, 会发转发到同一个服务器上 |
fair | 依据响应时间方式 | 优先把请求分发给处理请求时间短的服务器 |
权重的配置:
#upstream指令可以定义一组服务器
upstream targetserver{
server 192.168.200.201:8080 weight=10;
server 192.168.200.201:8081 weight=5;
}
上述配置的weight权重是相对的,在上述的配置中,效果就是,在大数据量的请求下,最终8080接收的请求数是8081的两倍。
MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎方面,使用XtraDB(英语:XtraDB)来代替MySQL的InnoDB
1)查看CentOS自带的mysql
输入 rpm -qa | grep mysql
2)将自带的mysql卸载
rpm -e --nodeps
3)yum安装
yum -y install mariadb-server
4)启动mysql
systemctl start mariadb
5)设置root密码
注:这只是设置root用户在本机(linux)登录时的密码
mysqladmin -u root password 'root'
6)进入mysql
mysql -u root -p
备注:输入密码:root
进入到数据库的执行命令行里面了。
7) 进入mysql,并执行下面sql
保证密码和本地一致
下面的话在mysql数据库里面里面执行
-- 查看当前的数据库
show databases;
-- 打开mysql
use mysql ;
-- 查看所有表
show tables;
-- 我们不用ipv6的地址,直接把host改为%,表示所有客户端都可以连接;同时设置密码为root
update user set host='%' ,password=password("root") where user='root' and host = '::1' ;
-- 刷新后才能生效
flush privileges;
退出数据库命令操作
exit;
开放端口号 (Linux命令)
# 开放端口命令
firewall-cmd --zone=public --add-port=3306/tcp --permanent
#重新加载配置
firewall-cmd --reload
在上述我们在使用nginx命令在进行服务的启动、停止、重新加载时,都需要用到一个指令nginx,而这个指令是在nginx/sbin目录下的,我们每一次使用这个指令都需要切换到sbin目录才可以,使用相对繁琐。那么我们能不能在任意目录下都可以执行该指令来操作nginx呢?答案是可以的,配置nginx的环境变量即可。
通过vim编辑器,打开/etc/profile文件, 在PATH环境变量中增加nginx的sbin目录,如下:
修改完配置文件之后,需要执行 source /etc/profile 使文件生效。 接下来,我们就可以在任意目录下执行nginx的指令了,如: