当前位置: 首页 > news >正文

使用springboot2.6、vue2.6以及mysql从0开始搭建个人博客网页

从零开始搭建博客网站:使用 Spring Boot 2.6、Vue 2.6 和 MySQL

搭建一个简单的博客网站从零开始,需要覆盖数据库设计、后端 API 开发(Spring Boot 处理 CRUD 操作)和前端界面(Vue 处理用户交互)。这个教程基于一个典型的博客模型:文章(Post)包括标题、内容、发布状态和作者。我们将实现基本的 CRUD 功能(创建、读取、更新、删除文章),并添加搜索和列表显示。整个过程假设你有基本的 Java、JavaScript 和 SQL 知识。

前提环境准备:

  • 安装 JDK 8/11/17(Spring Boot 2.6 兼容这些版本)。
  • 安装 MySQL 5.7 或更高版本。
  • 安装 Node.js 和 npm(用于 Vue)。
  • IDE:IntelliJ IDEA 或 Eclipse(后端),VS Code(前端)。
  • Maven(后端构建工具)。

预计时间:2-4 小时,视经验而定。

1. 数据库设计(MySQL)

首先,设计数据库 schema。我们使用一个简单的 posts 表来存储博客文章。

步骤:

  1. 启动 MySQL,创建一个数据库:

    CREATE DATABASE blogdb;
    USE blogdb;
    
  2. 创建表 posts

    CREATE TABLE posts (id BIGINT AUTO_INCREMENT PRIMARY KEY,title VARCHAR(255) NOT NULL,content TEXT,published BOOLEAN DEFAULT FALSE,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );
    
    • id:文章唯一 ID,自增主键。
    • title:文章标题。
    • content:文章内容。
    • published:是否发布(布尔值)。
    • created_at:创建时间。
  3. (可选)插入测试数据:

    INSERT INTO posts (title, content, published) VALUES 
    ('第一篇博客', '这是我的第一篇博客内容。', TRUE),
    ('Spring Boot 学习笔记', 'Spring Boot 是快速开发框架。', FALSE);
    

Spring Boot 将通过 JPA 自动管理 schema 更新,无需手动维护。

2. 后端开发(Spring Boot 2.6)

后端使用 Spring Boot 2.6 构建 RESTful API,支持文章的 CRUD 和按标题搜索。

