☰
新闻管理系统开发实战:Java Web+MySQL从数据库设计到部署全流程
2026/10/6 6:52:13 网站建设 项目流程

简介:这是一份用于软件综合实习的新闻管理系统设计文档,面向计算机相关专业学生及初级Web开发者,可作为课程设计、毕业设计或实训项目的完整参考资料。文档从系统概述与需求分析入手,详细梳理了前台新闻浏览与后台新闻管理两大模块:前台涵盖主页导航、新闻分类导航、站内模糊搜索、分类显示及友情链接;后台涵盖管理员设置、新闻信息管理、友情链接管理,并给出了数据库设计、系统实现与安全性方面的设计思路。资源为单个doc文档,压缩包仅77KB,虽小巧但内容完整,适合作为项目文档撰写或功能模块设计的对照模板。目前已有534人学习下载,对于需要快速理解新闻管理系统架构并动手实现的学习者,这份文档能提供清晰的功能结构划分和基础开发逻辑参考。

1. 新闻管理系统:从需求文档到能跑起来的完整落地

课设和毕设的季节,总有人拿到的只有一份写满功能描述的 doc,而新闻管理系统就是这类题目里最常见的一种。它前台要按类别展示新闻、按内容做模糊搜索,后台要管登录、管新闻、管友情链接,表面看功能不多,但真正从需求文档落到能跑的 Web 应用,中间隔着数据库设计、权限过滤、文件上传和一堆编码坑。这篇把整套系统从需求拆到部署,用 Java Web + MySQL 这条最稳妥的路线完整走一遍。新手可以直接照着复现,做过类似系统的人可以跳过前几章,直接翻到常见问题那章看坑点。

先说结论:这套系统真正的难点不在 CRUD,而在三个容易被忽略的细节——搜索需求里明确要求按新闻内容而不是标题查询、后台所有页面必须被登录状态保护、友情链接的 LOGO 上传要处理好相对路径。这三个点任何一个没做到,验收的时候都会被指出来返工。

2. 数据库设计先行:六张表的结构与字段取舍

2.1 为什么先定表结构:把功能结构图映射成表

拿到需求文档的第一步绝对不是写页面,而是把功能结构图翻译成表结构。新闻管理系统前台有分类导航、新闻分类显示、站内搜索、友情链接,后台有管理员设置、新闻信息管理、友情链接管理,这些功能点对应下来一共六张表:admin、category、news、friend_link,再加两张扩展表 comment 和 admin_log。

comment 表是为了给新闻加评论功能预留的,需求文档没提,但很多课设题目会现场加这个要求,先建上不亏。admin_log 是操作日志,记录管理员在后台做了哪些操作,这个表在答辩时很加分,因为需求里写了「后台由管理员进行管理维护,保证了网站的安全性」,日志就是安全性的最直接体现。

建表 SQL 如下:

