【JavaEE】(24) Linux 基础使用和程序部署
一、Linux 背景知识
Linux 的第一个版本开发者是 Linus,所以部分人会叫“林纳斯”。Linux 只是一个开源的操作系统内核,有些公司/开源组织基于 Linux 内核,配套了不同的应用程序,构成不同的操作系统(比如 vivo、),也就是不同“发行版”:RedHat 收费,CentOS 社区免费版但是停止维护了(出了问题小公司不好搞,但是大公司有能力二次开发),Ubuntu 免费并且在持续维护。
Linux 免费开源、稳定(持续运行不重启很多年都没问题)、安全(管理员才能操作内核)、社区支持(有问题去社区问)。
我们程序员必学 Linux,只不过不同岗位侧重点不同。Linux 虽有图形界面,但不好用切占资源开销,所以 Java 开发需要学 Linux 基础命令。Linux 自身提供了 API 给程序员完成复杂编程,比如文件操作、多线程、socket 编程等。但是 Java 有封装好的工具,并且跨平台,所以不需要学 Linux 的系统编程。然后就是在 Linux 上部署项目,让用户访问,企业有自动化工具一键部署。安装程序是运维的事。最后就是读日志,tail 跟踪日志,grep 过滤信息。
二、Linux 环境搭建
物理机装 Linux 用起来不方便,虚拟机装 Linux 有各种环境问题,云服务器开机就用就是费钱,可以申请学生优惠。小的项目 2核2G够,大的比如微服务项目 2核4G 够。
买好后,要记住:公有 IP、管理员账户(默认root)、密码。
下 XShell 终端软件,远程连接服务器,对服务器进行操作。
家庭/学校免费 - NetSarang Websitehttps://www.xshell.com/zh/free-for-home-school/
XShell 远程连接:
复制粘贴设置:工具》选项》终端:
三、Linux 基础命令
- ~ 表示 home 目录,root 管理员的 home 目录是 /root,普通用户是 /home/用户名。
1、创建文件夹(mkdir)
语法:touch [选项] [⽬录]
mkdir:创建文件夹
mkdir -p:先创建所有不存在的父文件夹(parent),再创建文件夹(test)。
2、创建文件(touch)
touch:什么后缀都行
3、删除文件夹/文件(rm)
rm -rf:直接删除文件夹,及其下所有内容。包括只读文件也删除。(-r 指删除文件夹下,还有文件的情况)
不要轻易在根目录 / 下使用该命令,即删除所有包括系统文件,使用了系统也会提示不能操作:图中说明加 --no-preserve-root 选项会忽略警告强制删除。
rm -ri:删除所有文件之前,询问。
4、列出目录(ls)
ls :列出当前目录下的所有文件夹、文件。
ls -a:列出所有文件,包括 . 开头的隐藏文件。
ls -l:列出所有文件的详细信息。
ll :列出所有文件,包括隐藏文件的详细信息。
ls -dl:列出当前文件的详细信息。
5、改变工作目录(cd)
cd 绝对路径:
cd 相对路径:. 表示当前目录,.. 表示上一级目录。
cd - : 返回最近访问的目录。
6、显示当前目录(pwd)
7、快捷键
tab 自动补全:敲部分文件名,tab 可根据当前目录下的文件自动补全。
crl+c:输入输错了,取消命令。
8、复制文件夹/文件(cp)
cp 源文件 目标路径
可以重命名:
若目标路径里有重复的,-f 是强制覆盖,-i 是覆盖前询问。
9、剪切文件夹/文件(mv)
mv:
可以重命名剪切的源文件:
9、写文件(vi)
vi/vim 文件名:用 vim 文本编辑器打开文件。
i :进入编辑模式。
Esc:退出编辑模式。
:q 未修改,直接退出。
:wq 修改,保存退出。
:wq! 修改,强制保存退出。(另一个窗口也修改了这个文件并保存了,如果当前窗口不要另一个窗口修改的,就强制保存并退出)
:q 修改了,强制不保存退出。
更多参考使用文档,命令 vimtutor。
10、读文件
cat -n 文件名:读取文件所有内容,并显示行号。
more : 显示部分内容。按 enter 再显示一行,按 下箭头 再显示一页。 crl+c 结束。
less :滚动读取,:q 退出。
head -10:显示头 10 行。
tail -10:显示尾 10 行。
11、查找内容(grep)
常用于查看日志。
grep -w 全字匹配。-r 递归查找所有文件。--color 高亮查找。
现实场景中,有很多用户请求,日志滚动得很快,所以需要用 tail -100f 跟踪最新日志,但是有些日志不是我们想要的,就用 grep 过滤日志。
12、查看进程(ps)
显示所有进程,并查找进程:ps aux 或者 ps -ef | grep "进行名" 或 “进程 id”
13、查看网络状态(netstat)
| 表示把前一个命令得输出,作为后一个命令得输入。
netstat -anp | grep "进程名" 或 “端口号”。
14、上传/下载文件
安装命令:
apt-get install lrzsz
上传文件:直接拖拽 / rz。
下载文件:sz 文件名。
四、搭建 Java 部署环境
1、软件管理(apt)
不同发行版的 Linux 软件管理命令不一样,Ubuntu 是 apt。
(1)查找软件包
列出的软件包数据库:apt list,不建议直接用,因为会显示所有的软件,信息太多会卡住。一般搭配 grep。
(2)管理员身份运行
在普通用户上进行 apt 更新、安装、卸载操作,需要在前面加上 sudo,表示以管理员身份运行。因为软件的更新、安装、卸载是管理员才能执行的操作。
sudo su,可切换至 root 用户。
(3)更新软件包数据库
安装软件前,需要更新软件包数据库。因为 apt 是按照系统上的软件包数据库的信息,从仓库中下载的。如果没有更新软件包数据库,就可能与仓库中的软件包信息不一致,导致下载失败。
apt-get update
(4)安装和卸载
apt install / remove。remove 会残留配置文件,purge 会把配置文件也删了。但是也有可能没删干净,查百度。
2、JDK
安装:
// 更新软件包
apt-get update// 查找 jdk 软件包
apt list |grep "jdk"// 安装 jdk
apt install openjdk-17-jdk// 查看 jdk 版本
java -version
卸载:
// 查看已安装 jdk,忽略大小写
dpkg --list | grep -i jdk// 删除 jdk
apt-get purge openjdk*// 卸载 jdk
apt-get purge icedtea-* openjdk-*// 查看是否卸载
dpkg --list | grep -i jdk
3、MySQL
安装:
// 查找
apt list |grep "mysql-server"// 安装
apt install mysql-server// 查看 mysql 状态
sudo systemctl status mysql
安装安全设置。使用 mysql 的脚本,解决不安全的默认设置:
sudo mysql_secure_installation
设置密码:
// 启动 mysql
mysql// 设置密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '密码'// 登录 mysql
mysql -uroot -p
输入密码// 退出 mysql
quit;
卸载 mysql:
// 停止 mysql
sudo systemctl stop mysql// 卸载 mysql
sudo apt-get remove --purge mysql-server mysql-client mysql-common// 删除配置文件和数据
sudo rm -rf /etc/mysql /var/lib/mysql// 清理残留
sudo apt-get autoremove
sudo apt-get autoclean// 验证卸载结果
mysql --version
4、部署 Web 到 Linux
环境分为:开发环境 dev(开发时用的服务器),测试环境 test(测试人员测试时用的服务器),预发布环境 stage(用的真实用户数据,但是是内部人员使用发起的请求),灰度环境 prob(逐步上线,一开始只要少量服务器接收用户请求),发布环境/线上环境 prod(所有服务器都能接收用户请求)。
按这个过程,程序最终上线,就叫做部署。一般公司使用自动化部署工具(如 Jenkins),避免手动部署出错。
在服务器上创建数据库:
// 执行 .sql 脚本文件
source 脚本文件
(1)Spring Boot 多平台文件配置
修改 .yml 配置文件,比如数据库密码不一样。但是多个运行环境(idea 本地、服务器开发/测试……)配置文件改来改去很麻烦,就给不同运行环境有不同的 .yml 文件。
主配置文件:放公共的部分。@属性名@
# 哪个环境激活
spring:profiles:active: @profile.name@# 应用服务 WEB 访问端口
server:port: 8080
# Mybatis-Plus 配置
mybatis-plus:configuration:
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 配置打印 MyBatis ⽇志map-underscore-to-camel-case: true # 配置驼峰⾃动转换
# Spring Boot 日志配置
logging:logback:rollingPolicy:fileNamePattern: logs/spring_blog-%d{yyyy-MM-dd}-%i.logmax-file-size: 10MBmax-history: 30
配置 pom 文件:
<profiles><profile><id>dev</id><properties><profile.name>dev</profile.name></properties></profile><profile><id>prod</id><activation><activeByDefault>true</activeByDefault> // 默认激活</activation><properties><profile.name>prod</profile.name></properties></profile></profiles>
dev:
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/spring_blog?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: "hdalddnasl"driver-class-name: com.mysql.jdbc.Driver
prod:
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/spring_blog?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: "Zhamuyan200114@"driver-class-name: com.mysql.jdbc.Driver
(2)打包并上线
如果
clean >> 打包:
把 target 下的 jar 包上传到服务器,运行程序:
// 后台运行,就算把连接服务器的终端关闭了,也能运行
nohup 执行的命令(java -jar jar包) &// 也可以把输出的内容重定向到 指定文件
nohup 执行的命令(java -jar jar包) >文件名 &
查看程序是否运行:
云服务器开放端口号:若有多个端口号,以逗号分隔。
如果需要重启服务,需要先杀掉之前的服务进程,如 8080:kill -9 进程id
(3)存在的问题
① spring-boot-starter-parent 自带自动化的资源过滤,如果 springboot 项目没有指定 spring-boot-starter-parent 的话,使用 @@ 的时候就会报 ScannerException 异常:
解决方案:启用对 src/main/resources
目录下资源文件的过滤处理,允许通过占位符动态替换配置文件中的变量。在 build 下加入,主要只需要过滤配置文件,避免把前端静态资源也过滤了。
<resources><resource><directory>src/main/resources</directory><filtering>true</filtering><includes><include>**/application*</include></includes></resource><resource><directory>src/main/resources</directory><filtering>false</filtering><excludes><exclude>**/application*</exclude></excludes></resource></resources>
② jar中没有主清单属性错误。原因是 jar 包里的 META-INF 文件下的 MANIFEST.MF 中缺少 Main-Class 元素声明,即启动类所在包。
解决办法:
③ 服务器本地 root 用户运行的 Spring Boot 程序无法连接本地数据库的 root 用户。解决办法:
查看本地 root 用户的认证方式:
SELECT User, Host, plugin FROM mysql.user WHERE User = 'root' AND Host = 'localhost';
auth_socket 认证方式,只能通过本地(只能用 UNIX 的 socket 方式登陆)登录、操作系统用户必须与数据库用户同名。在服务器上 root 用户直接通过命令行连接本地 mysql (若不指定 --protocol=tcp,则默认通过本地的 mysqld.sock socket 文件连接)的 root 用户,无需登陆密码。而 JDBC 默认通过 TCP/IP 协议通信,所以会出现程序连接本地数据库失败。
解决办法1(不建议):直接将本地 root 用户认证方式改为 mysql_native_password,这样就是通过密码连接。不建议的原因是,不能使用本地 root 用户免密连接的功能;再一个是没有 只给业务用户 指定的数据库操作权限安全。
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '密码';
解决办法2(推荐):
// 创建专用业务用户
CREATE USER 'spring-blog'@'localhost' IDENTIFIED BY '你的密码';// 赋予数据库操作权限
GRANT ALL PRIVILEGES ON 数据库名.* TO 'spring-blog'@'localhost';// 刷新
FLUSH PRIVILEGES;
④ -parameters 参数问题。 IDEA 的 Java Compiler设置只影响本地编译,Maven/Gradle 打包时自行调用 Javac,不会读取 IDEA 的这些配置。
解决办法:在 maven 插件中配置参数。
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><compilerArgs><arg>-parameters</arg></compilerArgs></configuration>
</plugin>
⑤ 如果还有问题,可以查看日志跟踪。
tail -100f logs/spring_blog.log | grep 'Exception'
因为 Spring Boot 项目已经配置了日志持久化,不想 nohup 将输入保存到 nohup.out,可以使用以下命令丢弃:
nohup 命令 > /dev/null 2>&1 &// 表示将标准输出(stdout)重定向到 /dev/null(Linux/Unix 系统中的一个特殊文件,也被称为“黑洞”或“空设备”。),丢弃所有正常输出。
> /dev/null// 表示将标准错误输出(stderr)重定向到标准输出(stdout),也就是所有错误信息也一起丢弃。
2>&1// 表示在后台运行该命令
&