个人微博应用拆解:Servlet+JSP+JDBC实现Web全链路

发布时间:2026/10/23 21:05:08
个人微博应用拆解:Servlet+JSP+JDBC实现Web全链路 简介这是基于Java Web的个人微博应用项目适合正在学习Web原理、Java开发或需要课程设计参考的读者。项目围绕社交平台常见功能展开包含会员管理、个人中心与消息发布管理等模块能够帮助理清从用户注册登录、个人信息展示到动态发布和数据库存储的完整开发流程。压缩包为zip格式共包含71个文件整体大小约3.33MB文件类型以Java源码、JSP页面、CSS样式、XML配置以及少量jar包和class文件为主结构较为清晰便于导入IDE后对照查看项目目录与运行方式。其中还涉及Servlet处理请求、JSP动态页面、JDBC数据访问、前端样式设计等关键知识适合作为Web开发入门实践参考。目前已有223人学习对于需要快速了解一个轻量级社交项目实现的同学可以通过梳理模块划分与文件用途快速定位关键代码并在此框架上扩展或改造自己的功能需求。1. 个人微博应用一条从浏览器到数据库的 Web 请求全链路某同学临近期末交 Web 课设前后端加起来写了八百行却连「登录之后 Session 存了什么、请求是怎么被 Servlet 接住的」都说不清楚。这份「个人微博应用」就是拿来治这个毛病的。它不是用 Spring Boot 把细节藏起来的黑匣子而是把前端页面、Java 后端、MySQL 数据库三者用最朴素的方式串成一个完整闭环浏览器发请求Servlet 接收处理JDBC 读写库JSP 渲染回显。拆完这个项目你能同时看明白 Web 原理课上的四个考点——HTTP 无状态、Session 机制、请求转发与重定向、三层架构分层。适合刚学完 Java Web 基础想找个完整项目练手的人也适合要拿课设骨架去二次开发的同学。2. 技术栈与目录结构为什么是 Servlet、JSP 和 JDBC 的「无框架」组合2.1 技术选型无框架组合的价值打开这份资源的第一眼你可能会觉得「怎么还在用 Servlet JSP」——这正是它值得拆的原因。标题写着「Web原理及应用」教学项目的核心诉求是把每个环节暴露出来而不是用框架把它们藏起来。Spring Boot 里一个Controller注解就把请求映射、参数绑定、视图解析全包了你很难看清一条请求到底经过了哪几道工序。而 Servlet 的doGet/doPost里你亲手写request.getParameter()、亲手调session.setAttribute()、亲手把结果forward到 JSP每一步都是 Web 原理课的考点本身。这套组合的具体选型如下Java 8 Servlet 4.0运行在 Tomcat 9 上JSP 2.3 做服务端渲染配合 JSTL 标签库控制页面逻辑JDBC Druid 连接池操作 MySQL 5.7 / 8.0前端用原生 HTML、CSS、JavaScript数据交互走 fetch JSON提示这不是生产级微服务架构是一份「能把原理讲清楚」的课程项目。正因为它没有框架遮蔽你反而能把三层架构、Session 管理、SQL 拼接这些细节逐个看透。对准备面试的人来说这就是最合适的底稿。2.2 目录结构先看包再写代码我拆项目有个习惯——先看目录结构再看配置文件最后才看代码。这份资源的 Maven 工程结构是标准的三层架构层与层之间单向依赖没有循环调用weibo/ ├── pom.xml ├── src/main/java/ │ ├── com.weibo.model/ # 实体类 User、Message │ ├── com.weibo.dao/ # 数据访问层纯 JDBC 操作 │ │ ├── UserDao.java │ │ └── MessageDao.java │ ├── com.weibo.service/ # 业务逻辑层校验和事务边界 │ │ ├── UserService.java │ │ └── MessageService.java │ ├── com.weibo.web.servlet/ # 控制层接收请求、返回视图或 JSON │ │ ├── LoginServlet.java │ │ ├── RegisterServlet.java │ │ ├── PublishServlet.java │ │ ├── FeedServlet.java │ │ └── ProfileServlet.java │ ├── com.weibo.web.filter/ # 登录拦截 │ │ └── AuthFilter.java │ ├── com.weibo.util/ # DBUtil 连接池工具、JsonUtil 序列化工具 │ └── com.weibo.constant/ # 常量类Session Key、参数名统一管理 └── src/main/webapp/ ├── login.jsp ├── register.jsp ├── home.jsp # 主页面发微博 时间线 个人主页 ├── static/css/ # 样式文件 ├── static/js/ # 前端交互 fetch 脚本 └── WEB-INF/web.xml这个结构是给二次开发留了后路的web 层的Servlet只做三件事——解析参数、调用 service、把结果交给 JSP 或 JSONservice 层承载业务规则比如内容校验、分页逻辑dao 层只写 SQL不掺业务判断。如果你后面想加一个「关注」功能只需要在 model 里加Follow实体、在 dao 里加FollowDao、在 service 里加新方法然后在 Servlet 里接一个新接口——不需要改动任何已有代码。2.3 依赖与配置三个容易忽略的细节pom.xml里依赖不多但每个都有讲究dependencies !-- Servlet 依赖Tomcat 已自带所以 scope 用 provided -- dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency !-- MySQL 驱动版本号必须和本地数据库匹配 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.30/version /dependency !-- Druid 连接池比 DriverManager.getConnection 省掉每次建连的开销 -- dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.8/version /dependency !-- Jackson用来把 Java 对象转成 JSON 字符串返回给前端 -- dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version2.13.3/version /dependency /dependencies这里三个易错点第一servlet-api的 scope 必须是provided如果漏了打 war 包时会把 API 打进去和 Tomcat 自带的类冲突第二MySQL 驱动版本要和你本机数据库一致5.1.x和8.0.x的驱动类名、连接串写法都不一样第三不用 Spring所以连接池得自己管好——DBUtil里通过静态代码块初始化 Druid 数据源整个应用只建一个池子多个线程共享连接。web.xml里做了两件事配置了 Druid 的WebStatFilter用来统计 SQL 执行顺便把静态资源的请求排除掉再声明了欢迎页指向login.jsp。项目的 Servlet 全部用WebServlet(/api/login)注解注册没有在 web.xml 里堆映射——因为注解更直观路径和类名放在一起排查问题少跳一层。3. 核心模块拆解一条微博从发布到刷进时间线的完整链路3.1 登录与 Session 管理权限拦截是 Web 应用的地基登录功能是这个项目里「Web 原理」浓度最高的一段代码。登录成功之后用户信息存进 Session后续的发布微博、刷时间线、看个人主页全靠 Session 里的 user 对象来识别「你是谁」。后端三个核心环节如下。先看UserService.login()的校验逻辑public User login(String username, String password) { // 参数校验空值和长度限制放在最外层 if (username null || username.trim().isEmpty() || password null || password.isEmpty()) { return null; } // 调用 DAO 层按用户名查用户 User user userDao.findByUsername(username); // 比对密码这里存的是 MD5 值不是明文 if (user ! null user.getPassword().equals(MD5Util.md5(password))) { return user; } return null; }逻辑说明service 层先做参数显式校验避免空指针进入 SQL 层findByUsername返回 null 表示用户不存在再比对 MD5 摘要后的密码与数据库中的 hash 值一致才算登录成功。这里用 MD5 是教学场景的习惯做法生产项目至少要加盐或换 BCrypt。参数说明username和password都来自前端表单前端在提交前也做了一次非空校验但后端校验才是真正的安全边界——前端校验只改善体验不可信。再看LoginServlet中登录成功后的 Session 处理protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username request.getParameter(username); String password request.getParameter(password); User user userService.login(username, password); if (user ! null) { // 登录成功把用户对象放进 Session后续请求都能读到 HttpSession session request.getSession(); session.setAttribute(Constants.SESSION_USER, user); session.setMaxInactiveInterval(60 * 30); // 30 分钟过期 response.sendRedirect(request.getContextPath() /home.jsp); } else { // 登录失败转发回登录页并携带错误信息 request.setAttribute(error, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } }逻辑说明request.getSession()内部会取或创建 JSESSIONID写入 Cookie 返回给浏览器setMaxInactiveInterval控制 Session 存活时长单位是秒sendRedirect是重定向浏览器会重新发起一次 GET 请求到/home.jsp这一步跳转 URL 会变化forward则不会。两者差别面试必考——重定向是两次请求转发是一次请求内完成。参数说明Constants.SESSION_USER是统一常量不允许在代码里手写字符串 key这是为了避免多个 Servlet 之间 key 不一致导致「登录了却拿不到用户」的玄学问题。拦截器AuthFilter把所有需要登录才能访问的接口锁住WebFilter(/api/*) public class AuthFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request (HttpServletRequest) req; HttpServletResponse response (HttpServletResponse) res; HttpSession session request.getSession(false); User user session null ? null : (User) session.getAttribute(Constants.SESSION_USER); if (user null) { // 未登录返回 401 JSON前端根据状态码跳登录页 response.setContentType(application/json;charsetUTF-8); response.getWriter().write({\code\:401,\message\:\未登录\}); return; } chain.doFilter(req, res); } }逻辑说明WebFilter(/api/*)把范围定在/api前缀上JSP 页面和静态资源不受拦截request.getSession(false)传入 false 表示「没有 Session 就返回 null」不会强行创建一个新 Session拿到用户对象后放行拿不到就直接返回 JSON。参数说明前端fetch请求遇到 HTTP 401 或返回 JSON 里的code:401就执行window.location.href login.jsp。这套前后端配合的拦截方式比直接重定向到登录页更接近真实项目的接口风格。3.2 发布微博表单参数到 INSERT 语句的完整旅程发布微博是整个应用的核心操作链路不长但每个环节都有戏。前端是一个 JSON 的 POST 请求后端PublishServlet接收后先取 Session 用户再校验内容长度最后调用 service 层落库。WebServlet(/api/publish) public class PublishServlet extends HttpServlet { Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { // 设置请求编码避免中文乱码必须放在读取参数之前 request.setCharacterEncoding(UTF-8); // 从 Session 中取当前登录用户 HttpSession session request.getSession(false); User user (User) session.getAttribute(Constants.SESSION_USER); // 读取参数content 是前端传来的微博文本 String content request.getParameter(content); if (content null || content.trim().isEmpty()) { writeJson(response, 400, 内容不能为空); return; } if (content.trim().length() 280) { writeJson(response, 400, 内容不能超过 280 字); return; } // 调 service 层这里负责 INSERT 语句的执行 MessageService messageService new MessageService(); boolean success messageService.publish(user.getId(), content.trim()); if (success) { writeJson(response, 200, 发布成功); } else { writeJson(response, 500, 发布失败请稍后重试); } } }逻辑说明编码设置必须在读取第一个参数之前调用因为参数读取时已经按字节解析了Session 用户在 Filter 里验证过非空这里只需取出即可不重复判断service 层返回 booleanServlet 只负责把它翻译成 JSON 响应。参数说明writeJson是自定义工具方法基于 Jackson 往 response 里写 JSON 字符串。280 字的长度限制在 service 层也做了一遍——Servlet 层防的是非法请求service 层防的是漏网之鱼两层校验各管一段。MessageService.publish里对应的就是一个带参数的 INSERTpublic boolean publish(Integer userId, String content) { String sql INSERT INTO message (user_id, content, create_time, like_count) VALUES (?, ?, NOW(), 0); return messageDao.executeUpdate(sql, userId, content) 0; }逻辑说明用占位符?而不是字符串拼接——这是防 SQL 注入的底线。虽然这里参数都是通过 PreparedStatement 预编译后传参的不会拼接进 SQL 语法结构但很多人写 JDBC 时图省事直接拼字符串一旦 content 里出现单引号和分号就翻车。参数说明NOW()由数据库生成时间不依赖服务器时钟like_count默认 0后续点赞功能直接UPDATE message SET like_count like_count 1即可不用先查后写。3.3 时间线 Feed为什么一条 SQL 能同时查出作者昵称主页刷出来的时间线不是简单的表格查询而是「微博 作者昵称」的联合数据。如果只查 message 表前端显示昵称的时候还得逐条回查 user 表那就是经典的 N1 问题。这项目直接在 SQL 层面 JOIN 解决public ListFeedItem findFeed(int page, int pageSize) { String sql SELECT m.id, m.content, m.create_time, m.like_count, u.username, u.nickname FROM message m INNER JOIN user u ON m.user_id u.id ORDER BY m.create_time DESC LIMIT ? OFFSET ?; // 执行带参查询将结果映射为 FeedItem 对象列表 return jdbcTemplate.query(sql, ps - { ps.setInt(1, pageSize); ps.setInt(2, (page - 1) * pageSize); }, rowMapper); }逻辑说明INNER JOIN user把 message 表和 user 表按user_id关联成一张宽表一次查询拿到内容和作者信息避免了逐条回查ORDER BY create_time DESC保证最新的微博在最前面LIMIT ? OFFSET ?是经典的分页方式。参数说明page从 1 开始OFFSET计算公式是(page-1) * pageSize即第一页跳过 0 条、第二页跳过 pageSize 条。这套分页在数据量达到几十万条之后会有深分页性能问题但课设场景完全够用——真到那个量级再说。FeedItem 这个模型值得看一眼它不是纯粹的数据库实体而是「视图模型」VOpublic class FeedItem { private Integer id; private String content; private Date createTime; private Integer likeCount; private String username; private String nickname; // getter/setter 省略 }逻辑说明VO 和实体分离是 Web 应用的好习惯——message 表里没有nickname字段但你需要在时间线上展示它所以专门建一个FeedItem聚合查询结果。以后要加一个「这条微博是否已点赞」的字段也是往 FeedItem 加属性不影响实体类。这个设计对二次开发很关键改查询不影响写入改表结构不影响接口。3.4 前端 fetch 与 JSON 接口贴近真实开发的前后端交互这份资源没有走传统的「JSP 里用 form 提交」老路而是用 fetch JSON这也是它比一般课设项目更像真实工程的地方。前端 JavaScript 的发布微博代码async function publishMessage() { const content document.getElementById(content).value.trim(); if (!content) { alert(内容不能为空); return; } if (content.length 280) { alert(内容不能超过 280 字); return; } const formData new URLSearchParams(); formData.append(content, content); const resp await fetch(/api/publish, { method: POST, body: formData }); const data await resp.json(); if (data.code 200) { loadFeed(1); // 重新刷新时间线 document.getElementById(content).value ; } else { alert(data.message); } }逻辑说明用URLSearchParams模拟表单提交服务端的getParameter可以直接取到请求头会自动加上application/x-www-form-urlencodedfetch返回的是 Promise和 JSP 里直接document.forms[0].submit()相比页面不刷新就能拿到 JSON 数据data.code是后端定义的业务状态码HTTP 状态码和业务码分开是前后端协作的标准姿势。注意点请求头没有手动设置Content-Type而是靠URLSearchParams自动携带application/x-www-form-urlencoded;charsetUTF-8这样不会出现跨域预检问题。// 加载时间线的 fetch 调用 async function loadFeed(page) { const resp await fetch(/api/feed?page${page}pageSize10); const data await resp.json(); if (data.code 200) { renderFeed(data.data.list); // data.data.list 是微博数组 } else if (data.code 401) { window.location.href /login.jsp; } }逻辑说明时间线走 GET 请求分页参数直接拼在 URL 查询串上data.code401时全局跳回登录页对应AuthFilter里返回的 JSON。看这份代码你顺带就把「HTTP 方法语义」「GET 与 POST 参数位置」两个 Web 原理知识点复习了GET 的参数在 URL 上有长度限制适合查询POST 的参数在请求体里适合写操作和敏感数据传递。4. 本地运行与调试从空数据库到第一条微博落库4.1 环境准备与数据库初始化这份资源我建议在如下环境跑JDK 8 或 11Maven 3.6Tomcat 9MySQL 5.7/8.0。IDE 没有强制要求IDEA 或 Eclipse 都行但后面调试那部分我用 IDEA 的 Artifact 部署方式讲操作路径更直观。数据库初始化是第一个容易卡住的点。项目根目录下应该有sql/init.sql如果没有按下面的建表语句手动执行CREATE DATABASE IF NOT EXISTS weibo DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE weibo; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, nickname VARCHAR(50) NOT NULL, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE message ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, content VARCHAR(280) NOT NULL, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, like_count INT NOT NULL DEFAULT 0, CONSTRAINT fk_message_user FOREIGN KEY (user_id) REFERENCES user(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; INSERT INTO user (username, password, nickname) VALUES (demo, e10adc3949ba59abbe56e057f20f883e, 演示用户);建表说明字符集统一用utf8mb4而不是utf8因为utf8mb4才能存下 Emoji 和生僻字——微博场景里颜文字和特殊符号很常见用错字符集会看到「?」乱码外键约束fk_message_user保证了 message 表的user_id一定指向存在的用户删用户时也会因为有外键而报错——这是数据完整性保护不是麻烦。密码字段存的是MD5(123456)的值e10adc...也就是说演示账号的密码是123456登录时后端算法自动比对 MD5 摘要。注意MySQL 8.0 的驱动类名和连接串和 5.x 不一样。8.0 用com.mysql.cj.jdbc.Driver连接串要加serverTimezoneAsia/Shanghai否则报时区错误。这份源码的db.properties已经处理好了你只需要改用户名和密码。4.2 配置连接池与启动入口进入资源包以后先改src/main/resources/db.propertiesjdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/weibo?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8mb4 jdbc.usernameroot jdbc.password你的数据库密码 jdbc.initialSize2 jdbc.maxActive10参数说明initialSize2是启动时在连接池里创建 2 个空闲连接maxActive10是最大连接数超出这个数的请求会排队。characterEncodingutf8mb4要放在连接串里否则中文会乱码。改完配置启动方式有两种选一种就行。方式一Maven 打 war 包丢进 Tomcat——这是最朴素的办法适合不想配 IDEA 的同学mvn clean package # 输出 target/weibo.war cp target/weibo.war $TOMCAT_HOME/webapps/ # 启动 Tomcat $TOMCAT_HOME/bin/startup.sh # 浏览器打开 http://localhost:8080/weibo/login.jsp方式二IDEA 里配置 Tomcat 的 ArtifactRun → Edit Configurations → 新建 Tomcat Server → LocalDeployment 里 Addweibo:war explodedApplication context 填/weibo然后点运行。war exploded比打包成 war 好在哪里——JSP 或 Java 代码改了之后IDEA 会自动热部署不用每次重启 Tomcat调试效率高很多。4.3 调试技巧把黑匣子打开一条缝这套代码跑不起来的时候多数人会觉得「玄学」。实际上只是把调试工具用错地方了。我一般按三个层次排查第一层看后端日志。在MessageDao的查询方法里临时打印 SQL 和参数——不是打印在纸上是打印到 IDEA 控制台。如果你在findFeed里看不到任何输出说明请求根本没进到这个层问题出在 Filter 拦截或 URL 写错。第二层看浏览器 Network 面板。按 F12 打开控制台找到 Network刷新主页逐个看请求的状态码404表示路径写错500表示后端异常401表示没登录。点开请求详情还能看到 FormData 或 Query String 的参数列表——前端是不是把参数名传错了一目了然。前端 JavaScript 报错则切到 Console 标签看调用栈。第三层断点调试全链路。在 IDEA 里把断点打在AuthFilter.doFilter第一行然后刷新页面——你会发现请求先进 Filter再进 Servlet再到 Service再到 DAO。这样你就亲眼看到了一条 HTTP 请求的完整旅程。整个过程不要怀疑「是不是环境问题」先确认代码里哪一步没执行到基本 5 分钟内能定位 80% 的问题。5. 避坑指南个人微博应用开发里最常见的五个问题这份资源我拆过不止一遍也帮别人排查过不少运行问题。下面五条是出现频率最高的每条都是「现象 → 原因 → 解决」三步走遇到同类问题时可以直接照方抓药。坑一POST 请求中文乱码现象通过/api/publish发布微博内容里的中文落库后变成???或者前端 alert 弹出的错误信息全是乱码。原因Tomcat 8 默认用 UTF-8 解码请求体但db.properties连接串里没有指定characterEncoding或者 Servlet 里在读取参数之后才调用setCharacterEncoding——编码设置必须在读取第一个参数之前否则只对后续参数生效。解决连接串加上characterEncodingutf8mb4Servlet 第一行就写request.setCharacterEncoding(UTF-8)数据库表字符集也统一为utf8mb4保持一致。三处都改完乱码问题彻底消失。坑二登录成功后刷新又回到登录页现象输入正确密码跳转到了主页但只要一刷新或新开标签页马上被弹回login.jsp。原因AuthFilter从 Session 里取用户用的是 keyuser而LoginServlet里存的是Constants.SESSION_USER——如果这个常量值不一致Session 里实际有用户对象但 Filter 取不到。另一个常见原因是浏览器禁用了 Cookie导致 JSESSIONID 没有回传Session 对不上。解决统一把 Session key 放到Constants类里杜绝手写字符串浏览器设置里把 Cookie 允许打开如果确实需要兼容禁用 Cookie 的场景在LoginServlet跳转 URL 上通过response.encodeRedirectURL()把 JSESSIONID 拼进 URL。坑三连不上数据库启动后请求报 500现象Tomcat 起来了访问登录页正常但输入账号后页面报 500后台日志显示Communications link failure或ClassNotFoundException: com.mysql.jdbc.Driver。原因MySQL 版本和驱动不匹配。如果本机是 MySQL 8.0但pom.xml里用的是mysql-connector-java 5.1.x驱动名要改成com.mysql.jdbc.Driver且连接串不能带serverTimezone参数——但 5.1.x 又时区报错一套配置两头堵。或者干脆是数据库服务没启动端口 3306 没监听。解决确认pom.xml版本、db.properties驱动类名、连接串时区参数三个地方匹配你本机的 MySQL 版本用mysql -uroot -p手动连一次数据库排除服务本身没起的问题再检查jdbc.url里的端口如果改过要和实际 MySQL 端口一致。坑四fetch 拿不到 JSON控制台报解析错误现象前端代码await resp.json()一直报SyntaxError: Unexpected token in JSONNetwork 面板里显示响应内容是 HTML 而不是 JSON。原因Servlet 在返回时没有设置Content-Type: application/json;charsetUTF-8Tomcat 默认按文本text/html返回了另一个是后端代码里getWriter().write()之后又调用了sendRedirect输出流被二次写入响应体被污染。解决所有返回 JSON 的接口统一调用writeJson工具方法——里面先setContentType(application/json;charsetUTF-8)再写数据每个 Servlet 都用这个工具避免重复犯低级错误。write和flush之后整个方法就 return不再做任何跳转操作。坑五改了 CSS 或 JS 但浏览器不生效现象改了static/css/weibo.css里的颜色刷新页面还是旧的清了浏览器缓存又好了过一会又出现。原因浏览器对静态资源有缓存策略同一个 URL 在过期前直接使用本地缓存不会重新请求服务器。开发期间这是最烦人的「假难问题」——代码没问题是浏览器在用旧文件。解决在 JSP 里引用静态资源的路径后面加版本号参数比如weibo.css?v1.0.1每次改动就递增版本号URL 变了浏览器就会重新拉取。或者在调试期间临时在web.xml加一个 Cache-Control 设置为 no-cache 的 Filter只影响开发环境正式部署的时候再放开。6. 二次开发思路从微博壳子到可扩展的 Web 应用骨架这份资源真正的价值在于改造空间。它把 Web 应用最常见的骨架——登录、发布内容、展示时间线、权限拦截——都搭好了你想往上加东西只需要顺着三层架构往里补模块。第一个推荐的方向是「关注时间线」。目前主页FeedServlet显示的是全部用户的微博你可以改成只显示当前登录用户关注的人。改动涉及三层先在message表旁加一张follow表id, user_id, follow_user_id, create_time然后重构FeedServlet的查询逻辑把原来不带条件的findFeed改成接受一组 userId 或直接 JOIN follow 表的方式-- 只看我关注的人的微博 SELECT m.id, m.content, m.create_time, m.like_count, u.username, u.nickname FROM message m INNER JOIN user u ON m.user_id u.id INNER JOIN follow f ON f.follow_user_id m.user_id WHERE f.user_id ? ORDER BY m.create_time DESC LIMIT ? OFFSET ?实现时加一个开关参数——保持原来的「全部微博」和新增的「关注时间线」两条查询并存通过Servlet里的typeall|follow区分。这样改造不破坏原有接口前端加一个 tab 就能切换。这是业务型改造验证方法是注册两个测试账号A 关注 BB 发一条微博A 的主页只看到 B 的内容同时 A 在「全部」tab 里仍能看到全站动态。第二个方向是把 JSP 换成前后端分离。这份资源的所有/api接口已经返回 JSON 而不是返回 JSP 页面把视图层替换成 Vue 或 React 的纯静态页面成本很低——你只需要保留api包下的 Servlet把login.jsp、home.jsp换成index.html用 fetch 调同样接口即可做到「同一个后端两套前端」。验证方式也简单先把静态页面放到 Tomcat 的webapps/ROOT下如果所有接口跨域问题不存在同域部署登录、发布、刷时间线三个主流程跑通就算成功。第三个方向是「点赞」功能。数据库里message表已经预留了like_count字段后端只需要写一个/api/like接口用UPDATE message SET like_count like_count 1 WHERE id ?前端在时间线每条微博上加一个按钮调这个接口。注意生产级做法是先查这条微博是否存在再加乐观锁防止并发重复点赞但在这个教学项目里你先把主流程跑通性能优化是后面的事。从那以后我每次拿到一个教学项目都会先问自己三个问题数据模型里有没有预留扩展字段接口是不是都走 JSON 而不是绑定页面前端能不能脱离开后端独立跑如果答案都是肯定的那这个项目就值得花时间细读——因为它的骨架允许你往上长新功能而不是每次改造都要推倒重来。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询