CREATE DATABASE IF NOT EXISTS news_system DEFAULT CHARACTER SET utf8mb4; USE news_system; CREATE TABLE admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE category ( id INT PRIMARY KEY AUTO_INCREMENT, category_name VARCHAR(50) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE news ( id INT PRIMARY KEY AUTO_INCREMENT, category_id INT NOT NULL, title VARCHAR(200) NOT NULL, content TEXT, author VARCHAR(50), publish_time DATETIME DEFAULT CURRENT_TIMESTAMP, click_count INT DEFAULT 0, CONSTRAINT fk_news_category FOREIGN KEY (category_id) REFERENCES category(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE friend_link ( id INT PRIMARY KEY AUTO_INCREMENT, site_name VARCHAR(100) NOT NULL, site_url VARCHAR(255) NOT NULL, logo_path VARCHAR(255) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE comment ( id INT PRIMARY KEY AUTO_INCREMENT, news_id INT NOT NULL, nickname VARCHAR(50), content VARCHAR(500), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE admin_log ( id INT PRIMARY KEY AUTO_INCREMENT, admin_id INT, action VARCHAR(200), log_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这段 SQL 的逻辑分三层。news 表里的 category_id 是外键,关联 category 表的 id,保证每条新闻必然属于一个存在的类别。admin_log 里的 admin_id 并不建物理外键,因为日志表只要记录是谁做的操作就够了,强外键反而会让删除管理员变得麻烦。如果后台要求管理员能删除,物理外键会造成删除失败或者级联删掉日志数据。

使用 utf8mb4 而不是 utf8,是因为 utf8 在 MySQL 里只能存 3 字节的字符,一些生僻字和表情符号会直接报错或者变成问号。新闻内容里可能出现特殊符号,这一步直接用 utf8mb4 省得后面返工。

接下来插入需求里列出的八个新闻类别:

INSERT INTO category (category_name) VALUES ('时政要闻'),('财经观察'),('世界军事'),('科学教育'), ('法制道德'),('社会百态'),('体育世界'),('时尚娱乐');

类别数据是需求文档写死的,必须原样录进去。注意不要在 category 表里加排序字段,因为前台分类导航就是按插入顺序显示的,加字段反而会让逻辑复杂化。

2.2 表字段怎么定:类型、长度与外键的取舍

news 表的 title 用 VARCHAR(200),是考虑到中文标题一般不超过 60 个字,200 的余量足够容纳特殊情况。content 用 TEXT 类型,MySQL 的 TEXT 最大存储 64KB,一条新闻的正文完全够用。如果题目要求支持长文,就改成 MEDIUMTEXT,但课设级别用 TEXT 就够了。

publish_time 用 DATETIME 并设置 DEFAULT CURRENT_TIMESTAMP,这样在插入新闻的时候不需要手动写时间。click_count 加 DEFAULT 0,新闻详情页每次被访问就加一,这个字段可以用来做热点新闻排序,答辩时可以作为扩展功能的素材。

category_id 和 news_id 这两个外键字段,注意类型必须和主表完全一致,都是 INT,否则 JOIN 查询会走全表扫描。friend_link 表的 site_url 用 VARCHAR(255),因为有些网站地址带着一长串参数,255 是 URL 字段的常见安全值。

2.3 JDBC 连接配置:三处必须改对的参数

数据库建好后,Java Web 项目要连上 MySQL,核心就在 jdbc.properties 这个配置文件。用 properties 文件而不是硬编码在 Java 里,是为了换环境时不用重新编译。

jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/news_system?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false jdbc.username=root jdbc.password=123456

这里三个参数最容易出问题。characterEncoding=utf8 负责应用和数据库之间的中文编码,不写它,中文存进去是乱码,读出来也是乱码。serverTimezone=Asia/Shanghai 是 MySQL 8.x 必须带的,不写会报时区错误。useSSL=false 是在本机开发时关闭 SSL 握手,不然每次都报 warning,虽然不影响运行但会干扰排查其他问题。

对应的 JDBC 工具类:

import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; public class DBUtil { private static String url; private static String user; private static String password; static { try { InputStream in = DBUtil.class.getClassLoader() .getResourceAsStream("jdbc.properties"); Properties props = new Properties(); props.load(in); Class.forName(props.getProperty("jdbc.driver")); url = props.getProperty("jdbc.url"); user = props.getProperty("jdbc.username"); password = props.getProperty("jdbc.password"); } catch (Exception e) { throw new ExceptionInInitializerError(e); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url, user, password); } }

这段代码把配置文件读取和驱动加载放在静态代码块里,类第一次被加载时就执行。如果配置文件缺失或驱动类名写错,会直接抛 ExceptionInInitializerError,项目一启动就能发现问题,而不是跑到第一个查询才报 ClassNotFoundException。getConnection 每次返回新连接,课设项目并发量不大,这样够用了。

3. 前台功能拆解:分类导航、模糊搜索与新闻展示

3.1 三层页面结构:index.jsp、list.jsp、detail.jsp 各自负责什么

前台的页面职责必须拆清楚,否则所有逻辑都堆在一个 JSP 里会变成难以维护的巨型页面。我的做法是拆成三个文件:index.jsp 显示主页导航、八个分类的最新新闻标题列表、搜索框和友情链接区;list.jsp 接收类别 ID 参数,显示某个分类下的全部新闻列表并支持分页;detail.jsp 接收新闻 ID 参数,显示新闻全文并累加点击量。

三个页面共用同一个顶部导航区,可以抽成 header.jsp 用 include 引入。横幅广告条、LOGO、当前日期、分类导航按钮都在 header.jsp 里,这样改导航只用改一处。主页上的「MORE」按钮指向 list.jsp?categoryId=某个值,新闻标题指向 detail.jsp?newsId=某个值,参数传递用 GET 请求足够。

3.2 分类导航与列表页:分页 SQL 的正确写法

分类列表页的核心是新闻数据访问对象,也就是 DAO 层的查询方法。这个查询有两个要点:一是用 PREPARED 语句防止 SQL 注入,二是用 LIMIT 做分页防止一次查出太多数据。

public List<News> findNewsByCategory(int categoryId, int offset, int limit) { String sql = "SELECT id, category_id, title, author, publish_time " + "FROM news WHERE category_id = ? " + "ORDER BY publish_time DESC LIMIT ?, ?"; List<News> list = new ArrayList<>(); try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, categoryId); ps.setInt(2, offset); ps.setInt(3, limit); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { News news = new News(); news.setId(rs.getInt("id")); news.setCategoryId(rs.getInt("category_id")); news.setTitle(rs.getString("title")); news.setAuthor(rs.getString("author")); news.setPublishTime(rs.getTimestamp("publish_time")); list.add(news); } } } catch (SQLException e) { e.printStackTrace(); } return list; }

LIMIT 后面的问号参数也是用 setInt 设置的,MySQL 支持在 LIMIT 子句里使用占位符。offset 表示从第几条开始取,limit 表示取几条。每页显示 5 条新闻的话,第一页 offset=0,第二页 offset=5,第三页 offset=10。还有一个关键点:列表页的 SELECT 不要查 content 字段,正文很长,列表页只需要标题、作者、发布时间和所属分类,查出来的数据越少页面渲染越快,这个习惯到企业开发里也是通用的。

3.3 站内搜索按内容而非标题:模糊查询的正确实现

需求文档里明确标注了一句话:此查询中按新闻内容进行查询,而不是新闻标题。这是很多人会踩的坑,默认思维里搜索就是搜标题,但这个题目偏偏要求搜正文。搜索逻辑写在 SearchServlet 里,接收 keyword 和 categoryId 两个参数。

public List<News> searchNews(String keyword, int categoryId) { StringBuilder sql = new StringBuilder( "SELECT id, category_id, title, content " + "FROM news WHERE content LIKE ?"); if (categoryId > 0) { sql.append(" AND category_id = ?"); } sql.append(" ORDER BY publish_time DESC"); List<News> list = new ArrayList<>(); try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql.toString())) { ps.setString(1, "%" + keyword + "%"); if (categoryId > 0) { ps.setInt(2, categoryId); } try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { News news = new News(); news.setId(rs.getInt("id")); news.setTitle(rs.getString("title")); news.setContent(rs.getString("content")); list.add(news); } } } catch (SQLException e) { e.printStackTrace(); } return list; }

