news 2026/11/6 2:12:22

JavaEE影视创作论坛课程设计:Servlet+JSP+JDBC全链路拆解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaEE影视创作论坛课程设计:Servlet+JSP+JDBC全链路拆解

简介:面向计算机专业课程设计与JavaEE入门进阶学习者的影视创作论坛完整项目包,围绕影视资讯、幕后创作心得、观众观影体验与交流讨论等模块展开,可用于课程设计选题、毕业设计参考或JavaEE综合实践练习。压缩包共142个文件、约54.95MB,以xml配置与rels关系文件为主体,配合png、jpeg界面截图与wdp素材图,覆盖工程配置、页面资源与图文素材等层面。另含源代码、数据库脚本与论文教程,便于按模块对照理解系统结构与实现流程。目前已有488人学习下载。读者可据此获得一套较完整的论坛系统实现方案:从需求分析、数据库表设计到前后端交互与页面呈现,配合论文文档梳理设计思路与关键技术点,适合需要快速搭建项目骨架、补足文档材料或对照学习JavaEE开发流程的同学参考。

1. 解压之后先别急着打开 IDE

解压一个课程设计压缩包,最怕看到的是满屏 JSP 和 Servlet,没有 README,连数据库有几张表都得从代码里反推。这份基于 JavaEE 的影视创作论坛就属于这一类:没有花哨的微服务,是一套典型的 Java Web 系统开发骨架——注册登录、按板块发帖、作品展示、评论回复、后台审核,功能闭环是完整的。它最适合两类人:正在做计算机专业课程设计、需要一个能跑通又改得动的参考工程的同学,以及刚学完 Servlet 想把 MVC 串一遍的初学者。下面按我拆包的顺序,从选型、表结构、核心链路,一路讲到部署和二次开发。

2. 技术栈拆解:Servlet + JSP + JDBC 这套“老三样”为什么够用

拿到一个陌生工程,我第一件事不是运行,而是看它用了什么、为什么这么用。影视创作论坛这类内容型站点,核心动作只有几个:读列表、看详情、写内容、管内容。请求量小、业务规则简单、数据关系清楚,这三条决定了它不需要上 Spring Cloud 那一套,Servlet 容器加一层薄薄的 MVC 就足够。

2.1 选型判断:为什么是 JSP 而不是前后端分离

这类课程设计工程的典型组合是 JDK 8 + Servlet 3.1 + JSP 2.3 + JSTL 1.2 + JDBC + MySQL 5.7 + Tomcat 8.5/9。前端多半是 Bootstrap 3 加 jQuery,页面跳转靠服务端渲染,表单同步提交。

这么选的理由很实在:JSP 可以直接在页面上写${post.title}和<c:forEach>,不用额外起一个 Node 服务,也不用配跨域;Tomcat 一个进程就把静态资源和接口全包了,答辩时插上 U 盘、拷个 war 包就能演示。代价是页面和 Java 代码耦合度高,改样式要动 JSP,改逻辑要动 Servlet。对课程设计来说,这个代价可以接受。

真正需要留意的分界点在“内容编辑器”上。影视创作论坛发帖经常要贴剧本、贴分镜说明,纯 textarea 体验很差。常见做法是引一个轻量富文本编辑器(如 wangEditor 早期版本),把 HTML 内容存进content字段,展示时用<c:out value="${post.content}" escapeXml="false"/>输出。这一步会顺带引出一个 XSS 问题,后面避坑章节会讲。

2.2 四个包的分层约定:entity / dao / service / servlet

工程里的 Java 源码一般按职责分包,看清包名基本就看懂了架构:

包名职责典型类
com.forum.entity与表一一对应的 POJOUser、Post、Reply、Board
com.forum.dao只做 SQL,返回实体或集合UserDao、PostDao
com.forum.service业务规则、事务边界、参数校验UserService、PostService
com.forum.servlet收参数、调 service、转发或重定向LoginServlet、PostListServlet
com.forum.filter编码、登录态、权限EncodingFilter、AuthFilter
com.forum.util连接池、分页对象、字符串工具DBUtil、PageBean

