ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

全栈个人网站开发部署实战:Vue 3 + Spring Boot 3 从开发到上线

全栈个人网站开发部署实战:Vue 3 + Spring Boot 3 从开发到上线 从零到一上线个人网站听起来像是一个庞大的工程涉及前端、后端、部署、运维等多个环节。对于独立开发者或初学者而言最大的挑战往往不是某个具体的技术点而是如何将零散的知识点串联成一个可运行、可访问的完整系统。在这个过程中现代 AI 辅助编程工具如 ChatGPT、Claude Code和成熟的技术栈如 Vue 3、Spring Boot 3可以极大地提升效率但它们无法替代你对项目结构、环境配置和部署流程的系统性理解。本文将从一个全栈开发者的视角带你走一遍从本地开发到服务器上线的完整路径重点解释每个阶段的关键决策、具体操作和避坑指南让你不仅能把网站跑起来更能理解背后的“为什么”。1. 项目蓝图与技术选型明确目标与工具在动手写第一行代码之前清晰的项目蓝图和合理的技术选型是成功的基石。一个典型的个人网站可能包含展示页面如首页、关于、文章列表和一个简单的后台管理功能如发布文章。我们需要为此选择一套高效、易维护且学习曲线适中的技术栈。前端选型Vue 3 TypeScript ViteVue 3 的 Composition API 配合 TypeScript能提供更好的类型安全和代码组织能力非常适合中大型项目。Vite 作为构建工具其极快的冷启动和热更新速度能显著提升开发体验。这构成了我们前端的技术核心。后端选型Spring Boot 3 Java 17Spring Boot 3 要求最低 Java 17它带来了更好的性能、更清晰的模块划分以及对 Jakarta EE 9 的支持。对于个人网站这类 CRUD 操作居多的项目Spring Boot 能快速搭建 RESTful API并集成数据库、安全等组件成熟稳定。开发辅助AI 工具的正确打开方式AI 编程助手如 Cursor、GitHub Copilot或通过特定方式访问的 ChatGPT、Claude在此项目中主要扮演两个角色一是生成重复性样板代码如实体类、简单的 CRUD 接口二是解释错误信息和提供解决方案思路。但必须明确AI 生成代码需要经过你的审查和调试不能直接信任并部署。我们的原则是用 AI 提高效率用自身知识保证质量。环境清单在开始前请确保你的开发环境已就绪组件推荐版本作用验证命令Node.js18.x 或 20.x LTS前端运行与构建环境node -vnpm / yarn / pnpm最新稳定版前端包管理器npm -v或yarn -vJava17 或 21后端运行环境java -versionMaven3.8后端项目构建与依赖管理mvn -vIDEIntelliJ IDEA / VS Code代码编辑与调试-Git最新版版本控制git --versionMySQL / PostgreSQL8.0 / 14数据库任选其一mysql --version注意版本兼容性至关重要。Spring Boot 3.x 必须使用 Java 17并对应 Jakarta Servlet 规范。如果版本不匹配会在启动时遇到诸如ClassNotFoundException: javax.servlet...之类的错误。2. 前后端项目初始化与基础架构搭建有了蓝图我们开始创建项目骨架。这一步的目标是建立两个独立的工程前端 Vue 项目和后端 Spring Boot 项目并配置好基本的开发环境。2.1 创建 Vue 3 TypeScript Vite 前端项目打开终端进入你的工作目录执行以下命令创建项目# 使用 npm 创建 Vite 项目选择 Vue 和 TypeScript 模板 npm create vitelatest my-website-frontend -- --template vue-ts # 进入项目目录 cd my-website-frontend # 安装依赖 npm install # 安装路由和状态管理库根据需求选择 npm install vue-router4 pinia创建完成后项目结构大致如下my-website-frontend/ ├── index.html # 入口 HTML ├── package.json # 项目配置和依赖 ├── vite.config.ts # Vite 构建配置 ├── tsconfig.json # TypeScript 配置 ├── src/ │ ├── main.ts # 应用主入口 │ ├── App.vue # 根组件 │ ├── components/ # 可复用组件 │ ├── views/ # 页面级组件 │ ├── router/ # 路由配置需创建 │ ├── stores/ # Pinia 状态管理需创建 │ └── assets/ # 静态资源接下来配置路由。在src/router/index.ts中import { createRouter, createWebHistory } from vue-router import HomeView from ../views/HomeView.vue const router createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: /, name: home, component: HomeView }, { path: /about, name: about, component: () import(../views/AboutView.vue) // 路由懒加载 } // ... 其他路由 ] }) export default router在main.ts中引入并使用路由import { createApp } from vue import App from ./App.vue import router from ./router const app createApp(App) app.use(router) app.mount(#app)2.2 创建 Spring Boot 3 Java 17 后端项目使用 Spring Initializr 是最高效的方式。你可以通过 start.spring.io 网页生成或使用 IDE 的集成功能。关键依赖选择Spring Web: 构建 Web API。Spring Data JPA: 数据持久化。MySQL Driver或PostgreSQL Driver: 数据库驱动。Lombok: 简化实体类代码可选但推荐。生成并解压后项目结构如下my-website-backend/ ├── pom.xml # Maven 配置文件 ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── website/ │ │ │ ├── WebsiteApplication.java # 启动类 │ │ │ ├── controller/ # 控制器层 │ │ │ ├── service/ # 业务逻辑层 │ │ │ ├── repository/ # 数据访问层 │ │ │ └── entity/ # 实体类 │ │ └── resources/ │ │ ├── application.properties # 配置文件 │ │ └── ... │ └── test/ # 测试代码首先配置数据库连接。编辑src/main/resources/application.properties# 应用端口避免与前端冲突 server.port8080 # 数据库配置 (以MySQL为例) spring.datasource.urljdbc:mysql://localhost:3306/my_website_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai spring.datasource.usernameroot spring.datasource.passwordyour_password spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver # JPA 配置 spring.jpa.hibernate.ddl-autoupdate spring.jpa.show-sqltrue spring.jpa.properties.hibernate.dialectorg.hibernate.dialect.MySQL8Dialect spring.jpa.properties.hibernate.format_sqltrue注意spring.jpa.hibernate.ddl-autoupdate在开发初期很方便它可以自动根据实体类创建或更新表结构。但在生产环境中务必改为validate或none并使用 Flyway/Liquibase 等工具进行版本化的数据库迁移以避免数据丢失风险。2.3 解决前端开发时的跨域问题在前后端分离开发模式下前端运行在http://localhost:5173(Vite 默认)后端运行在http://localhost:8080浏览器会因同源策略阻止请求。我们可以在后端配置全局跨域支持。创建一个配置类src/main/java/com/example/website/config/WebConfig.javapackage com.example.website.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; Configuration public class WebConfig { Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { Override public void addCorsMappings(CorsRegistry registry) { // 允许前端开发服务器的地址跨域访问 registry.addMapping(/api/**) // 只对 /api 开头的接口生效 .allowedOrigins(http://localhost:5173) // 你的前端地址 .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true); } }; } }这样前端就可以通过fetch或axios访问http://localhost:8080/api/xxx了。3. 核心功能实现以文章管理为例我们以实现一个简单的文章发布与展示功能为例串联前后端。这涉及数据库设计、后端 API 创建和前端页面调用。3.1 后端实体、仓库、服务与控制器的四层架构1. 创建实体类 (Entity)定义文章的数据结构。使用 Lombok 减少样板代码。package com.example.website.entity; import jakarta.persistence.*; import lombok.Data; import java.time.LocalDateTime; Entity Data // Lombok 注解自动生成 getter, setter, toString 等 Table(name article) public class Article { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; Column(nullable false) private String title; Column(columnDefinition TEXT) // 使用 TEXT 类型存储长内容 private String content; Column(name created_at) private LocalDateTime createdAt; Column(name updated_at) private LocalDateTime updatedAt; PrePersist protected void onCreate() { createdAt LocalDateTime.now(); updatedAt LocalDateTime.now(); } PreUpdate protected void onUpdate() { updatedAt LocalDateTime.now(); } }2. 创建仓库接口 (Repository)Spring Data JPA 会根据方法名自动实现 SQL。package com.example.website.repository; import com.example.website.entity.Article; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; Repository public interface ArticleRepository extends JpaRepositoryArticle, Long { // 可以定义自定义查询例如根据标题模糊查询 // ListArticle findByTitleContaining(String keyword); }3. 创建服务类 (Service)封装业务逻辑。package com.example.website.service; import com.example.website.entity.Article; import com.example.website.repository.ArticleRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; Service public class ArticleService { Autowired private ArticleRepository articleRepository; public ListArticle findAll() { return articleRepository.findAll(); } public OptionalArticle findById(Long id) { return articleRepository.findById(id); } public Article save(Article article) { return articleRepository.save(article); } public void deleteById(Long id) { articleRepository.deleteById(id); } }4. 创建 REST 控制器 (Controller)暴露 HTTP API 接口。package com.example.website.controller; import com.example.website.entity.Article; import com.example.website.service.ArticleService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; RestController RequestMapping(/api/articles) // 所有接口以 /api 开头便于管理 public class ArticleController { Autowired private ArticleService articleService; GetMapping public ResponseEntityListArticle getAllArticles() { return ResponseEntity.ok(articleService.findAll()); } GetMapping(/{id}) public ResponseEntityArticle getArticleById(PathVariable Long id) { return articleService.findById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } PostMapping public ResponseEntityArticle createArticle(RequestBody Article article) { Article savedArticle articleService.save(article); return ResponseEntity.ok(savedArticle); } // 更新和删除接口省略逻辑类似 }启动后端应用访问http://localhost:8080/api/articles应该返回一个空数组[]。此时JPA 应该已经在数据库中自动创建了article表。3.2 前端页面组件与 API 调用1. 安装并配置 HTTP 客户端我们使用axios。npm install axios创建一个src/utils/request.ts文件来封装 axios 实例import axios from axios const request axios.create({ baseURL: http://localhost:8080/api, // 后端 API 基础地址 timeout: 10000 // 请求超时时间 }) // 请求拦截器 request.interceptors.request.use( (config) { // 如果需要可以在这里统一添加 token // const token localStorage.getItem(token) // if (token) { // config.headers.Authorization Bearer ${token} // } return config }, (error) { return Promise.reject(error) } ) // 响应拦截器 request.interceptors.response.use( (response) { // 对响应数据做点什么 return response.data }, (error) { // 对响应错误做点什么 console.error(API Request Error:, error.response?.data || error.message) return Promise.reject(error) } ) export default request2. 创建文章列表页面在src/views/ArticlesView.vue中template div classarticles h1文章列表/h1 div v-ifloading加载中.../div div v-else ul li v-forarticle in articles :keyarticle.id router-link :to/article/${article.id} {{ article.title }} /router-link span - {{ formatDate(article.createdAt) }}/span /li /ul /div /div /template script setup langts import { ref, onMounted } from vue import request from /utils/request import { useRouter } from vue-router interface Article { id: number title: string content: string createdAt: string updatedAt: string } const articles refArticle[]([]) const loading ref(true) const router useRouter() const fetchArticles async () { try { const data await request.get(/articles) articles.value data } catch (error) { console.error(获取文章列表失败:, error) // 这里可以添加用户提示例如使用 Element Plus 的 Message 组件 } finally { loading.value false } } const formatDate (dateString: string) { return new Date(dateString).toLocaleDateString() } onMounted(() { fetchArticles() }) /script style scoped .articles { padding: 20px; } ul { list-style: none; padding: 0; } li { margin-bottom: 10px; padding: 10px; border-bottom: 1px solid #eee; } /style3. 配置路由在src/router/index.ts中添加这个页面的路由{ path: /articles, name: articles, component: () import(../views/ArticlesView.vue) }现在运行前端 (npm run dev) 和后端访问http://localhost:5173/articles你应该能看到文章列表页面。虽然目前没有数据但前后端通信的通道已经打通。4. 项目构建与生产环境部署本地开发完成后我们需要将代码构建成生产环境可用的形式并部署到服务器。这是从“能运行”到“能访问”的关键一步。4.1 前端构建与优化Vite 提供了开箱即用的生产构建命令。在项目根目录执行npm run build这个命令会在项目根目录下生成一个dist文件夹里面包含了所有静态资源HTML、CSS、JS、图片等这些文件可以直接被任何静态文件服务器托管。构建优化配置 (vite.config.ts):import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], build: { // 构建输出目录 outDir: dist, // 生成静态资源的存放目录 assetsDir: assets, // 小于此阈值的导入或引用资源将内联为 base64 编码 assetsInlineLimit: 4096, // 启用/禁用 CSS 代码拆分 cssCodeSplit: true, // 构建后是否生成 source map 文件 sourcemap: false, // 生产环境建议关闭 // 自定义底层的 Rollup 打包配置 rollupOptions: { output: { // 对代码分割产生的 chunk 自定义命名 chunkFileNames: assets/js/[name]-[hash].js, entryFileNames: assets/js/[name]-[hash].js, assetFileNames: assets/[ext]/[name]-[hash].[ext] } } }, // 开发服务器配置与生产无关 server: { port: 5173, open: true } })4.2 后端构建与打包Spring Boot 使用 Maven 或 Gradle 打包。最常用的方式是生成一个可执行的 JAR 文件它内嵌了 Tomcat 服务器。在项目根目录执行mvn clean package -DskipTests命令执行成功后在target目录下会生成一个my-website-backend-0.0.1-SNAPSHOT.jar文件文件名取决于你的pom.xml中的artifactId和version。这个 JAR 包包含了应用本身及其所有依赖。关键配置检查 (application.properties 生产环境版):在生产环境我们需要一个独立的配置文件例如application-prod.properties并通过激活prodprofile 来使用它。# src/main/resources/application-prod.properties server.port8080 # 生产数据库配置务必修改 spring.datasource.urljdbc:mysql://YOUR_DB_HOST:3306/my_website_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse spring.datasource.usernamePROD_DB_USER spring.datasource.passwordSTRONG_PASSWORD # 生产环境 JPA 配置禁止自动更新表结构 spring.jpa.hibernate.ddl-autovalidate spring.jpa.show-sqlfalse # 生产环境关闭 SQL 日志 # 日志配置 logging.level.rootINFO logging.level.com.example.websiteDEBUG # 可根据需要调整 # 激活生产环境配置 spring.profiles.activeprod打包时可以通过命令行参数指定激活的 profilejava -jar my-website-backend-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod4.3 服务器环境准备与部署假设你拥有一台云服务器如阿里云、腾讯云 ECS系统为 CentOS 7/8 或 Ubuntu 20.04/22.04。1. 服务器基础环境配置通过 SSH 登录服务器后执行以下命令# 更新系统包 sudo yum update -y # CentOS # 或 sudo apt update sudo apt upgrade -y # Ubuntu # 安装 Java 17 # CentOS sudo yum install -y java-17-openjdk-devel # Ubuntu sudo apt install -y openjdk-17-jdk # 验证安装 java -version # 安装 MySQL (以 Ubuntu 为例) sudo apt install -y mysql-server sudo systemctl start mysql sudo systemctl enable mysql # 运行安全脚本设置 root 密码等 sudo mysql_secure_installation # 登录 MySQL创建数据库和用户 mysql -u root -p在 MySQL 命令行中CREATE DATABASE my_website_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER website_user% IDENTIFIED BY YourStrongPassword123!; GRANT ALL PRIVILEGES ON my_website_db.* TO website_user%; FLUSH PRIVILEGES; EXIT;2. 部署后端 JAR 包将本地打包好的 JAR 文件上传到服务器。可以使用scp命令# 在本地终端执行 scp target/my-website-backend-0.0.1-SNAPSHOT.jar usernameyour_server_ip:/home/username/在服务器上创建一个专门的应用目录并运行# 在服务器上操作 mkdir -p /opt/mywebsite/backend mv /home/username/my-website-backend-0.0.1-SNAPSHOT.jar /opt/mywebsite/backend/ cd /opt/mywebsite/backend # 创建生产环境配置文件 vi application-prod.properties # 将本地准备好的 application-prod.properties 内容粘贴进去并保存 # 使用 nohup 在后台运行并将日志输出到文件 nohup java -jar my-website-backend-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod app.log 21 3. 部署前端静态资源将前端dist目录下的所有文件上传到服务器。我们可以使用 Nginx 作为静态文件服务器和反向代理。安装 Nginx# CentOS sudo yum install -y nginx # Ubuntu sudo apt install -y nginx配置 Nginx。编辑配置文件/etc/nginx/nginx.conf或/etc/nginx/sites-available/default(Ubuntu)server { listen 80; server_name your_domain.com; # 你的域名如果没有就写服务器 IP # 前端静态资源 location / { root /opt/mywebsite/frontend/dist; # 前端构建文件存放路径 index index.html; try_files $uri $uri/ /index.html; # 支持 Vue Router 的 history 模式 } # 反向代理到后端 API 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; proxy_set_header X-Forwarded-Proto $scheme; } }创建前端文件目录并上传文件mkdir -p /opt/mywebsite/frontend/dist # 使用 scp 或 sftp 将本地 dist/ 下的所有文件上传到此目录检查 Nginx 配置并重启sudo nginx -t # 测试配置语法 sudo systemctl restart nginx # 重启 Nginx sudo systemctl enable nginx # 设置开机自启现在通过浏览器访问你的服务器 IP 或域名应该就能看到网站了。前端页面由 Nginx 直接提供当它需要调用 API 时如/api/articlesNginx 会将请求转发给运行在 8080 端口的 Spring Boot 应用。5. 上线后的关键运维与排查指南网站上线只是开始保证其稳定运行更为重要。以下是几个核心的运维和排查场景。5.1 服务进程管理使用 Systemd使用nohup和运行服务不够可靠进程容易意外退出。推荐使用 Systemd 来管理 Spring Boot 应用。创建服务单元文件/etc/systemd/system/mywebsite.service[Unit] DescriptionMy Website Backend Service Afternetwork.target mysql.service [Service] Typesimple Userwww-data # 或一个专门的用户如 appuser WorkingDirectory/opt/mywebsite/backend ExecStart/usr/bin/java -jar my-website-backend-0.0.1-SNAPSHOT.jar --spring.profiles.activeprod SuccessExitStatus143 Restartalways RestartSec10 StandardOutputjournal StandardErrorjournal [Install] WantedBymulti-user.target然后启用并启动服务sudo systemctl daemon-reload sudo systemctl enable mywebsite.service sudo systemctl start mywebsite.service # 查看状态和日志 sudo systemctl status mywebsite.service sudo journalctl -u mywebsite.service -f # 实时查看日志5.2 常见问题排查清单当网站无法访问或功能异常时可以按以下顺序排查问题现象可能原因检查命令/位置解决方案浏览器无法访问服务器 IP服务器防火墙未开放 80/443 端口sudo firewall-cmd --list-ports(CentOS)sudo ufw status(Ubuntu)开放端口sudo firewall-cmd --add-port80/tcp --permanent sudo firewall-cmd --reload访问域名显示 Nginx 默认页Nginx 配置未生效或站点配置错误sudo nginx -t检查/etc/nginx/sites-enabled/下的链接修正配置并sudo systemctl reload nginx前端页面加载但 API 调用失败 (404/502)后端服务未启动或 Nginx 代理配置错误sudo systemctl status mywebsitecurl http://127.0.0.1:8080/api/articles启动后端服务检查 Nginxproxy_pass地址是否正确后端启动失败报Port 8080 already in use端口被占用或旧进程未退出sudo netstat -tlnp | grep :8080终止占用进程或修改server.port后端启动失败报数据库连接错误数据库配置错误、网络不通或权限不足检查application-prod.properties中的 JDBC URL、用户名密码从服务器mysql -u website_user -p -h localhost测试连接修正配置确保数据库用户有远程连接权限 (website_user%)前端构建后页面空白或资源 404资源路径错误或路由 history 模式未配置浏览器开发者工具 Network 面板查看具体哪个资源 404检查vite.config.ts中的base配置配置 Nginxtry_files如果项目部署在子路径设置base: /subpath/修改了后端代码重新打包后服务未更新旧 JAR 包进程仍在运行ps aux | grep java找到旧进程 PID先sudo systemctl stop mywebsite替换 JAR 包后再sudo systemctl start mywebsite5.3 基础安全与优化建议配置 HTTPS使用 Let‘s Encrypt 免费证书通过 Certbot 工具为 Nginx 配置 SSL强制 HTTP 跳转到 HTTPS。数据库安全生产环境切勿使用root用户连接应用。数据库密码应足够复杂并定期更换。考虑将数据库置于内网仅允许应用服务器访问。应用安全在application-prod.properties中设置management.endpoints.web.exposure.includehealth,info仅暴露必要的监控端点。使用环境变量或配置中心管理敏感信息如数据库密码而不是硬编码在配置文件中。性能监控配置日志轮转避免日志文件无限增大。可以使用logback-spring.xml配置。使用spring-boot-starter-actuator添加健康检查端点/actuator/health便于监控服务状态。备份策略定期备份数据库mysqldump -u username -p database_name backup_$(date %Y%m%d).sql备份应用配置文件。可以考虑将备份文件同步到对象存储如阿里云 OSS或其他服务器。从零到一上线网站是一个系统工程它考验的不仅是编码能力更是对开发流程、环境配置、部署运维和问题排查的综合掌握。AI 工具在代码生成和问题解答上提供了巨大助力但它无法替代你对项目架构的思考和决策。建议你在完成这个基础版本后逐步引入更专业的工具链使用 Docker 容器化部署来保证环境一致性使用 CI/CD如 GitHub Actions自动化构建和部署流程使用 Prometheus 和 Grafana 进行监控。这些步骤将把你的个人网站项目从一个“玩具”升级为一个真正可维护、可扩展的线上服务。
返回列表