这段代码有两个必须理解的点。第一个是通配符 % 拼接在参数值里而不是 SQL 语句里,PreparedStatement 会把整个值当作普通字符串处理,关键字里的单引号、百分号都不会破坏 SQL 结构。第二个是 if (categoryId > 0) 的写法,这个条件区分了两种情况:下拉列表选了「全部类别」时 categoryId 传 0,SQL 只看内容;选了具体类别时追加 AND category_id = ?,在内容匹配的基础上再按类别过滤。

搜索结果里要把 content 中命中的那一段截取出来加高亮,做法是把内容按 keyword 切割,取前后各 30 个字符作为摘要。这个功能在答辩时很好讲,评委问起来也容易说清楚。

3.4 新闻详情页:点击量自增的原子性

detail.jsp 显示新闻全文前要做两件事:根据 newsId 查出新闻记录,同时把 click_count 加一。很多人把这两步做成先查再更新,这在高并发下会丢计数。正确做法是一条 UPDATE 完成自增:

UPDATE news SET click_count = click_count + 1 WHERE id = ?;

这条 SQL 依赖数据库自身的原子操作,不需要先查出来再算,不会出现两个请求同时读到相同值的问题。查新闻详情的 SQL 用 JOIN 把类别名称带出来,因为详情页要显示「所属分类」这个信息。

