用Java搭建一个简易博客系统,重点在于把文章发布与评论这两块业务逻辑拆清楚。很多刚接触Web开发的人容易把接收请求、处理数据和存库都写在一个类里,导致代码越改越乱。下面我们从分层结构讲起,逐步给出一个可运行的实现思路。

一、整体模块分层设计
简易博客系统通常采用经典的三层架构:控制层、业务层、持久层。控制层用Spring MVC的Controller接收前端请求,只负责参数校验和返回结果;业务层Service写真正的发布文章、添加评论规则;持久层用JPA或者MyBatis把对象存进MySQL。
这样的好处是文章模块和评论模块各自独立。比如文章表article存标题和内容,评论表comment存内容和关联的文章ID。两者通过外键约束保证评论一定挂在存在的文章下,避免脏数据。
1.1 数据表结构示例
先定义两张表,字段尽量简单但能表达关系。article表用自增主键,comment表用article_id做外键。
CREATE TABLE article ( id BIGINT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(200) NOT NULL, content TEXT NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE comment ( id BIGINT AUTO_INCREMENT PRIMARY KEY, article_id BIGINT NOT NULL, content VARCHAR(500) NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (article_id) REFERENCES article(id) );
1.2 实体类映射
在Java里用实体类对应表结构。下面以JPA注解方式写两个类,关系字段用@ManyToOne标注,方便后续查询某篇文章的全部评论。
@Entity
@Table(name = "article")
public class Article {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
private LocalDateTime createTime;
// getter和setter省略
}
@Entity
@Table(name = "comment")
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "article_id")
private Article article;
private String content;
private LocalDateTime createTime;
// getter和setter省略
}
二、文章发布模块实现
文章发布接口要做的事不多:拿到标题和内容,判空,然后存库。Controller层用@PostMapping接收JSON,Service层调用Repository的save方法。这里注意标题不能超长,内容不能为空,否则直接返回错误码。
如果直接在Controller里写保存逻辑,以后要加“发布时自动提取摘要”就得分散改代码。放到Service里,只改一个方法即可,符合单一职责原则。
2.1 Controller接收发布请求
以下代码展示如何用Spring Boot接收文章发布请求。使用@RequestBody把前端JSON转成对象,用BindingResult做基础校验。
@RestController
@RequestMapping("/api/article")
public class ArticleController {
@Autowired
private ArticleService articleService;
@PostMapping("/publish")
public Map<String, Object> publish(@RequestBody Article article, BindingResult result) {
Map<String, Object> resp = new HashMap<>();
if (result.hasErrors() || article.getTitle() == null || article.getContent() == null) {
resp.put("code", 400);
resp.put("msg", "标题或内容不能为空");
return resp;
}
articleService.publish(article);
resp.put("code", 200);
resp.put("msg", "发布成功");
return resp;
}
}
2.2 Service与Repository
Service注入JpaRepository,发布方法仅仅是保存并打日志。实际项目可在这里接入搜索引擎或清理缓存。
@Service
public class ArticleService {
@Autowired
private ArticleRepository articleRepository;
public void publish(Article article) {
article.setCreateTime(LocalDateTime.now());
articleRepository.save(article);
}
}
public interface ArticleRepository extends JpaRepository<Article, Long> {
}
三、评论模块结构
评论模块必须绑定文章。常见错误是前端传了不存在的articleId,后端没校验就插入,导致评论找不到归属。正确做法是在Service里先查文章存不存在,再存评论。
另外评论内容要做长度限制和简单敏感词拦截,虽然简易系统不一定接第三方,但至少防一下空评论和超长文本,减轻数据库压力。
3.1 添加评论接口
Controller接收articleId和content,转给Service处理。下面代码演示参数用表单格式提交,也可以改成JSON。
@RestController
@RequestMapping("/api/comment")
public class CommentController {
@Autowired
private CommentService commentService;
@PostMapping("/add")
public Map<String, Object> addComment(@RequestParam Long articleId, @RequestParam String content) {
Map<String, Object> resp = new HashMap<>();
boolean ok = commentService.addComment(articleId, content);
if (ok) {
resp.put("code", 200);
resp.put("msg", "评论成功");
} else {
resp.put("code", 404);
resp.put("msg", "文章不存在或内容非法");
}
return resp;
}
}
3.2 评论业务校验
Service先查文章,再构建Comment对象。这里用Optional避免空指针,是Java 8之后的推荐写法。
@Service
public class CommentService {
@Autowired
private ArticleRepository articleRepository;
@Autowired
private CommentRepository commentRepository;
public boolean addComment(Long articleId, String content) {
if (content == null || content.trim().length() == 0 || content.length() > 500) {
return false;
}
Optional<Article> opt = articleRepository.findById(articleId);
if (!opt.isPresent()) {
return false;
}
Comment c = new Comment();
c.setArticle(opt.get());
c.setContent(content);
c.setCreateTime(LocalDateTime.now());
commentRepository.save(c);
return true;
}
}
四、模块联调与扩展思考
文章和评论分开写完后,可以用Postman先发一篇文章,拿到返回的文章ID,再带着这个ID发评论。只要外键和校验生效,数据层就不会乱。
如果以后想显示某篇文章和全部评论,可以在ArticleRepository里写@Query查评论列表,或者前端分两次请求。这种结构下,接Redis缓存热门文章、接消息队列异步审核评论都不会动到原有发布逻辑,维护成本明显更低。
4.1 查询文章评论示例
给CommentRepository加一个按文章ID查的方法,Spring会自动生成SQL。
public interface CommentRepository extends JpaRepository<Comment, Long> {
List<Comment> findByArticleId(Long articleId);
}
通过上述结构,一个简易博客系统的文章发布与评论模块就具备了清晰边界。即便后续加入用户系统和权限控制,也只需在Controller入口加拦截器,不影响已经写好的核心逻辑。
Java博客系统Spring_Boot修改时间:2026-08-10 07:48:33