在JavaWeb开发中实现留言功能,是一个经典且基础的项目实践,涵盖了前端交互、后端处理、数据存储等多个核心环节,本文将从需求分析、技术选型、环境搭建、数据库设计、后端实现、前端开发、功能扩展及测试部署等方面,系统介绍JavaWeb留言功能的实现步骤。

需求分析与技术选型
实现留言功能前,需明确核心需求:用户可发布留言、查看留言列表、回复留言,管理员可删除不当留言,基于这些需求,技术栈选择如下:
- 后端:Servlet + JSP(传统JavaWeb方案,适合入门),或Spring Boot(简化配置,适合进阶);
- 数据库:MySQL(关系型数据库,适合结构化数据存储);
- 前端:HTML + CSS + JavaScript(基础页面),结合jQuery实现异步请求;
- 其他:JDBC(数据库连接),或MyBatis(持久层框架,简化SQL操作)。
本文以传统Servlet + JSP + MySQL为例,兼顾学习成本与实用性。
开发环境搭建
- JDK安装:配置环境变量,确保
java -version命令可用(建议JDK 8及以上)。 - Tomcat服务器:下载并解压Tomcat,配置
CATALINA_HOME环境变量,通过startup.sh(Linux)或startup.bat(Windows)启动服务。 - 数据库工具:安装MySQL,创建数据库(如
message_board),并使用Navicat等工具管理数据表。 - 开发工具:IntelliJ IDEA或Eclipse,安装Tomcat插件和MySQL连接驱动。
数据库设计
留言系统的核心数据包括用户信息和留言信息,需设计两张表:

用户表(user)
| 字段名 | 类型 | 描述 |
|---|---|---|
| id | int | 主键,自增 |
| username | varchar(50) | 用户名 |
| password | varchar(50) | 密码(加密存储) |
留言表(message)
| 字段名 | 类型 | 描述 |
|---|---|---|
| id | int | 主键,自增 |
| content | text | |
| user_id | int | 外键,关联user.id |
| parent_id | int | 回复的留言ID(0表示顶级留言) |
| create_time | datetime | 留言时间 |
通过SQL语句创建表:
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(50) NOT NULL
);
CREATE TABLE message (
id INT PRIMARY KEY AUTO_INCREMENT,
content TEXT NOT NULL,
user_id INT NOT NULL,
parent_id INT DEFAULT 0,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES user(id)
);
后端实现
项目结构
在IDEA中创建Dynamic Web Project,目录结构如下:
src/main
├── java
│ └── com
│ └── message
│ ├── dao
│ │ ├── MessageDao.java(数据访问层)
│ │ └── UserDao.java
│ ├── entity
│ │ ├── Message.java(实体类)
│ │ └── User.java
│ ├── servlet
│ │ ├── AddMessageServlet.java(添加留言)
│ │ ├── ListMessageServlet.java(展示留言)
│ │ └── DeleteMessageServlet.java(删除留言)
│ └── util
│ └── DBUtil.java(数据库连接工具类)
└── webapp
├── WEB-INF
│ └── web.xml(配置Servlet映射)
├── index.jsp(留言列表页)
└── addMessage.jsp(添加留言页)
数据库连接工具类(DBUtil)
public class DBUtil {
private static final String URL = "jdbc:mysql://localhost:3306/message_board?useSSL=false";
private static final String USER = "root";
private static final String PASSWORD = "123456";
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PASSWORD);
}
public static void close(Connection conn, Statement stmt, ResultSet rs) {
try { if (rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); }
try { if (stmt != null) stmt.close(); } catch (SQLException e) { e.printStackTrace(); }
try { if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); }
}
}
实体类(Message.java)
public class Message {
private int id;
private String content;
private int userId;
private int parentId;
private Date createTime;
private String username; // 关联用户名
// getter/setter省略
}
数据访问层(MessageDao.java)
public class MessageDao {
// 添加留言
public void add(Message message) throws SQLException {
String sql = "INSERT INTO message (content, user_id, parent_id) VALUES (?, ?, ?)";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, message.getContent());
pstmt.setInt(2, message.getUserId());
pstmt.setInt(3, message.getParentId());
pstmt.executeUpdate();
}
}
// 查询所有留言(按时间倒序)
public List<Message> list() throws SQLException {
List<Message> messages = new ArrayList<>();
String sql = "SELECT m.*, u.username FROM message m JOIN user u ON m.user_id = u.id ORDER BY m.create_time DESC";
try (Connection conn = DBUtil.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
Message message = new Message();
message.setId(rs.getInt("id"));
message.setContent(rs.getString("content"));
message.setUserId(rs.getInt("user_id"));
message.setParentId(rs.getInt("parent_id"));
message.setCreateTime(rs.getTimestamp("create_time"));
message.setUsername(rs.getString("username"));
messages.add(message);
}
}
return messages;
}
// 删除留言(及回复)
public void delete(int id) throws SQLException {
String sql = "DELETE FROM message WHERE id = ? OR parent_id = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, id);
pstmt.setInt(2, id);
pstmt.executeUpdate();
}
}
}
Servlet实现
-
AddMessageServlet.java(处理留言提交)