步骤:

  1. 创建项目

    • 访问 Spring Initializr,选择:
      • Project: Maven
      • Language: Java
      • Spring Boot: 2.6.x(最新 2.6 版本)
      • Dependencies: Spring Web、Spring Data JPA、MySQL Driver
    • 下载并导入 IDE,项目名为 blog-backend
  2. 配置 pom.xml(添加依赖,如果 Initializr 未包含):

    org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-data-jpamysqlmysql-connector-javaruntime
  3. 配置 application.properties(src/main/resources/application.properties):

    spring.datasource.url=jdbc:mysql://localhost:3306/blogdb?useSSL=false&serverTimezone=UTC
    spring.datasource.username=root
    spring.datasource.password=your_passwordspring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
    spring.jpa.hibernate.ddl-auto=update
    spring.jpa.show-sql=true
    
    • 替换 your_password 为你的 MySQL 密码。
    • ddl-auto=update:自动创建/更新表(生产环境改为 validate)。
  4. 创建实体类(model 包下,新建 Post.java):

    package com.example.blog.model;import javax.persistence.*;@Entity
    @Table(name = "posts")
    public class Post {@Id@GeneratedValue(strategy = GenerationType.AUTO)private Long id;@Column(name = "title")private String title;@Column(name = "content")private String content;@Column(name = "published")private boolean published;// 无参构造函数public Post() {}// Getters 和 Setters(使用 Lombok 或手动添加)public Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getTitle() { return title; }public void setTitle(String title) { this.title = title; }public String getContent() { return content; }public void setContent(String content) { this.content = content; }public boolean isPublished() { return published; }public void setPublished(boolean published) { this.published = published; }
    }
    
  5. 创建仓库接口(repository 包下,新建 PostRepository.java):

    package com.example.blog.repository;import com.example.blog.model.Post;
    import org.springframework.data.jpa.repository.JpaRepository;
    import java.util.List;public interface PostRepository extends JpaRepository {List findByPublished(boolean published);List findByTitleContaining(String title);
    }
    
    • 继承 JpaRepository 自动获得 CRUD 方法。
    • 自定义方法:按发布状态或标题搜索。
  6. 创建控制器(controller 包下,新建 PostController.java):

    package com.example.blog.controller;import com.example.blog.model.Post;
    import com.example.blog.repository.PostRepository;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;import java.util.List;
    import java.util.Optional;@CrossOrigin(origins = "http://localhost:8081")  // 允许 Vue 前端跨域
    @RestController
    @RequestMapping("/api")
    public class PostController {@Autowiredprivate PostRepository postRepository;@GetMapping("/posts")public ResponseEntity> getAllPosts(@RequestParam(required = false) String title) {try {List posts;if (title == null)posts = postRepository.findAll();elseposts = postRepository.findByTitleContaining(title);if (posts.isEmpty())return new ResponseEntity<>(HttpStatus.NO_CONTENT);return new ResponseEntity<>(posts, HttpStatus.OK);} catch (Exception e) {return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);}}@GetMapping("/posts/{id}")public ResponseEntity getPostById(@PathVariable Long id) {Optional post = postRepository.findById(id);return post.map(value -> new ResponseEntity<>(value, HttpStatus.OK)).orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));}@PostMapping("/posts")public ResponseEntity createPost(@RequestBody Post post) {try {Post _post = postRepository.save(new Post(post.getTitle(), post.getContent(), post.isPublished()));return new ResponseEntity<>(_post, HttpStatus.CREATED);} catch (Exception e) {return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);}}@PutMapping("/posts/{id}")public ResponseEntity updatePost(@PathVariable Long id, @RequestBody Post post) {Optional existingPost = postRepository.findById(id);if (existingPost.isPresent()) {Post _post = existingPost.get();_post.setTitle(post.getTitle());_post.setContent(post.getContent());_post.setPublished(post.isPublished());return new ResponseEntity<>(postRepository.save(_post), HttpStatus.OK);} else {return new ResponseEntity<>(HttpStatus.NOT_FOUND);}}@DeleteMapping("/posts/{id}")public ResponseEntity deletePost(@PathVariable Long id) {try {postRepository.deleteById(id);return new ResponseEntity<>(HttpStatus.NO_CONTENT);} catch (Exception e) {return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);}}@DeleteMapping("/posts")public ResponseEntity deleteAllPosts() {try {postRepository.deleteAll();return new ResponseEntity<>(HttpStatus.NO_CONTENT);} catch (Exception e) {return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);}}@GetMapping("/posts/published")public ResponseEntity> findByPublished() {try {List posts = postRepository.findByPublished(true);if (posts.isEmpty())return new ResponseEntity<>(HttpStatus.NO_CONTENT);return new ResponseEntity<>(posts, HttpStatus.OK);} catch (Exception e) {return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);}}
    }
    
    • API 端点:/api/posts (GET 列表/搜索), /api/posts/{id} (GET/ PUT/ DELETE), /api/posts (POST 创建), /api/posts/published (GET 已发布)。
  7. 运行后端

    • 在 IDE 中运行 BlogBackendApplication 主类,或命令行 mvn spring-boot:run
    • 测试:浏览器访问 http://localhost:8080/api/posts,应返回 JSON 列表(如果有数据)。
3. 前端开发(Vue 2.6)

前端使用 Vue 2.6 构建单页应用(SPA),包括文章列表、详情/编辑页和添加页。使用 Axios 调用后端 API。

