在数字化阅读日益普及的背景下,传统纸质书籍和分散的网络文学资源已难以满足现代读者对便捷性、连续性和个性化服务的需求。读者经常面临书籍携带不便、阅读进度无法同步、优质内容发现困难等问题。针对这些痛点,一个集中化、智能化的在线文学阅读平台应运而生。该系统采用经典的JSP+Servlet技术架构,结合MySQL数据库,构建了一个功能完备的在线阅读环境。
平台采用典型的三层架构模式,清晰分离表示层、业务逻辑层和数据访问层。表示层使用JSP动态页面技术,结合HTML、CSS和JavaScript实现用户界面的渲染和交互;业务逻辑层由Servlet充当控制器,负责处理用户请求、调用业务规则和数据验证;数据访问层通过JDBC技术与MySQL数据库进行通信,完成数据的持久化操作。这种架构虽未使用复杂的现代框架,但通过严格的分层设计,确保了代码的可维护性和系统的可扩展性。

数据库设计是系统的核心基础,共包含5张核心表。用户表(users)采用自增主键设计,确保用户标识的唯一性,同时通过唯一索引约束用户名和邮箱,防止数据重复。关键字段包括密码的MD5加密存储、用户角色区分和注册时间记录。
CREATE TABLE users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
role ENUM('admin','user') DEFAULT 'user',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
小说表(novels)的设计体现了内容的层次化管理,包含标题、作者、分类、封面图片等元数据。status字段支持作品的上下架状态管理,created_at和updated_at时间戳实现了内容的版本追踪。
CREATE TABLE novels (
novel_id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
author VARCHAR(100) NOT NULL,
category_id INT NOT NULL,
cover_image VARCHAR(300),
description TEXT,
status ENUM('published','draft') DEFAULT 'draft',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
章节表(chapters)采用与小说的外键关联设计,通过chapter_number字段确保章节顺序的正确性。content字段使用LONGTEXT类型支持大容量文本存储,满足长篇小说章节内容的需求。
用户阅读进度表(reading_progress)是系统的关键创新点,通过联合唯一索引确保每个用户对每本小说只能有一条进度记录。last_read_chapter和last_read_time实现了阅读进度的精准跟踪和同步。
用户认证模块采用Session管理机制,LoginServlet负责验证用户凭证并建立会话。密码通过MD5加密后与数据库存储的密文进行比对,确保安全性。
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
UserDAO userDAO = new UserDAO();
User user = userDAO.authenticate(username, MD5Util.encrypt(password));
if (user != null) {
HttpSession session = request.getSession();
session.setAttribute("user", user);
response.sendRedirect("home.jsp");
} else {
request.setAttribute("error", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}
小说阅读功能的核心控制器ChapterServlet通过章节ID参数动态加载内容。该Servlet处理章节切换、进度更新等操作,确保阅读体验的连贯性。
public class ChapterServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int chapterId = Integer.parseInt(request.getParameter("id"));
int novelId = Integer.parseInt(request.getParameter("novel_id"));
ChapterDAO chapterDAO = new ChapterDAO();
Chapter chapter = chapterDAO.getChapterById(chapterId);
// 更新阅读进度
HttpSession session = request.getSession();
User user = (User) session.getAttribute("user");
ReadingProgressDAO progressDAO = new ReadingProgressDAO();
progressDAO.updateProgress(user.getUserId(), novelId, chapterId);
request.setAttribute("chapter", chapter);
request.getRequestDispatcher("chapter.jsp").forward(request, response);
}
}
内容管理模块为管理员提供了完整的作品生命周期管理功能。NovelManagementServlet支持小说的增删改查操作,通过文件上传组件处理封面图片,并对输入数据进行严格验证。