@WebServlet("/addMessage") public class AddMessageServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); String content = req.getParameter("content"); int userId = Integer.parseInt(req.getParameter("userId")); int parentId = Integer.parseInt(req.getParameter("parentId")); Message message = new Message(); message.setContent(content); message.setUserId(userId); message.setParentId(parentId); try { new MessageDao().add(message); resp.sendRedirect("listMessage"); // 重定向到留言列表页 } catch (SQLException e) { e.printStackTrace(); resp.getWriter().write("留言失败"); } } } -
ListMessageServlet.java(展示留言列表)
@WebServlet("/listMessage") public class ListMessageServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { List<Message> messages = new MessageDao().list(); req.setAttribute("messages", messages); req.getRequestDispatcher("index.jsp").forward(req, resp); } catch (SQLException e) { e.printStackTrace(); resp.getWriter().write("加载留言失败"); } } }
web.xml配置
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>AddMessageServlet</servlet-name>
<servlet-class>com.message.servlet.AddMessageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddMessageServlet</servlet-name>
<url-pattern>/addMessage</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ListMessageServlet</servlet-name>
<servlet-class>com.message.servlet.ListMessageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ListMessageServlet</servlet-name>
<url-pattern>/listMessage</url-pattern>
</servlet-mapping>
</web-app>
前端实现
留言列表页(index.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head> 留言板</title>
<style>
.message { border: 1px solid #ddd; margin: 10px 0; padding: 10px; border-radius: 5px; }
.message-content { margin-bottom: 5px; }
.message-info { color: #888; font-size: 12px; }
.reply { margin-left: 20px; background-color: #f9f9f9; }
</style>
</head>
<body>
<h1>留言板</h1>
<a href="addMessage.jsp">发表留言</a>
<c:forEach items="${messages}" var="message">
<div class="message ${message.parentId != 0 ? 'reply' : ''}">
<div class="message-content">${message.content}</div>
<div class="message-info">
用户:${message.username} | 时间:${message.createTime}
<c:if test="${sessionScope.user != null && sessionScope.user.id == message.userId}">
<a href="deleteMessage?id=${message.id}" onclick="return confirm('确定删除?')">删除</a>
</c:if>
<a href="addMessage.jsp?parentId=${message.id}">回复</a>
</div>
</div>
</c:forEach>
</body>
</html>
添加留言页(addMessage.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head> 发表留言</title>
</head>
<body>
<form action="addMessage" method="post">
<input type="hidden" name="userId" value="${sessionScope.user.id}">
<input type="hidden" name="parentId" value="${param.parentId}">
<textarea name="content" rows="5" cols="50" placeholder="请输入留言内容" required></textarea>
<br>
<input type="submit" value="提交">
<a href="listMessage">返回</a>
</form>
</body>
</html>
功能扩展与优化
- 用户登录注册:增加UserDao和LoginServlet,通过session管理用户状态,确保只有登录用户可留言。
- 分页显示:在MessageDao中添加分页查询方法(
LIMIT offset, size),前端通过页码加载不同页数据。 - 富文本编辑:集成UEditor或TinyMCE,支持图片、表情等富文本内容。
- 异步提交:前端使用jQuery的
$.ajax()实现异步留言提交,避免页面刷新,提升用户体验。 - 权限控制:管理员删除留言功能需验证session中的用户角色(如
isAdmin字段)。
测试与部署
- 单元测试:使用JUnit测试MessageDao的增删改查方法,确保数据库操作正确。
- 集成测试:启动Tomcat,访问
http://localhost:8080/项目名/listMessage,测试留言发布、回复、删除等功能。 - 部署上线:将项目打包为WAR文件,复制到Tomcat的
webapps目录,重启Tomcat即可通过公网IP访问。
通过以上步骤,即可实现一个功能完善的JavaWeb留言系统,核心在于分层设计(MVC模式)、数据库表结构设计及前后端数据交互,后续可根据需求扩展更多功能,如留言审核、点赞、搜索等,进一步提升系统实用性。












