news 2026/4/18 5:40:17

手把手教你用 Spring Boot + Vue 搭建个人博客系统(后端篇)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手把手教你用 Spring Boot + Vue 搭建个人博客系统(后端篇)

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!


一、为什么要做这个项目?

很多刚入门 Java 的小伙伴在学完 Spring Boot 基础后,常常不知道如何实战。而“个人博客系统”是一个非常经典又实用的小型全栈项目:

  • 功能清晰:文章发布、分类、评论等模块明确;
  • 技术全面:涵盖 RESTful API、数据库操作、前后端分离等核心技能;
  • 可扩展性强:后续可加登录鉴权、Markdown 编辑器、图片上传等功能。

今天我们就先聚焦后端部分,用Spring Boot + MyBatis + MySQL搭建一个简洁但完整的博客 API 接口服务。


二、需求场景

假设你是博主小明,想搭建一个自己的技术博客网站,需要以下基本功能:

  1. 发布/编辑/删除文章;
  2. 查看所有文章列表(带分页);
  3. 根据文章 ID 查看详情;
  4. 文章按分类(如“Java”、“前端”、“生活”)归类。

注意:本文只实现后端接口,前端 Vue 部分我们后续再讲。


三、技术选型

技术作用
Spring Boot 3.x快速构建 Web 应用
MyBatis-Plus简化数据库 CRUD 操作
MySQL 8.0存储文章和分类数据
Lombok自动生成 getter/setter/toString
Hutool(可选)工具类库,简化开发

四、数据库设计

-- 博客分类表 CREATE TABLE blog_category ( id BIGINT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL UNIQUE COMMENT '分类名称' ); -- 博客文章表 CREATE TABLE blog_post ( id BIGINT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(200) NOT NULL, content TEXT NOT NULL, category_id BIGINT NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (category_id) REFERENCES blog_category(id) );

五、Spring Boot 后端代码实现

1. 创建 Spring Boot 项目(使用 Spring Initializr)

依赖选择:

  • Spring Web
  • MyBatis Framework
  • MySQL Driver
  • Lombok

2.application.yml配置

spring: datasource: url: jdbc:mysql://localhost:3306/blog_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true global-config: db-config: id-type: auto

3. 实体类

// Category.java @Data @TableName("blog_category") public class Category { @TableId(type = IdType.AUTO) private Long id; private String name; } // Post.java @Data @TableName("blog_post") public class Post { @TableId(type = IdType.AUTO) private Long id; private String title; private String content; private Long categoryId; private LocalDateTime createTime; private LocalDateTime updateTime; // 用于返回时携带分类名称(非数据库字段) @TableField(exist = false) private String categoryName; }

4. Mapper 层

@Mapper public interface CategoryMapper extends BaseMapper<Category> {} @Mapper public interface PostMapper extends BaseMapper<Post> {}

5. Service 层

@Service public class PostService { @Autowired private PostMapper postMapper; @Autowired private CategoryMapper categoryMapper; public List<Post> getAllPosts() { List<Post> posts = postMapper.selectList(null); // 补充分类名称 for (Post post : posts) { Category category = categoryMapper.selectById(post.getCategoryId()); if (category != null) { post.setCategoryName(category.getName()); } } return posts; } public Post getPostById(Long id) { Post post = postMapper.selectById(id); if (post != null) { Category category = categoryMapper.selectById(post.getCategoryId()); post.setCategoryName(category != null ? category.getName() : "未知"); } return post; } public boolean savePost(Post post) { return postMapper.insert(post) > 0; } public boolean updatePost(Post post) { return postMapper.updateById(post) > 0; } public boolean deletePost(Long id) { return postMapper.deleteById(id) > 0; } }

6. Controller 层(RESTful API)

@RestController @RequestMapping("/api/posts") public class PostController { @Autowired private PostService postService; @GetMapping public ResponseEntity<List<Post>> listAll() { return ResponseEntity.ok(postService.getAllPosts()); } @GetMapping("/{id}") public ResponseEntity<Post> getById(@PathVariable Long id) { Post post = postService.getPostById(id); if (post == null) { return ResponseEntity.notFound().build(); } return ResponseEntity.ok(post); } @PostMapping public ResponseEntity<String> create(@RequestBody Post post) { if (postService.savePost(post)) { return ResponseEntity.ok("文章创建成功"); } return ResponseEntity.badRequest().body("创建失败"); } @PutMapping("/{id}") public ResponseEntity<String> update(@PathVariable Long id, @RequestBody Post post) { post.setId(id); if (postService.updatePost(post)) { return ResponseEntity.ok("更新成功"); } return ResponseEntity.badRequest().body("更新失败"); } @DeleteMapping("/{id}") public ResponseEntity<String> delete(@PathVariable Long id) { if (postService.deletePost(id)) { return ResponseEntity.ok("删除成功"); } return ResponseEntity.badRequest().body("删除失败"); } }

六、反例 & 常见错误

❌ 反例1:直接在 Controller 中写数据库逻辑

// 错误示范! @GetMapping("/bad") public List<Post> badExample() { return postMapper.selectList(null); // 耦合严重,无法复用,难测试 }

✅ 正确做法:分层架构(Controller → Service → Mapper),职责清晰。


❌ 反例2:忽略空指针异常

// 如果 categoryId 对应的分类不存在,category.getName() 会 NPE! post.setCategoryName(category.getName());

✅ 正确做法:判空处理,或使用 Optional。


❌ 反例3:不统一返回格式

有的接口返回String,有的返回Map,前端很难处理。

✅ 正确做法:统一封装响应体(如Result<T>),但为简化本例暂未使用。


七、注意事项

