ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Java项目从Windows到Linux服务器部署全流程实战指南

Java项目从Windows到Linux服务器部署全流程实战指南 很多同学在Windows上把Java项目跑得飞起一到Linux服务器上部署就手足无措。这很正常Windows和Linux的思维方式、命令体系、环境管理方式完全是两套逻辑平时课程设计和课设都在IDE里点按钮突然要面对纯命令行环境懵是必然的。但这恰恰是毕设答辩时最能拿分的地方——一个能独立完成从编码到上线的完整链路说明你不只是会写代码还懂工程化落地。这篇实践指南就是冲着这个目标去的。我会从开发机的环境准备开始一路走到打包、部署、配置、调优把整个流程中容易踩坑的细节全部过一遍所有步骤都是我在真实项目中验证过的。无论你是第一次接触Linux的Java初学者还是想把手里的毕设项目完整部署上线的同学照着做就能少走很多弯路。1. 毕设项目为什么要选Java Linux这条路线先说个很多人没想明白的问题Java是跨平台的Windows上能跑为什么非得折腾Linux答案很简单因为生产环境就是Linux的天下你去任何一家公司线上跑的Java服务几乎清一色是Linux服务器。从技术角度讲Java服务的典型架构是Spring Boot MySQL Redis这类组合这些组件在Linux下的稳定性和性能表现远优于Windows。Linux本身是开源免费的没有Windows Server那种授权成本而且对内存和进程的管理更精细尤其适合跑长时间运行的Web服务。做毕设时如果你把项目部署在Linux上答辩老师问为什么选Linux部署你能说出上面这些理由印象分会差很多。还有一点现在很多毕设题目本身就涉及微服务、Docker容器化、前后端分离这些内容这些东西在Windows上体验很差。比如DockerWindows上要用Hyper-V虚拟化要么就得用Docker Desktop那个笨重的方案而Linux原生支持容器体验完全不是一个级别。所以这条路线不只是为了应付毕设更是提前熟悉真实的工作环境。角色的划分也要提前想清楚。你的开发机笔记本继续用Windows日常编码、调试都在上面完成。另外准备一台Linux环境——可以是云服务器学生优惠买一台很便宜也可以是本地的虚拟机这台机器就是你的生产环境。开发机负责写代码Linux负责跑代码两个环境各司其职。如果你连虚拟机都懒得装直接买一台1核2G的云服务器也够用还能顺带练习服务器运维一举两得。2. 开发机上的工具链准备JDK、Maven与IDEA的取舍大部分同学的开发机是Windows这一步反而是整个流程里最简单的因为IDE已经帮你处理好了绝大多数环境变量问题。但有几个细节值得注意处理不好后面部署时会有麻烦。2.1 JDK版本怎么选——别一上来就装最新版如果你的毕设项目是基于Spring Boot 2.x的老老实实用JDK 8或JDK 11。Spring Boot 2.7是最后一个支持JDK 8的大版本很多教学项目、毕设项目还在用这个版本。如果你用的是Spring Boot 3.x那必须JDK 17及以上因为Spring Boot 3底层是基于Jakarta EE的JDK 8跑不了。我见过最坑的情况是同学在Windows上用的JDK 17写的代码本地跑得好好的部署到服务器发现服务器装的是JDK 8一启动直接报UnsupportedClassVersionError。所以装之前先确认你的pom.xml里Spring Boot的版本然后决定JDK版本开发机和服务器保持一致这个不能偷懒。Windows下安装JDK推荐用安装包方式装完之后手动配置环境变量。很多教程让你去系统属性-高级-环境变量里新建JAVA_HOME然后改Path这样做没问题。但我建议你额外做一步在Path里加上%JAVA_HOME%\bin的同时把系统里可能存在的其他Java路径全部清掉。有些机器装了Oracle自带JRE、或者某些软件捆绑了JDKPath里同时存在多个Java路径时java -version输出的可能不是你想要的版本。检查方法很简单java -version javac -version两个命令的版本号必须一致不一致就说明环境变量有冲突。2.2 Maven仓库配置——别忽视这个隐藏瓶颈Maven是Java项目构建的标配但很多同学用IDEA自带的Maven压根不知道配置文件在哪。如果你发现项目构建时下载依赖特别慢多半是没配国内镜像源。修改%MAVEN_HOME%\conf\settings.xml或者用户目录下的.m2\settings.xml在mirrors节点里加上阿里云镜像mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror这个配置能让你从等依赖下载等到怀疑人生变成几秒钟拉完所有包。另一个建议是把settings.xml里的localRepository指向一个非C盘的目录比如D:\maven-repo避免系统盘空间被撑爆。一个大型项目的依赖仓库轻轻松松好几个GB放在C盘迟早出问题。2.3 IDEA里必须检查的两个项目配置在IDEA里有两处配置经常被忽略但对后续打包部署影响重大。第一处是File - Project Structure - Project确认Project SDK选的是你刚才装的JDK版本Project language level也对应好。这里如果选错编译时不会报错但打包出来的字节码版本可能和服务器不兼容。第二处是File - Settings - Build, Execution, Deployment - Compiler - Java Compiler把-parameters加到编译器参数里这样编译出的代码会保留参数名元数据对Spring MVC的参数绑定和MyBatis的映射都有帮助。不加的话某些低版本的Spring Boot在接收请求参数时可能拿到null。还有个小细节项目的.gitignore必须把.idea目录、target目录和*.iml文件加进去。如果这些文件被提交到仓库你换一台机器拉代码后IDEA会各种报错还得花时间清理缓存。3. Linux服务器环境搭建从裸机到能跑Java项目这一步是整个毕设里技术含量最高、也最容易出问题的地方。我在帮学弟学妹排查问题时发现环境搭建的错误占了至少六成。这里我把每一步详细拆开你照着做就行。3.1 系统选择与初始化配置云服务器推荐选Ubuntu 20.04 LTS或22.04 LTSCentOS 7虽然经典但已经停止维护了CentOS Stream的坑也不少对新手不友好。Ubuntu的文档多遇到问题搜索起来方便软件源也新装什么都很顺利。拿到服务器后第一件事是更新系统并创建普通用户。很多人习惯直接拿root干活这可以理解但为了安全起见我建议创建一个带sudo权限的普通用户apt update apt upgrade -y adduser devuser usermod -aG sudo devuser这里插一句云服务器的安全组规则一定要确认。很多同学在服务器里配好了防火墙结果外部还是连不上最后发现是云控制台的安全组没放行端口。安全组是云平台层面的防火墙是系统层面的两层都要放行才能通。所以你的云服务器控制台里安全组的入方向规则要加一条放行8080端口或者你项目要用的端口否则系统防火墙配得再好也没用。3.2 JDK安装用包管理器还是手动装Ubuntu上安装JDK有两种方式。apt install openjdk-8-jdk或apt install openjdk-11-jdk即可完成安装非常省事。但有些场景你需要特定版本的JDK比如甲骨文JDK或者某个特殊的发行版那就得手动装了。手动装其实也很简单从官网下载tar.gz包后解压、配置环境变量即可。需要注意你下载的版本要和开发机保持一致。我给的命令是把JDK装在/usr/local/javatar -zxvf jdk-17_linux-x64_bin.tar.gz -C /usr/local/java vim /etc/profile在文件末尾追加export JAVA_HOME/usr/local/java/jdk-17.0.x export PATH$JAVA_HOME/bin:$PATH然后source /etc/profile生效。手动装的好处是版本完全可控缺点是升级时得自己操作。对毕设来说用apt装官方OpenJDK完全够用省时省力。验证安装成功的标准是java -version which java第一条能看到版本号第二条能显示路径就说明OK了。3.3 MySQL 8.0的安装与远程访问坑点MySQL是JavaWeb项目的核心数据库安装时我推荐直接用aptapt install mysql-server装完后运行mysql_secure_installation做安全配置设置root密码。但这里有个大坑Ubuntu上MySQL默认的root用户是auth_socket认证只能用sudo mysql方式登录不支持密码登录。你需要改成密码认证sudo mysql ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;这样以后就可以用mysql -uroot -p方式登录了。如果你的项目代码要从开发机直连数据库比如在IDEA里跑项目然后连服务器数据库还需要创建一个远程访问用户CREATE USER testuser% IDENTIFIED BY 密码; GRANT ALL PRIVILEGES ON *.* TO testuser%; FLUSH PRIVILEGES;同时修改/etc/mysql/mysql.conf.d/mysqld.cnf里的bind-address为0.0.0.0否则MySQL只会监听本地端口远程连接直接拒绝。3.4 Redis安装——学生项目尽量少用Windows版如果毕设项目里用了Redis做缓存现在很常见务必在Linux上装Redis。虽然Redis官方早就支持Windows但Windows版停止更新很久而且性能表现差距很大。Linux下安装apt install redis-server systemctl enable redis-server systemctl start redis-server这里做个提示Redis默认配置只监听127.0.0.1如果你的Java项目部署在同一台机器的Docker容器里那没问题localhost就能访问。如果你打算把Java项目也装在宿主机上直接跑java -jar同样不需要改这个配置。只有远程连接Redis才需要改bind和protected-mode。对毕设来说建议保持默认安全性更好。4. 项目打包与部署方式选型jar、war还是Docker这是你在毕设答辩中一定能被问到的问题。提前想清楚每一种方式的适用场景对你加深理解大有帮助。4.1 打jar包直接运行——最主流最省心的方案Spring Boot最常用的部署方式就是打成可执行jar包然后java -jar直接跑。这个方式最简单不需要额外装Tomcat因为Spring Boot内嵌了Tomcat一个jar包就是一个完整的Web应用。在IDEA右侧的Maven面板执行package命令或者在项目根目录执行mvn clean package -DskipTests打包完成后target目录下会生成一个项目名-0.0.1-SNAPSHOT.jar。把这个jar包上传到服务器然后java -jar 项目名-0.0.1-SNAPSHOT.jar服务启动后浏览器访问http://服务器IP:8080就能看到页面了。这个方案唯一的缺点是如果你在IDEA里改了代码需要重新打包、重新上传、重新启动步骤略多。改进办法后面讲对接Git的自动化部署时再说。4.2 打war包丢进外部Tomcat——老派但答辩时能展示功底如果你的毕设题目明确要求使用外部Tomcat或者你用的还是传统的SSH框架Spring MVC Spring MyBatis没有内嵌容器那需要打成war包。Spring Boot项目打成war包需要做两步调整第一修改pom.xml把打包方式从jar改为warpackagingwar/packaging第二修改启动类继承SpringBootServletInitializer并重写configure方法SpringBootApplication public class DemoApplication extends SpringBootServletInitializer { Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(DemoApplication.class); } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }然后打包把生成的war包丢到Tomcat的webapps目录下启动Tomcat就能自动解压部署。Tomcat安装不复杂下载tar.gz包解压后修改bin/startup.sh给JVM加内存参数就行JAVA_OPTS-Xms512m -Xmx1024m4.3 Docker部署——毕设加分项但别为了用而用如果时间充裕强烈建议学一下Docker。Linux上装Docker很简单curl -fsSL https://get.docker.com | bash systemctl enable docker systemctl start docker装好之后写一个Dockerfile把你的jar包做成镜像FROM openjdk:17-jdk-slim WORKDIR /app COPY target/demo-0.0.1-SNAPSHOT.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar]然后构建并运行docker build -t demo:latest . docker run -d --name demo -p 8080:8080 demo:latest这样你的应用就容器化运行了。答辩时老师问起Docker的优势你能说出镜像实现环境一致、容器秒级启停、资源隔离这些话已经比很多人强了。但注意Docker不适合所有场景如果项目里用了大量的本地文件存储、或者依赖宿主机上的特殊设备容器的运维复杂度会明显上升。毕设项目用它来展示容器化部署的思路就足够了。4.4 三种方式的选型原理与推荐我给学生推荐的原则是默认选jar包直跑这是最稳定、最好排障的方式。如果项目里已经有现成的Docker环境或者你对Docker熟悉那选Docker展示能力也不错。传统SSH项目或者明确要求用Tomcat的选war包。务必避开的坑是打出来的jar包在本地能跑到服务器上就报无法找到主类或者jar包损坏。这个问题九成是因为打包时机不对——IDEA里package前没执行cleantarget目录里混入了旧编译产物。解决方式是养成clean package连用的习惯不要单独执行package。5. 部署上线后的运维实用操作日志、进程与开机自启项目跑起来只是开始真正考验动手能力的是后续的运维操作。这部分内容虽然基础但极其实用我逐个讲清楚。5.1 用systemd管好你的Java进程直接java -jar启动最大的问题是终端一关进程就死了。而且进程在后台无法管理崩溃了也不会自动拉起。解决方法是配置systemd服务。在/etc/systemd/system/下新建一个demo.service文件[Unit] DescriptionDemo Spring Boot Application Afternetwork.target mysql.service redis-server.service [Service] Userdevuser WorkingDirectory/opt/demo ExecStart/usr/bin/java -Xms512m -Xmx1024m -jar /opt/demo/demo-0.0.1-SNAPSHOT.jar Restartalways RestartSec10 StandardOutputappend:/var/log/demo/app.log StandardErrorappend:/var/log/demo/error.log [Install] WantedBymulti-user.target配置好之后systemctl daemon-reload systemctl enable demo systemctl start demo这样你的Java服务就变成了一个完全受systemd管理的系统服务开机自动启动、崩溃自动拉起、日志统一收集。管理起来只需要记住几条命令systemctl status demo查看运行状态、systemctl restart demo重启、journalctl -u demo查看日志。这里特别提醒WorkingDirectory必须和jar包所在目录一致否则Spring Boot读取外部配置文件比如application-prod.yml时会找不到文件。我踩过这个坑因为直接java -jar启动时默认工作目录是当前目录而systemd启动时默认工作目录是/文件路径不一致导致配置没加载服务起来却连不上数据库。5.2 日志排查三板斧磁盘、内存、进程服务出问题时先别急着看代码。按照下面的顺序排查90%的问题都能定位到。第一看磁盘够不够用df -hJava服务写日志是无底洞尤其是项目里用了Logback或Log4j2但没配滚动策略时几天就能写满几个G。日志占满磁盘后MySQL会拒绝写入服务会变得极其卡顿表面上看起来像死锁其实是磁盘满了。第二看内存够不够free -hJava进程默认最多用物理内存的1/4如果你的服务器只有2G内存而JVM默认堆大小是512M再算上MetaSpace和线程栈很容易内存溢出。用-Xmx256m限制最大堆能有效避免这个问题或者干脆升级服务器配置。第三看进程还活着没ps -ef | grep java如果进程存在但服务不通多半是端口被占了或者网络问题如果进程不存在查看systemd的状态看重启报错信息。这里需要补一句Spring Boot项目如果配置了server.port但端口被占用启动会直接失败用netstat -tlnp | grep 8080可以快速确认端口占用情况。5.3 Nginx反向代理——用80端口访问你的8080项目很多毕设项目的架构是Vue前端打包成静态文件Java后端跑在8080端口数据库3306端口。直接让用户访问http://IP:8080不是不行但不够正规而且想用80端口访问就得装Nginx做反向代理。安装与配置apt install nginx修改/etc/nginx/sites-available/defaultserver { listen 80; server_name _; # 前端静态资源 location / { root /opt/frontend/dist; index index.html; try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }这个配置是前后端分离项目最常见的形态直接访问80端口看到的是前端页面/api/开头的请求被转发到后端的8080端口。配置完成后nginx -t systemctl reload nginx这里有个注意点如果你的项目里使用了WebSocket比如实时的消息推送或者在线聊天功能Nginx的location /api/需要额外加上Upgrade相关的头否则WebSocket连接会被Nginx拦截proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade;这个细节很容易被忽略等线上WebSocket连不上时再查能查半天。6. 常见故障的排查链路与安全加固建议到这一步项目已经跑通了但毕设答辩前你最好把下面这些坑也提前踩一遍。我按真实场景的排查链路来写你看完就能举一反三。6.1 连接超时决定先查防火墙还是先查安全组场景本地能访问服务器IP但8080端口超时。排查顺序应该是curl http://127.0.0.1:8080在服务器本机测试端口通不通——如果本机通、外部不通那问题一定在云控制台的安全组或者系统防火墙iptables/ufw的规则。如果本机也不通那就是应用没启动成功回去看日志。用这个顺序排查能把防火墙问题和应用问题快速区分开不浪费时间。99%的新手连接不上都栽在这上面。6.2 数据库连接报错密码、时区、版本一个都不能少Java连MySQL最经典的报错是Access denied for user和The server time zone value XXX is unrecognized。前者是密码或者host不匹配检查你的数据库用户到底有没有远程访问权限后者是JDBC连接串里缺了时区参数在jdbc:mysql://localhost:3306/demo后面加上?serverTimezoneAsia/Shanghai即可解决。MySQL 8.0的驱动还要求连接串里带useSSLfalseallowPublicKeyRetrievaltrue否则会报公钥检索错误。这些都是毕设里非常常见的小问题配好一次记牢即可。6.3 安全加固三板斧部署上线后至少做以下三件事再交给答辩老师第一修改SSH默认端口。编辑/etc/ssh/sshd_config把Port 22改成Port 2222然后重启SSH服务。这样可以极大减少被暴力扫描的风险代价是你以后SSH连接时得带-p 2222参数。第二防火墙只放行必要端口。用UFW的话ufw allow 2222/tcp ufw allow 80/tcp ufw allow 8080/tcp ufw allow 3306/tcp ufw enable3306端口是否放行取决于你是否需要远程连数据库如果不需要请务必关上。第三MySQL的root密码别用root、123456这种至少用一个大小写字母加数字混合的强度。如果一个攻破了你的服务器拿到的也是弱密码的数据库那就是雪上加霜。安全这块不用做得太复杂毕设项目本来就面向教学展示保持基本的安全卫生习惯就够了。7. 一个额外的建议用版本控制管理你的部署我接触过的很多同学部署的时候还在用本地打jar包 - 用SCP工具上传 - 手动重启这种操作。这种方式做一次两次还行每次改代码都要重来一遍非常容易出错。如果你愿意多花半小时配一条自动化的路之后的体验会完全不同。流程大致是在服务器上装好Git拉取你的项目代码然后用Maven直接在服务器上打包运行git pull mvn clean package -DskipTests systemctl restart demo这三条命令就是在服务器上更新版本的全过程了。配合Git的tag功能你还可以在每次答辩演示前打一个稳定的tag需要回滚时随时切回去。不过这个方案的前提是服务器内存至少要2G以上因为构建过程内存占用不小。如果配置太低还是建议本地打包再上传避免构建时内存溢出。关于这条自动化链路我个人的体验是做完之后我调代码的速度至少快了一倍因为省去了无数次上传。更关键的是不用再盯着文件传输进度条发呆可以把精力真正放到代码本身。这套流程跑通以后你基本就有了一个可持续迭代的开发节奏也不用手忙脚乱地去别的地方找替代方案了。
返回列表