初学者应以Spring Boot+Thymeleaf+JDBC实现发帖、列表、详情三核心功能:建users/posts表,用JdbcTemplate手写SQL,Controller返回模板名,Thymeleaf仅用th:each/th:href/th:text基础语法,严格匹配命名。
直接上手写一个“完整论坛系统”对 Java 初学者不现实,真正可行的路径是:用最简技术栈实现核心交互闭环——用户发帖、查看帖子列表、点击进入详情页。其余功能(登录、权限、回复、搜索)先搁置,否则三天内必然卡死在 Spring Security 配置或 MyBatis 多表关联上。
别碰前后端分离。初学者强行接 axios 和 Vue,90% 的时间花在跨域、CORS、404 路由和浏览器控制台红字上,跟业务逻辑无关。Thymeleaf 模板渲染能让你一眼看到“请求 → Controller → Model → HTML”的完整链条。
spring-boot-starter-web + spring-boot-starter-thymeleaf + spring-boot-starter-jdbc(先不用 JPA,避免被 @Entity 和 Hibernate 的代理对象绕晕)application.properties 里只配数据库 URL、用户名、密码,其他全删掉,不加 spring.jpa.hibernate.ddl-auto 自动建表——手写 CREATE TABLE 更清醒"post/list"),对应 src/main/resources/templates/post/list.html,不返回 ResponseEntity 或 JSON别设计 categories、tags、replies 表。一张 posts 表含 id、title、content、user_id、created_at 就够。外键先不设约束,用注释说明“此处应为 users.id”,避免 SQLIntegrityConstraintViolationException 让人懵圈。
CREATE TABLE users ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL ); CREATE TABLE posts ( id BIGINT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL, content TEXT, user_id BIGINT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP );
INSERT INTO users (username) VALUES ('alice'), ('bob');,手动填 user_id 值,不依赖序列或触发器JdbcTemplate 直接写 SQL 查询,比如 query("SELECT p.*, u.username FROM posts p JOIN users u ON p.user_id = u.id", ...),不抽象 PostMapper 接口queryForList(),查单条用 queryForObject(),别碰 RowMapper 泛型——类型擦除会让初学者怀疑 Java 是不是坏了别写 th:fragment、th:replace、th:with。一个页面一个文件,重复代码先复制粘贴,等跑通再抽离。重点盯住三处:
th:each="post : ${posts}" —— 确保后端 Model.addAttribute("posts", list) 的 key 名和模板里一致th:href="@{/post/{id}(id=${post.id})}" —— 注意括号位置,写成 @{/post/${post.id}} 会生成错误 URLth:text="${post.title}" —— 不要漏掉 ${},写成 th:text="post.title" 页面就显示字面量 “post.title”90% 的初学者卡在启动失败,不是框架问题,是配置或路径笔误:
Whitelabel Error Page:检查 Controller 方法是否真返回了模板名字符串,且对应 HTML 文件在 templates/ 下存在;确认类上有 @Controller(不是 @RestController)Failed to configure a DataSource:检查 application.properties 是否拼错 spring.datasource.url,MySQL 8+ 必须加 ?serverTimezone=UTC
GET /post/list 返回的是 200 还是 404;若 404,确认 Controller 的 @GetMapping("/post/list") 路径和浏览器地址栏完全一致(注意斜杠)复杂点在于:所有环节都依赖“命名严格匹配”——Java 类名、方法名、模板文件路径、HTML 中的变量名、数据库字段名,差一个字母就断链。这不是设计缺陷,是初学阶段必须亲手踩过的验证过程。