public class NovelManagementServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
NovelDAO novelDAO = new NovelDAO();
if ("add".equals(action)) {
String title = request.getParameter("title");
String author = request.getParameter("author");
int categoryId = Integer.parseInt(request.getParameter("category_id"));
// 处理文件上传
Part coverPart = request.getPart("cover_image");
String coverPath = FileUploadUtil.saveUploadedFile(coverPart);
Novel novel = new Novel(title, author, categoryId, coverPath);
novelDAO.addNovel(novel);
} else if ("delete".equals(action)) {
int novelId = Integer.parseInt(request.getParameter("novel_id"));
novelDAO.deleteNovel(novelId);
}
response.sendRedirect("novel_management.jsp");
}
}
搜索功能通过SearchServlet实现关键词匹配和分类过滤。该模块支持按标题、作者、内容进行全文搜索,并提供了分页显示机制。
public class SearchServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String keyword = request.getParameter("keyword");
String category = request.getParameter("category");
int page = Integer.parseInt(request.getParameter("page"));
NovelDAO novelDAO = new NovelDAO();
List<Novel> novels = novelDAO.searchNovels(keyword, category, page, 10);
int totalCount = novelDAO.getSearchCount(keyword, category);
request.setAttribute("novels", novels);
request.setAttribute("totalPages", (int) Math.ceil(totalCount / 10.0));
request.getRequestDispatcher("search_results.jsp").forward(request, response);
}
}

数据访问层采用DAO模式封装所有数据库操作。BaseDAO类提供连接管理的基础功能,各实体DAO继承此类并实现特定的数据操作逻辑。
public abstract class BaseDAO {
protected Connection getConnection() throws SQLException {
return DataSourceManager.getDataSource().getConnection();
}
protected void closeResources(Connection conn, PreparedStatement stmt, ResultSet rs) {
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public class NovelDAO extends BaseDAO {
public List<Novel> getNovelsByCategory(int categoryId, int limit) {
List<Novel> novels = new ArrayList<>();
String sql = "SELECT * FROM novels WHERE category_id = ? AND status = 'published' LIMIT ?";
try (Connection conn = getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, categoryId);
stmt.setInt(2, limit);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
novels.add(mapResultSetToNovel(rs));
}
} catch (SQLException e) {
e.printStackTrace();
}
return novels;
}
private Novel mapResultSetToNovel(ResultSet rs) throws SQLException {
return new Novel(
rs.getInt("novel_id"),
rs.getString("title"),
rs.getString("author"),
rs.getInt("category_id"),
rs.getString("cover_image"),
rs.getString("description"),
rs.getString("status"),
rs.getTimestamp("created_at"),
rs.getTimestamp("updated_at")
);
}
}
前端页面采用响应式设计,使用Bootstrap框架确保在不同设备上的良好显示效果。JSP页面通过JSTL标签库和EL表达式实现数据的动态渲染,减少脚本代码的嵌入。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<div class="novel-list">
<c:forEach var="novel" items="${novels}">
<div class="novel-item col-md-4">
<div class="card">
<img src="${novel.coverImage}" class="card-img-top" alt="${novel.title}">
<div class="card-body">
<h5 class="card-title">${novel.title}</h5>
<p class="card-text">作者: ${novel.author}</p>
<a href="chapter?novel_id=${novel.novelId}&chapter=1"
class="btn btn-primary">开始阅读</a>
</div>
</div>
</div>
</c:forEach>
</div>

系统安全性方面,通过过滤器链实现访问控制,对敏感操作进行权限验证和SQL注入防护。XSSFilter对用户输入进行转义处理,防止跨站脚本攻击。
@WebFilter("/*")
public class SecurityFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String path = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
// 检查访问权限
if (path.startsWith("/admin") && !isAdmin(httpRequest)) {
httpResponse.sendRedirect(httpRequest.getContextPath() + "/login.jsp");
return;
}
chain.doFilter(new XSSRequestWrapper(httpRequest), response);
}
private boolean isAdmin(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
User user = (User) session.getAttribute("user");
return user != null && "admin".equals(user.getRole());
}
return false;
}
}
在性能优化方面,系统实现了数据库连接池管理,避免频繁创建和销毁连接的开销。通过查询结果分页和懒加载策略,有效控制内存使用和提高响应速度。
未来优化方向包括引入全文搜索引擎提升检索效率,实现基于用户行为的个性化推荐算法,开发移动端应用程序扩展访问渠道,增加社交功能如书评互动和阅读社区,以及采用更安全的密码哈希算法替代MD5。
该在线阅读平台通过严谨的架构设计和完整的功能实现,为读者提供了稳定高效的数字化阅读体验。系统采用成熟的技术方案,在保证功能完备性的同时兼顾了可维护性和扩展性,为后续的功能增强和技术升级奠定了坚实基础。