需要说明的是,很多课程设计工程会把 service 层省掉,Servlet 里直接 new 一个 Dao 就开始查库。这种写法短期省事,一旦要加“发帖同时给用户加积分”这类跨表操作,事务就没地方放了。我在拆这类项目时,倾向于至少在帖子发布、回复、删除这三处保留 service 层,其余查询可以让 Servlet 直连 Dao,不必为了分层而分层。

2.3 依赖与环境:把 jar 包和版本先对齐

工程一般不是 Maven 结构,WEB-INF/lib下直接躺着 jar。要跑起来,先确认这几样:

  • JDK 1.8(Servlet 3.1 与 Tomcat 9 的组合最稳,JDK 17 会因为模块化限制在编译期报javax找不到)
  • Tomcat 8.5 或 9.0(不要用 Tomcat 10,它的包名从javax.servlet改成了jakarta.servlet,整份代码会全红)
  • MySQL 5.7(5.8/8.0 也能用,但驱动类名和连接串要改)
  • mysql-connector-java-5.1.x.jar、jstl-1.2.jar、standard-1.1.2.jar,这三个缺一个页面就会抛 500

数据源不引连接池也能跑,但每次请求都DriverManager.getConnection在演示时明显卡顿。我一般会写一个静态工具类,把驱动加载和连接获取封起来:

package com.forum.util; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class DBUtil { private static String url; private static String username; private static String password; // 类加载时读一次配置,避免每次取连接都读文件 static { try (InputStream in = DBUtil.class.getClassLoader() .getResourceAsStream("jdbc.properties")) { Properties p = new Properties(); p.load(in); Class.forName(p.getProperty("jdbc.driver")); url = p.getProperty("jdbc.url"); username = p.getProperty("jdbc.username"); password = p.getProperty("jdbc.password"); } catch (Exception e) { // 静态块里抛异常,必须包成 Error,否则会被吞掉 throw new ExceptionInInitializerError("数据源初始化失败: " + e.getMessage()); } } public static Connection getConn() throws SQLException { return DriverManager.getConnection(url, username, password); } public static void close(ResultSet rs, Statement st, Connection conn) { // 关闭顺序与打开顺序相反,且每个都要单独 try,前一个抛异常不能影响后面的 try { if (rs != null) rs.close(); } catch (SQLException ignored) {} try { if (st != null) st.close(); } catch (SQLException ignored) {} try { if (conn != null) conn.close(); } catch (SQLException ignored) {} } }

配套的jdbc.properties放在src根目录,编译后会自动落到WEB-INF/classes下:

jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/film_forum?useUnicode=true&characterEncoding=utf8&useSSL=false jdbc.username=root jdbc.password=123456

这里有两个参数值得单独说。useUnicode=true&characterEncoding=utf8少了,中文标题入库就是问号;useSSL=false少了,MySQL 5.7 以上会在控制台刷一堆警告,虽然不影响功能,但演示时不好看。驱动类名在 MySQL 8 的驱动里要改成com.mysql.cj.jdbc.Driver,连接串再加serverTimezone=Asia/Shanghai,否则时间字段会差 8 小时——这是我从一个“发帖时间总是显示凌晨”的 bug 里换来的经验。

3. 工程结构与数据表:5 张表 + 4 个包撑起整个论坛

搞清楚分层之后,下一步是把“代码长在哪”和“数据存成什么样”对齐。论坛类系统的表设计有个共同点:实体少、关系清楚、读多写少。这份工程的核心就是五张表。

3.1 目录结构:从 webapp 往下看

典型的 Eclipse 动态 Web 工程结构如下,如果你拿到的是 IDEA 工程,只是.idea和src/main的差异,业务代码位置一致:

路径内容
src/com/forum/entityUser.java、Board.java、Post.java、Reply.java
src/com/forum/daoUserDao.java、PostDao.java、ReplyDao.java
src/com/forum/serviceUserService.java、PostService.java
src/com/forum/servletLoginServlet.java、RegisterServlet.java、PostListServlet.java、PostDetailServlet.java、PostAddServlet.java
src/com/forum/filterEncodingFilter.java、AuthFilter.java
WebContent/jspindex.jsp、login.jsp、post_list.jsp、post_detail.jsp、post_add.jsp
WebContent/adminboard_manage.jsp、post_audit.jsp
WebContent/staticcss/、js/、images/(含用户上传的作品封面)
WebContent/WEB-INFweb.xml、lib/、classes/

web.xml里除了 welcome-file,主要就是 Filter 和 Servlet 的映射。如果工程用的是 Servlet 3.0 的@WebServlet注解,web.xml会很干净,只留一个EncodingFilter;两种写法都常见,看web.xml的metadata-complete是不是true就能判断。

3.2 五张表的关系与建表语句

用户发帖、帖子归属板块、帖子下面挂回复、管理员改状态,这四条关系决定了表结构。下面是我按这类工程常见字段整理的建表脚本,字段名与实体类的属性一一对应:

CREATE DATABASE IF NOT EXISTS film_forum DEFAULT CHARSET utf8mb4; USE film_forum; -- 用户表:role 区分普通会员(0)和管理员(1),status 用于封禁 CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, -- 存 MD5 摘要,不存明文 nickname VARCHAR(32), email VARCHAR(64), avatar VARCHAR(255), role TINYINT DEFAULT 0, status TINYINT DEFAULT 1, reg_time DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 板块表:影视创作论坛按内容分区,如剧本、短片、影评、器材 CREATE TABLE t_board ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(32) NOT NULL, description VARCHAR(255), sort INT DEFAULT 0, post_count INT DEFAULT 0 ); -- 帖子表:is_top 置顶、is_essence 加精、status 控制是否已审核 CREATE TABLE t_post ( id INT PRIMARY KEY AUTO_INCREMENT, board_id INT NOT NULL, user_id INT NOT NULL, title VARCHAR(128) NOT NULL, content TEXT, cover VARCHAR(255), -- 作品封面图路径 views INT DEFAULT 0, reply_count INT DEFAULT 0, is_top TINYINT DEFAULT 0, is_essence TINYINT DEFAULT 0, status TINYINT DEFAULT 1, -- 0 待审核 1 已发布 2 已删除 create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_board_time (board_id, create_time) ); -- 回复表:parent_id 支持楼中楼,不需要就把该字段留空 CREATE TABLE t_reply ( id INT PRIMARY KEY AUTO_INCREMENT, post_id INT NOT NULL, user_id INT NOT NULL, content VARCHAR(1000) NOT NULL, parent_id INT DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_post (post_id, create_time) );