步骤:

  1. 创建项目

    • 命令行运行 vue create blog-frontend(选择默认配置:Vue 2.x)。
    • 进入目录:cd blog-frontend,安装依赖:npm install vue-router@3 axios bootstrap
  2. 配置路由(src/router/index.js):

    import Vue from 'vue';
    import VueRouter from 'vue-router';
    import PostsList from '../components/PostsList.vue';
    import Post from '../components/Post.vue';
    import AddPost from '../components/AddPost.vue';Vue.use(VueRouter);export default new VueRouter({mode: 'history',routes: [{ path: '/', name: 'posts', component: PostsList },{ path: '/posts/:id', name: 'post-details', component: Post },{ path: '/add', name: 'add', component: AddPost }]
    });
    
  3. 主应用配置(src/main.js):

    import Vue from 'vue';
    import App from './App.vue';
    import router from './router';
    import 'bootstrap/dist/css/bootstrap.min.css';Vue.config.productionTip = false;
    new Vue({router,render: h => h(App),
    }).$mount('#app');
    
  4. 配置 Axios(src/services/PostDataService.js):

    import http from '../http-common.js';class PostDataService {getAll() {return http.get('/posts');}get(id) {return http.get(`/posts/${id}`);}create(data) {return http.post('/posts', data);}update(id, data) {return http.put(`/posts/${id}`, data);}delete(id) {return http.delete(`/posts/${id}`);}deleteAll() {return http.delete('/posts');}findByTitle(title) {return http.get(`/posts?title=${title}`);}
    }export default new PostDataService();
    

    http-common.js(src/http-common.js):

    import axios from 'axios';export default axios.create({baseURL: 'http://localhost:8080/api',headers: {'Content-Type': 'application/json'}
    });
    
  5. 导航栏(src/App.vue):

    我的博客文章列表添加文章
  6. 文章列表组件(src/components/PostsList.vue):

    搜索全部无文章{{ post.title }} - {{ post.content.substring(0, 50) }}...{{ post.published ? '已发布' : '草稿' }}编辑删除import PostDataService from '../services/PostDataService';
    import { useRouter } from 'vue-router';  // Vue 2.6 使用 this.$routerexport default {data() {return { posts: [], title: '' };},methods: {retrievePosts() {PostDataService.getAll().then(response => { this.posts = response.data; });},searchTitle() {PostDataService.findByTitle(this.title).then(response => { this.posts = response.data; });},getPost(id) { this.$router.push(`/posts/${id}`); },removePost(id) {PostDataService.delete(id).then(() => { this.retrievePosts(); });}},mounted() { this.retrievePosts(); }
    };
  7. 添加文章组件(src/components/AddPost.vue)和详情/编辑组件(src/components/Post.vue):类似列表组件,使用表单(v-model 绑定 title/content)和服务方法(create/update)。完整代码可参考类似 CRUD 模板,添加表单验证。

  8. 运行前端

    • npm run serve,访问 http://localhost:8081
4. 集成、测试与部署
  • 集成:后端运行在 8080 端口,前端 8081 端口。确保 CORS 配置正确(@CrossOrigin)。
  • 测试
    • 添加文章:导航到 /add,提交表单。
    • 列表:首页显示文章,支持搜索和删除。
    • 编辑:点击编辑跳转到详情页,更新后返回列表。
    • 已发布:/api/posts/published 只显示 published=true 的文章。
  • 常见问题
    • 跨域错误:检查 @CrossOrigin。
    • 数据库连接失败:验证 properties 配置。
    • Vue 版本:确保使用 Vue 2.6(package.json 中 “vue”: “^2.6.0”)。
  • 部署(简单方式):后端打包 JAR (mvn package) 部署到服务器;前端构建 npm run build,静态文件上传到 Nginx 或 Vercel。使用 Docker 容器化。

这个教程提供了一个最小 viable 博客。如果你需要添加用户认证(Spring Security)或富文本编辑器(Vue-Quill-Editor),可以扩展。参考完整 CRUD 示例进行调整。
10

http://www.dtcms.com/a/442267.html

相关文章:

  • MySQL 核心架构解析:从 SQL 层到存储引擎的深度探索
  • 网站建设推广济南兴田德润优惠吗网站推广四个阶段
  • logbuffer 概念及题目
  • 通用定时器的基本介绍与功能概述
  • 洛谷 P14115:[IAMOI R4] 木桶效应 ← 二分
  • Python pip -U参数作用及使用建议
  • python全栈(基础篇)——day03:基础内容(字符串格式化+简单数据类型转换+进制的转换+运算符+实战演示+每日一题)
  • 学网站建设能赚钱吗网上购物哪家质量好
  • 基于ASRPRO的语音对话
  • 女人与狗做网站天津重型网站建设风格
  • 拼图小游戏开发日记 | Day3(已完结)
  • Go 1.25 新特性:正式支持 Git 仓库子目录作为 Go 模块
  • 鸿蒙NEXT Remote Communication Kit:打破设备壁垒,构筑无缝协同体验
  • 那些网站建设的好杭州建站程序
  • 做团购网站企业网站设计调查问卷
  • 基于 RoBERTa + 多策略优化的中文商品名细粒度分类
  • 做翻译兼职的网站是哪个特色的网站建设
  • 山西建设银行招聘网站crm系统的销售管理功能包括
  • 如何在C#中配置ONNX Runtime以确保准确性和目标框位置的正确性?
  • PiscCode使用YOLO识别超大分辨率高清视图实践
  • 力扣2200. 找出数组中的所有 K 近邻下标
  • 文化馆网站建设情况在微信上做彩票网站有哪些
  • 网站301怎么做企业法治建设工作计划
  • list模拟实现(简单版)【C++】
  • 烟台网站建设哪家好呢维护一个网站需要多少钱
  • 什么网站做视频最赚钱wordpress无法使用ajax
  • 对接MCP服务之sse/streamable-http模式
  • springMVC中/*与/**匹配的区别
  • 如何快速学习一个网络协议?
  • 从安装到上手实战——Docker 基础命令全解析