SELECT n.id, n.category_id, c.category_name, n.title, n.content, n.author, n.publish_time, n.click_count FROM news n LEFT JOIN category c ON n.category_id = c.id WHERE n.id = ?;

4. 后台管理实现:登录验证、新闻 CRUD 与友情链接维护

4.1 登录验证的完整链路:LoginServlet 与 Session 的配合

后台入口在前台页面最下方,单击进入 login.jsp。登录表单提交到 LoginServlet,验证逻辑是先对密码做 MD5 加密再与数据库比对。密码不能明文存储,这是个基本的安全意识问题。

@WebServlet("/login") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String username = request.getParameter("username"); String password = MD5Util.md5(request.getParameter("password")); Admin admin = new AdminDao().findByUsernameAndPassword(username, password); if (admin != null) { request.getSession().setAttribute("loginAdmin", admin); response.sendRedirect(request.getContextPath() + "/admin/index.jsp"); } else { request.setAttribute("msg", "用户名或密码错误,请重新输入"); request.getRequestDispatcher("login.jsp").forward(request, response); } } }

登录成功用 sendRedirect 重定向到后台主页,失败用 forward 转发回登录页并携带错误提示。重定向和转发的差别在于:重定向会让浏览器重新发起一次请求,地址栏变成后台主页,用户刷新页面不会重复提交表单;转发是服务端内部跳转,地址栏还是 /login,刷新会再次触发表单提交。登录成功必须用重定向,这是个细节但很重要。

Session 在登录成功后写入 loginAdmin 属性,之后的每个后台请求都靠这个属性判断是否已登录。MD5Util.md5 是工具方法,把输入的字符串转成 32 位十六进制摘要。MD5 不算强加密,但课设级别够用,如果想让答辩更有亮点可以换成加盐 MD5,也就是 MD5(密码 + 固定盐值)。

后台的安全保护靠一个 Filter 拦截所有 /admin/ 路径。这个过滤器是整个后台管理系统的安全底线。

@WebFilter("/admin/*") public class LoginFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; HttpSession session = request.getSession(false); if (session != null && session.getAttribute("loginAdmin") != null) { chain.doFilter(req, resp); } else { response.sendRedirect(request.getContextPath() + "/login.jsp"); } } }

request.getSession(false) 表示如果当前没有 Session 就返回 null,而不是创建一个新的。这样设计有两个好处:未登录用户访问后台页面时不会被强制创建 Session,节省内存;已经登录但 Session 超时的用户会被正确拦截到登录页。如果写成 getSession(true),未登录用户也会拿到一个空 Session,过滤条件永远不成立,照样被拦截,只是白白创建了无用对象。

4.2 新闻信息管理:添加、修改、删除与下拉框联动

后台新闻管理三个操作对应三个 Servlet 或者一个 Servlet 加 method 参数区分。添加新闻的表单要包含三个字段:新闻类别下拉框、新闻标题输入框、新闻内容文本域。下拉框的数据要动态读取 category 表,不能在 JSP 里写死,因为类别可能被后台维护。

@WebServlet("/admin/news/add") public class AddNewsServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); int categoryId = Integer.parseInt(request.getParameter("categoryId")); String title = request.getParameter("title"); String content = request.getParameter("content"); String author = "admin"; String sql = "INSERT INTO news (category_id, title, content, author) " + "VALUES (?, ?, ?, ?)"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, categoryId); ps.setString(2, title); ps.setString(3, content); ps.setString(4, author); ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } response.sendRedirect(request.getContextPath() + "/admin/news/list.jsp"); } }