几点设计上的取舍值得说清楚。t_post上的idx_board_time联合索引是为板块列表页准备的,列表查询永远是where board_id=? order by is_top desc, create_time desc,走这个索引能避免全表扫描。reply_count和post_count是冗余字段,每次回复时update ... set reply_count = reply_count + 1,读列表时就不用count(*)子查询了——这是论坛类系统最划算的一处反范式。

status字段是审核功能的关键。影视创作论坛里用户上传的是原创剧本、短片链接,管理员多半要过一眼再放出来。默认值设成 0(待审核)还是 1(直接发布),取决于课程设计要不要演示审核流程。如果答辩时需要展示“后台审核”这个功能点,就把它设成 0,前台列表查询统一加and status = 1。

3.3 初始化数据与首次导入

脚本一般随工程一起放在db/film_forum.sql,用命令行导入最快:

# 登录 MySQL 并执行脚本,注意路径换成你解压后的实际位置 mysql -uroot -p123456 --default-character-set=utf8mb4 < db/film_forum.sql # 验证:应该能看到 5 张表和至少一条管理员账号 mysql -uroot -p123456 -e "use film_forum; show tables; select id,username,role from t_user;"

初始化数据至少要有一个管理员账号(role=1)和四个板块(剧本创作、短片分享、影评杂谈、器材交流)。如果脚本里没写,手工补一条:

INSERT INTO t_user(username, password, nickname, role) VALUES ('admin', MD5('123456'), '管理员', 1);