  1. 数据库连接:确保 MySQL 服务已启动,且blog_db数据库存在;
  2. MyBatis-Plus 依赖:需引入mybatis-plus-boot-starter,不是普通 MyBatis;
  3. 时间字段:MySQL 的DATETIME对应 Java 的LocalDateTime(Spring Boot 2.7+ 支持自动转换);
  4. 跨域问题:前端 Vue 开发时(如 localhost:8080)调用后端(localhost:8081)会遇到 CORS,可在 Controller 上加@CrossOrigin临时解决,生产环境应配置网关或 Nginx。

八、下一步

后端 API 已就绪!接下来你可以:

  • 用 Postman 测试/api/posts接口;
  • 搭建 Vue 前端,通过 Axios 调用这些接口;
  • 增加用户登录、JWT 鉴权、富文本编辑器支持等。

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 3:31:23

Git commit统计贡献度查看GLM项目参与情况

Git Commit 统计揭示 GLM 项目真实活跃度&#xff1a;谁在推动多模态模型演进&#xff1f; 在 AI 模型“军备竞赛”愈演愈烈的今天&#xff0c;一个耐人寻味的现象正在浮现&#xff1a;越来越多开发者不再只看论文指标或 Demo 效果&#xff0c;而是悄悄打开项目的 Git 提交记录…

作者头像 李华
网站建设 2026/4/18 3:30:50

物联网赋能环境管控:在线温湿度实时监控系统解决方案,保障数据稳定无丢失

在物联网技术飞速普及的今天&#xff0c;“实时感知、精准调控、智能报警”已成为各行业环境管理的核心需求。温湿度作为影响产品质量、生产安全、生态环境的关键因素&#xff0c;其监控方式正从传统的人工巡检、离线记录&#xff0c;全面升级为在线实时监控模式。在线温湿度实…

作者头像 李华
网站建设 2026/4/17 5:58:04

工业遥控器光纤模块技术解析

工业遥控器光纤模块的核心&#xff0c;是用光纤这条不受电磁干扰的“专属高速路”&#xff0c;在复杂工业环境下建立一条可靠的控制通道。核心原理与技术架构光纤模块的核心是光电-电光转换。遥控器的电信号经光电转换模块调制成光信号&#xff0c;通过光纤传输后&#xff0c;在…

作者头像 李华
网站建设 2026/4/18 3:36:51

ComfyUI变量传递实现GLM-4.6V-Flash-WEB参数复用

ComfyUI变量传递实现GLM-4.6V-Flash-WEB参数复用 在当前多模态AI应用快速落地的背景下&#xff0c;一个现实问题摆在开发者面前&#xff1a;如何在有限算力下&#xff0c;高效部署具备图文理解能力的大模型&#xff1f;传统方式中&#xff0c;每次推理都重新加载模型、重复配置…

作者头像 李华
网站建设 2026/4/18 3:25:33

电子产品设计内部评审的构建与执行

设计内部评审的系统性构建与执行指南一、内部评审的四大核心类型及作用1. 构思评审&#xff08;Concept Review&#xff09; 作用&#xff1a;验证设计方向的正确性&#xff0c;确保方案符合业务目标与用户需求时机&#xff1a;项目启动初期&#xff0c;设计方案成型前关键…

作者头像 李华
网站建设 2026/4/18 3:27:22

实例控制台日志排查GLM-4.6V-Flash-WEB启动失败问题全记录

GLM-4.6V-Flash-WEB 启动失败&#xff1f;从控制台日志看透本质问题 在多模态大模型快速落地的今天&#xff0c;一个看似简单的“网页打不开”问题&#xff0c;可能背后藏着显存溢出、环境错乱或权限缺失等复杂原因。最近不少开发者反馈&#xff1a;明明按照文档执行了 1键推理…

作者头像 李华