发布时间的填充依赖数据库的 DEFAULT CURRENT_TIMESTAMP,所以 INSERT 语句里不用写 publish_time 字段。修改新闻是 UPDATE 语句加 WHERE id = ?,删除是 DELETE 语句。删除时要注意有一个常见需求:删除新闻后评论区数据如何处理。如果没有外键约束,评论会成为孤儿数据,所以删新闻之前先执行 DELETE FROM comment WHERE news_id = ?,再删新闻本身。

4.3 友情链接管理:LOGO 上传与保存路径的处理

友情链接管理是后台功能里最容易出问题的模块,核心在于 LOGO 图片的上传。Servlet 3.0 提供的 Part API 可以处理文件上传,不需要额外引入第三方库。

@WebServlet("/admin/link/add") @MultipartConfig(maxFileSize = 1024 * 1024 * 2) public class AddLinkServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String siteName = request.getParameter("siteName"); String siteUrl = request.getParameter("siteUrl"); Part part = request.getPart("logo"); String submittedFileName = part.getSubmittedFileName(); String ext = submittedFileName.substring(submittedFileName.lastIndexOf(".")); String fileName = UUID.randomUUID().toString().replace("-", "") + ext; String uploadPath = getServletContext().getRealPath("/uploads/link"); File dir = new File(uploadPath); if (!dir.exists()) { dir.mkdirs(); } part.write(uploadPath + File.separator + fileName); String sql = "INSERT INTO friend_link (site_name, site_url, logo_path) " + "VALUES (?, ?, ?)"; // 执行参数:siteName、siteUrl、uploads/link/文件名 } }

@MultipartConfig 注解的 maxFileSize 限制单张图片最大 2MB,超出会抛异常。UUID.randomUUID() 生成随机文件名是为了防止不同网站上传相同文件名的 LOGO 互相覆盖,比如两个站都传了 logo.png,不用 UUID 的话后上传的会覆盖先前的。part.write 把文件写到服务器磁盘的 uploads 目录,数据库里存的是相对路径 uploads/link/文件名,而不是磁盘绝对路径。

数据库存相对路径是关键,部署到不同机器、不同操作系统,绝对路径都不一样,写死绝对路径等于写死环境。页面引用 LOGO 时用${pageContext.request.contextPath}/uploads/link/xxx.png,Tomcat 会把 uploads 目录映射成 URL,前端直接访问即可。

5. 常见问题与避坑:登录失效、中文乱码与图片上传的五个坑

课设验收前我会强制自己和学生把下面这五类问题完整踩一遍,都是实际项目中反复出现的真实翻车点。

坑一:搜索结果为空,明明数据库里有关键字。

现象:在前台搜索框输入新闻里出现过的词,结果一条都查不出来。原因:需求要求按内容搜索,但 DAO 的 SQL 写成了 WHERE title LIKE ?,标题里恰好没这个词。还有另一个可能:keyword 从前台传到 Servlet 时编码不对,中文变成了乱码,乱码当然匹配不到任何记录。解决:先把 SQL 改成 content LIKE ?,确认字段选对了;再在 Servlet 里检查 request.getParameter 拿到的值是否正常,不正常就检查请求编码过滤器是否配置。

坑二:页面全是问号,中文乱码成「???」或「锟斤拷」。

现象:新闻标题在列表页显示为问号,后台添加的中文新闻内容存进数据库后变成乱码。原因:MySQL 连接 URL 少了 characterEncoding=utf8,或者 jsp 页面本身没声明 UTF-8。解决:jdbc.url 里加上 useUnicode=true&characterEncoding=utf8,JSP 顶部写<%@ page contentType="text/html; charset=UTF-8" %>,再补一个全局编码过滤器把所有请求统一设置为 UTF-8。