密码用MD5()函数直接生成,登录时 Java 侧对用户输入做同样的摘要再比对。注意:MD5 在今天不算安全方案,但课程设计里够用;如果这是要真正上线的项目,换成 BCrypt 并加盐,改动点只在UserService.login()一处。

4. 核心链路:一个帖子列表请求从 Filter 走到 JSP 的 5 个节点

功能跑通与否,看一条完整链路就够。我选“打开某个板块的帖子列表”这条路径,因为它串起了编码过滤、登录校验、分页查询、JSP 渲染四个环节,几乎覆盖了这个工程的全部技术要点。

4.1 第一站:EncodingFilter 解决中文乱码

所有请求先进编码过滤器。这一步放在最前面,是因为 POST 表单里的中文一旦在getParameter之前没设编码,后面怎么补救都没用:

package com.forum.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter("/*") public class EncodingFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { // 请求体编码,只对 POST 有效;GET 的编码由 Tomcat 的 URIEncoding 决定 req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); chain.doFilter(req, resp); } }

req.setCharacterEncoding只影响请求体,GET 请求的参数在 Tomcat 8 之后默认按 UTF-8 解析,但如果拿到的是 Tomcat 7,需要在server.xml的 Connector 上加URIEncoding="UTF-8"。这就是为什么同样的代码在别人机器上好好的,在你这里搜索关键词全是问号。

4.2 第二站:AuthFilter 判断哪些路径要登录

论坛的规则是:列表和详情页游客可看,发帖、回复、后台必须登录。这个判断写在一个 Filter 里,比在每个 Servlet 里写if (session.getAttribute("user") == null)要干净得多:

@WebFilter("/*") public class AuthFilter implements Filter { // 白名单:静态资源、登录注册、帖子浏览不拦 private static final String[] WHITE = { "/login", "/register", "/post/list", "/post/detail", "/static/", "/jsp/login.jsp", "/jsp/register.jsp" }; @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String uri = request.getRequestURI().substring(request.getContextPath().length()); for (String w : WHITE) { if (uri.startsWith(w)) { chain.doFilter(req, resp); return; } } // 后台路径额外校验角色,普通会员访问 /admin/ 一律打回首页 Object user = request.getSession().getAttribute("loginUser"); if (user == null) { response.sendRedirect(request.getContextPath() + "/jsp/login.jsp"); return; } if (uri.startsWith("/admin/") && ((com.forum.entity.User) user).getRole() != 1) { response.sendRedirect(request.getContextPath() + "/post/list"); return; } chain.doFilter(req, resp); } }

两个 Filter 的执行顺序由web.xml里<filter-mapping>的声明顺序,或注解的类名字母序决定。注意:如果AuthFilter排在EncodingFilter前面,登录失败跳转时写入 session 的提示语会是乱码。稳妥做法是在web.xml里显式声明,把编码过滤器放第一个。

4.3 第三站:PostListServlet 收参数

列表页要处理三个参数:板块 id、页码、可选的关键词。Servlet 的职责很薄——解析参数、调 service、把结果塞进 request、转发 JSP:

@WebServlet("/post/list") public class PostListServlet extends HttpServlet { private final PostService postService = new PostService(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 参数缺失时给默认值,避免 NumberFormatException 直接把页面打崩 int boardId = parseInt(req.getParameter("boardId"), 0); int pageNo = parseInt(req.getParameter("page"), 1); String kw = req.getParameter("kw"); PageBean<Post> page = postService.listByBoard(boardId, kw, pageNo, 10); req.setAttribute("page", page); req.setAttribute("boards", postService.listAllBoards()); req.getRequestDispatcher("/jsp/post_list.jsp").forward(req, resp); } private int parseInt(String s, int def) { try { return Integer.parseInt(s); } catch (Exception e) { return def; } } }

parseInt这个私有方法看着不起眼,却是很多工程翻车的地方——地址栏被人手改成?page=abc,服务端直接 500,答辩现场很尴尬。给默认值是最省事的防御。

4.4 第四站:分页查询与 PageBean

分页是论坛列表的核心。两条 SQL:一条count拿总数算总页数,一条limit拿当前页数据。封装成一个通用PageBean后,所有列表页都能复用:

public class PageBean<T> { private int pageNo; // 当前页,从 1 开始 private int pageSize; // 每页条数 private int total; // 总记录数 private List<T> list; // 当前页数据 public int getTotalPage() { return total % pageSize == 0 ? total / pageSize : total / pageSize + 1; } public boolean isHasPrev() { return pageNo > 1; } public boolean isHasNext() { return pageNo < getTotalPage(); } // getter / setter 省略 }

对应的 DAO 方法,注意limit的两个参数是偏移量和条数,偏移量从 0 开始:

public PageBean<Post> listByBoard(int boardId, String kw, int pageNo, int pageSize) { PageBean<Post> page = new PageBean<>(); page.setPageNo(pageNo); page.setPageSize(pageSize); StringBuilder where = new StringBuilder(" where status = 1 "); List<Object> args = new ArrayList<>(); if (boardId > 0) { where.append(" and board_id = ? "); args.add(boardId); } if (kw != null && !kw.trim().isEmpty()) { where.append(" and title like ? "); args.add("%" + kw.trim() + "%"); } String countSql = "select count(*) from t_post " + where; String dataSql = "select * from t_post " + where + " order by is_top desc, create_time desc limit ?, ?"; // ... 执行 countSql 得到 total,再补两个分页参数执行 dataSql,映射成 List<Post> return page; }

这里拼接的是where条件串,参数一律走?占位符。不要把kw直接拼进 SQL——' or 1=1 --这种输入会让整个帖子库裸奔,是课程设计里最常见的安全扣分项。另外order by is_top desc, create_time desc的顺序不能反,否则置顶帖会被新帖淹没。

4.5 第五站:JSP 渲染与分页条

数据到了 JSP,用 JSTL 遍历即可,不需要写 Java 脚本片段:

<c:forEach items="${page.list}" var="post"> <div class="post-item"> <a href="${pageContext.request.contextPath}/post/detail?id=${post.id}">${post.title}</a> <span>${post.nickname} · <fmt:formatDate value="${post.createTime}" pattern="yyyy-MM-dd HH:mm"/></span> <span>浏览 ${post.views} / 回复 ${post.replyCount}</span> </div> </c:forEach> <%-- 分页条:上一页/下一页用 PageBean 的布尔方法控制,避免页码越界 --%> <c:if test="${page.hasPrev}"> <a href="?boardId=${param.boardId}&page=${page.pageNo - 1}">上一页</a> </c:if> <c:if test="${page.hasNext}"> <a href="?boardId=${param.boardId}&page=${page.pageNo + 1}">下一页</a> </c:if>

fmt:formatDate需要页面顶部<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>,少这一行,时间会直接打印成Tue Mar 12 10:20:31 CST 2024这种 Java 默认格式。列表页做完,详情页、发帖页、回复页基本是同一套模式复制,理解了这条链路,其余页面看一眼就懂。

5. 部署与避坑:从解压到首页打开要过的六道关

代码看懂不等于能跑起来。这一章是我每次拿到类似工程必定会走的部署顺序,以及几个最容易翻车的地方。

5.1 六步部署流程

# 1. 建库导数据(脚本在 db 目录下) mysql -uroot -p --default-character-set=utf8mb4 < db/film_forum.sql # 2. 改 jdbc.properties 里的账号密码,务必和本机一致 # 3. 确认 WEB-INF/lib 下有 mysql-connector、jstl、standard 三个 jar # 4. IDE 中把工程加入 Tomcat,Deployment 里确认 context path(如 /forum) # 5. 启动 Tomcat,先看控制台有没有 ClassNotFoundException # 6. 浏览器访问 http://localhost:8080/forum/post/list 验证列表页

先访问列表页而不是首页,是有讲究的:列表页依赖数据库连通性,能打开就说明连接串、驱动、建表三件事全对;首页往往只有静态内容,打开了也证明不了什么。

5.2 六个高频翻车点

现象一:页面报 404,控制台无异常。原因多半是@WebServlet("/post/list")这类注解没生效,工程web.xml的metadata-complete="true"会关闭注解扫描。解决办法是把该属性删掉或改成false,或者改在web.xml里显式配置<servlet-mapping>。

现象二:所有中文变问号或乱码。三个地方要逐个排查:连接串有没有characterEncoding=utf8、Filter 有没有在getParameter之前执行、数据库和表的字符集是不是utf8mb4。我遇到过一次建库时用了默认的 latin1,改连接串怎么都没用,最后alter database film_forum character set utf8mb4才解决。

现象三:登录成功但一刷新就掉线。通常是 JSP 页面里写死了session="false",或者 Filter 里用request.getSession()时又 new 了一个 session,和登录时存的不是同一个。检查登录 Servlet 里存的是request.getSession().setAttribute("loginUser", user),取的时候也用request.getSession(),不要用getSession(true)重复创建。

现象四:图片上传成功但页面显示裂图。上传目录如果放在工程根目录下的upload/,重新部署 war 包时整个目录会被覆盖清空。稳妥做法是把上传路径配到工程外部(如D:/forum_upload/),再在 Tomcat 里配一个虚拟目录映射;或者接受“演示前重新传一次”的妥协。

现象五:SQL 报Unknown column 'xxx' in 'field list'。实体类加了字段、数据库没加列,或者反过来的情况在二次开发时特别常见。这类错误的排查顺序是:先看报错里的列名,去表结构里desc t_post确认,再回实体类对属性名。

现象六:发帖提交后浏览器提示重复提交表单。刷新页面会重复插数据,这是转发和重定向没分清。写操作(发帖、回复、删除)处理完必须response.sendRedirect(),不能forward()。改一行就能解决,但很多工程里就是错的。

5.3 出问题先看哪三处

第一看 Tomcat 控制台的catalina.out或 IDE 控制台,异常栈的第一行Caused by通常就是根因;第二看浏览器 F12 的 Network,请求状态码是 404 还是 500 决定了排查方向完全不同;第三看 SQL 日志,如果工程没配 log4j,最土的办法是在 DAO 方法里临时System.out.println(sql)打一下拼好的语句,复制到 MySQL 客户端跑一遍,问题立刻现形。这套三板斧用完,九成问题都能定位。

6. 二次开发:在现有骨架上加“作品集 + 审核流”的两处改法

这份工程最值钱的地方不是功能多,而是骨架完整、改动面小。我在它上面做过两次扩展,一次是加“个人作品集”,一次是把审核流从“管理员手动放行”改成“积分自动放行 + 抽检”,两次改动都控制在半天以内。

第一处,作品集。思路是复用t_post而不是新建表,给t_user加works_count冗余字段,个人主页直接查select * from t_post where user_id=? and status=1 order by create_time desc,前台加一个/user/works的 Servlet 即可。真正要动的是权限:作品集页面的删除按钮必须校验session里的用户 id 与帖子的user_id一致,否则改个 URL 参数就能删别人的帖子。这段校验我建议写在 service 里,别放在 JSP 用c:if隐藏按钮——隐藏不等于拦截。

第二处,审核流。原逻辑是status从 0 到 1 由管理员逐条点。改成自动放行的关键是在PostService.add()里加一个分支:

public int add(Post post, User user) { // 老用户(发帖数 >= 3 且未被封禁)直接发布,新用户进待审核队列 boolean trusted = user.getStatus() == 1 && postDao.countByUser(user.getId()) >= 3; post.setStatus(trusted ? 1 : 0); int id = postDao.insert(post); if (trusted) { // 只有真正发布的帖子才更新板块计数,避免待审核内容把统计撑虚 boardDao.incrPostCount(post.getBoardId()); } return id; }

改动只有三行,但它把“谁能直接发、谁要等审核”这条业务规则从散落在各处的 if 收敛到了一处。验证方法是准备两个账号,一个发满三条、一个刚注册,分别发帖后查t_post.status,能稳定得到 1 和 0 就说明分支正确。

还有一处容易被忽略的改造点:帖子详情页的浏览量。update t_post set views = views + 1 where id = ?放在每次详情查询里,压力不大时没问题,但同一个人反复刷新会刷出虚高数字。我一般的做法是用 session 记一个已访问帖子 id 的 Set,同一个会话内只加一次,代码不到十行,演示时数据好看很多。

顺便给个改造顺序的建议,按依赖关系来最省事:

顺序改动影响文件
1加数据库字段film_forum.sql、对应实体类
2改 service 业务规则PostService、UserService
3加或改 Servlet 路由web.xml或注解
4最后动 JSP页面展示与表单

从后往前改必翻车——先改 JSP 再改表结构,中间那段时间页面永远报列不存在,改一次错一次。我头一回拆这类课程设计,图省事直接从 JSP 下手,结果字段名对不上、分页参数丢、编码又乱了一遍,折腾到凌晨才发现是改的顺序反了。从那以后我每次动这类 JavaEE 老工程,都强制先跑通列表页、再动数据库、最后碰页面,一步一验证。希望帮到你。

本文还有配套的精品资源,点击获取

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

Cookie安全实践:从document.cookie可见性到HttpOnly与CSP加固

简介&#xff1a;这套名为 cookie-stealer 的 JS 小工具&#xff0c;定位为前端安全与浏览器 Cookie 机制的学习演示&#xff0c;适合具备基础脚本知识、希望理解 Cookie 读取流程、调试方式与风险边界的学生和开发者参考。压缩包共 7 个文件&#xff0c;约 33KB&#xff0c;包…

作者头像 李华
网站建设 2026/11/6 2:10:11

eNSP IPv6校园网实验:环境搭建、拓扑配置与验收排错

简介&#xff1a;这份基于eNSP的IPv6校园网网络规划与设计实验包&#xff0c;面向网络工程、计算机网络课程设计学生及准备网络技术认证的学习者&#xff0c;用于完整复现一个具备IPv6双栈接入、路由与安全策略的校园网综合实验。包内共48个文件&#xff0c;以cfg设备配置、efz…

作者头像 李华
网站建设 2026/11/6 2:09:50

ThinkPad SL系列无线网卡白名单解锁指南

简介&#xff1a;本资源专为ThinkPad SL系列&#xff08;SL300/SL400/SL500&#xff09;笔记本用户设计&#xff0c;解决官方BIOS严格限制无线网卡型号导致无法更换兼容网卡的核心痛点&#xff0c;适用于具备基础DOS操作与BIOS刷写经验的硬件爱好者及维修技术人员。压缩包共106…

作者头像 李华
网站建设 2026/11/6 2:09:11

GPTQ量化:175B大模型单卡推理的工程实践

简介&#xff1a;这份PDF资料聚焦大模型量化技术GPTQ&#xff0c;面向希望降低大语言模型推理成本的研究者、算法工程师与部署实践者&#xff0c;系统讲解如何在几乎不损失精度的前提下压缩GPT类模型。内容源自ICLR 2023论文&#xff0c;涵盖GPTQ的一次性权重量化思路、近似二次…

作者头像 李华
网站建设 2026/11/6 2:07:43

Android Studio 新手实战:从零做一个简易计算器

简介&#xff1a;面向K12阶段学习者与Android入门开发者的期末大作业项目&#xff0c;围绕Android Studio实现一个可运行的简易计算器&#xff0c;覆盖从新建Empty Activity项目到生成APK的完整流程。资源包共48个文件&#xff0c;约180KB&#xff0c;包含Java源码、XML布局、G…

作者头像 李华
网站建设 2026/11/6 2:06:10

Datacom-HCIP 备考指南:路由交换与自动化运维核心考点梳理

简介&#xff1a;这份题库面向备考华为Datacom HCIP认证&#xff08;H12-831&#xff09;的考生&#xff0c;尤其适合已具备一定数通基础、需要集中刷题冲刺的学员。内容来自培训机构整理&#xff0c;题型覆盖较全&#xff0c;题目与考试真题重合度较高&#xff0c;可用于熟悉考…

作者头像 李华