@WebFilter("/*") public class EncodingFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { req.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8"); chain.doFilter(req, resp); } }

坑三:友情链接的 LOGO 图上传播放后就 404。

现象:后台提示上传成功,友链记录也在,但前台图片区域是破图。原因:数据库存的是磁盘绝对路径,比如 D:/apache-tomcat/webapps/news/uploads/...,部署机器的目录结构一换,路径就失效。解决:数据库只存相对路径 uploads/link/文件名,JSP 页面用${pageContext.request.contextPath}拼完整地址。

坑四:后台页面不登录也能直接访问。

现象:地址栏输入 http://localhost:8080/news/admin/news/list.jsp 直接打开后台列表页,没有任何拦截。原因:@WebFilter("/admin/") 没有生效,或者根本没写 LoginFilter。解决:检查 Filter 类上有没有 @WebFilter 注解,注意注解路径必须以 / 开头;确认项目是 Servlet 3.0 及以上版本,Tomcat 7+ 支持注解扫描。如果用的是 web.xml 配置过滤器,还要检查<url-pattern>是否写成 /admin/。

坑五:登录时密码输入正确还是提示错误。

现象:第一次用管理员账号登录前台底部入口总是提示用户名或密码错误。原因:直接在数据库里插入了一条明文密码,比如 INSERT INTO admin VALUES (1, 'admin', '123456'),但登录校验时把用户输入转成 MD5 再比对,两者当然不一致。解决:用工具类把密码转成 MD5 再写入数据库:

public static String md5(String source) { try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] digest = md.digest(source.getBytes("UTF-8")); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); } return sb.toString(); } catch (Exception e) { throw new RuntimeException(e); } }

然后执行 UPDATE admin SET password = '转换后的密文' WHERE username = 'admin'。从那以后,我每次初始化项目都会先准备好一条 MD5 后的管理员数据,不会再在这个问题上浪费时间。

6. 部署上线前的验证清单:用一条路径测透前后台

系统写完不等于验收通过,建议按下面这条路径完整走一遍,每一环节出错都能马上定位。先把 six_tables.sql 导入 MySQL,修改 jdbc.properties 里的用户名密码,然后把项目打包成 WAR 部署到 Tomcat 的 webapps 目录,启动。

步骤操作预期结果
1访问 http://localhost:8080/news/主页显示八大分类、当前日期、搜索框、友情链接区
2点击「财经观察」分类跳转 list.jsp,只显示该分类的新闻,每页最多 5 条
3点击「MORE」按钮显示该分类全部新闻列表,翻页正常
4搜索框输入「GDP」,类别选「全部」列出所有内容包含「GDP」的新闻
5点击任意新闻标题详情页显示完整内容,刷新后点击量 +1
6页面底部点击「后台入口」跳转 login.jsp
7不登录直接访问 admin/news/list.jsp被过滤器拦截,重定向回登录页
8输入管理员账号密码登录跳转后台主页,Session 写入成功
9后台添加一条新闻,选择类别、填标题和内容前台对应分类下出现新新闻
10后台修改刚才的新闻标题前台列表页和详情页同步更新
11后台添加一个友链并上传 LOGO前台底部友情链接区显示新链接和图片
12点击「安全退出」Session 清除,返回登录页,再访问后台被拦截

这套流程覆盖了前台展示、搜索、详情、后台登录、过滤器拦截、新闻 CRUD、友链上传和退出登录全部关键路径。第 7 步是验证过滤器是否真的生效,很多人部署完才发现后台裸奔,这一步一定要测。第 8 步验证的是密码加密是否正确,进不去就回头看 MD5 那一节。

如果是做毕业设计,还可以在这个基础上加两个低成本的功能点:新闻评论模块把 comment 表用起来,前台详情页展示评论列表、后台管理员可以删除违规评论;操作日志把 admin_log 表用起来,后台每次增删改都写入一条记录,在后台管理页面加一个日志查询入口。这两个都是现有表结构直接支持的,不需要改数据库,只加界面和 Servlet 逻辑。

从那以后,我每次拿到任何课设题目,都会先画一遍这张验证路径表,再动手写代码,而不是写完后随手点几个页面就当做完。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询