1. 项目概述:JSP图书馆读者行为分析系统
这个基于JSP的图书馆读者行为分析系统,是我在参与某高校图书馆数字化改造时开发的一套实用工具。核心功能是通过抓取读者在图书馆门户网站的浏览轨迹、借阅记录、检索关键词等数据,构建读者画像并分析行为模式。系统上线后帮助图书馆员精准掌握读者偏好,优化图书采购策略和阅读推荐算法。
整套系统采用经典的JSP+Servlet+JavaBean架构,数据库选用MySQL 5.7,前端使用Bootstrap框架实现响应式布局。特别之处在于集成了Apache ECharts进行可视化展示,以及通过自定义日志采集模块实现无侵入式数据收集。下面我将从技术选型到部署上线的完整流程进行拆解,包含实际开发中遇到的典型问题及解决方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构解析
2.1 整体技术栈设计
选择JSP作为主要技术方案主要基于以下考量:
- 高校原有系统多采用Java技术栈,需保持技术延续性
- JSP的taglib和EL表达式适合快速开发数据展示页面
- 与学校统一身份认证系统(CAS)集成更方便
技术栈组成:
- 前端层:Bootstrap 3 + jQuery + ECharts 4.0
- Web层:JSP 2.2 + Servlet 3.1 + JSTL 1.2
- 业务层:Spring 4.3(仅用于IoC管理)
- 数据层:MyBatis 3.4 + MySQL 5.7 + Druid连接池
- 辅助工具:Log4j 2.0(日志)、POI 3.17(报表导出)
注意:虽然现在主流是Spring Boot,但学校服务器环境限制必须使用传统部署方式。这也是许多传统单位信息化项目的典型约束条件。
2.2 数据库设计要点
读者行为分析的核心表结构设计:
sql复制CREATE TABLE reader_behavior (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
reader_id VARCHAR(20) NOT NULL COMMENT '学工号',
action_type TINYINT NOT NULL COMMENT '1-检索 2-浏览 3-借阅 4-续借',
book_id VARCHAR(15) COMMENT 'ISBN编号',
search_keyword VARCHAR(100) COMMENT '检索关键词',
dwell_time INT COMMENT '页面停留时长(秒)',
action_time DATETIME NOT NULL COMMENT '行为时间',
device_type VARCHAR(10) COMMENT '终端类型'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE book_metadata (
isbn VARCHAR(15) PRIMARY KEY,
title VARCHAR(200) NOT NULL,
author VARCHAR(100) NOT NULL,
publisher VARCHAR(100),
publish_year INT,
category_id INT COMMENT '中图分类号'
);
设计时的特殊考虑:
- 使用utf8mb4字符集支持emoji等特殊符号(学生检索时确实会用)
- 行为表与元数据表分离,避免频繁更新的行为数据影响基础信息
- 建立复合索引 (reader_id, action_time) 加速查询
3. 核心功能实现
3.1 行为数据采集模块
采用过滤器+监听器方案实现无侵入采集:
java复制// 行为采集过滤器
public class BehaviorFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
// 记录行为日志
long dwellTime = (System.currentTimeMillis() - startTime) / 1000;
BehaviorLog log = new BehaviorLog(
req.getSession().getAttribute("userId"),
getActionType(req.getRequestURI()),
req.getParameter("isbn"),
req.getParameter("keyword"),
dwellTime
);
LogQueue.getInstance().add(log); // 异步写入队列
}
}
关键实现技巧:
- 使用单例模式的内存队列缓冲日志,避免直接写库影响性能
- 通过URI模式匹配自动识别行为类型(检索/浏览等)
- 采用生产者-消费者模式处理队列中的日志
3.2 可视化分析模块
基于ECharts的热门图书词云实现:
jsp复制<%@ page import="com.lib.analysis.ChartBuilder" %>
<%
String jsonData = ChartBuilder.generateBookWordCloud();
%>
<div id="wordcloud" style="width:600px;height:400px;"></div>
<script>
var chart = echarts.init(document.getElementById('wordcloud'));
chart.setOption({
series: [{
type: 'wordCloud',
data: <%= jsonData %>,
sizeRange: [12, 60]
}]
});
</script>
后台数据处理逻辑:
java复制public static String generateBookWordCloud() throws SQLException {
List<Map<String, Object>> data = new ArrayList<>();
String sql = "SELECT title, COUNT(*) as heat FROM reader_behavior "
+ "JOIN book_metadata ON book_id=isbn "
+ "GROUP BY book_id ORDER BY heat DESC LIMIT 100";
try (Connection conn = DataSource.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
Map<String, Object> item = new HashMap<>();
item.put("name", rs.getString("title"));
item.put("value", rs.getInt("heat"));
data.add(item);
}
}
return new Gson().toJson(data);
}
4. 开发环境搭建
4.1 基础环境配置
推荐开发环境组合:
- JDK:1.8.0_202(避免使用高版本,学校生产环境限制)
- IDE:Eclipse JEE 2020-06 + Tomcat插件
- 数据库:MySQL 5.7.32(与生产环境严格一致)
- 构建工具:Maven 3.6.3
常见环境问题解决方案:
- JSP文件修改不生效:清理Tomcat的work目录
bash复制rm -rf /opt/tomcat8/work/Catalina/localhost/ - 中文乱码问题:统一设置编码
xml复制<!-- web.xml中追加 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter>
4.2 项目依赖管理
关键Maven依赖(pom.xml节选):
xml复制<dependencies>
<!-- JSP/Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<!-- 数据库相关 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<!-- 可视化 -->
<dependency>
<groupId>org.apache.echarts</groupId>
<artifactId>echarts</artifactId>
<version>4.8.0</version>
</dependency>
</dependencies>
5. 部署与调试实战
5.1 Tomcat部署要点
-
war包生成:
bash复制mvn clean package -Dmaven.test.skip=true生成的target/*.war文件直接拷贝到Tomcat的webapps目录
-
数据库初始化:
bash复制
mysql -u root -p < src/main/resources/sql/init.sql -
生产环境配置:
properties复制# conf/context.xml <Resource name="jdbc/library" auth="Container" type="javax.sql.DataSource" maxTotal="50" maxIdle="10" username="libadmin" password="加密密码建议使用Jasypt" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://10.0.0.1:3306/library?useSSL=false&characterEncoding=utf8" />
5.2 典型问题排查
问题1:图表加载缓慢
- 现象:页面打开后需要10+秒才能显示图表
- 排查:
- 使用Chrome开发者工具查看Network请求
- 发现/data.json请求耗时过长
- 检查SQL发现未添加索引
- 解决:
sql复制ALTER TABLE reader_behavior ADD INDEX idx_reader (reader_id, action_time);
问题2:内存泄漏
- 现象:Tomcat运行几天后响应变慢
- 排查:
- 使用jmap生成堆转储文件
- MAT分析发现BehaviorLog对象堆积
- 解决:调整日志队列消费策略,增加异常处理
java复制// 修改后的消费者线程 public void run() { while (true) { try { BehaviorLog log = queue.take(); logService.save(log); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } catch (Exception e) { logger.error("保存日志失败", e); } } }
6. 系统优化建议
经过实际运行检验,给出以下优化方向:
-
缓存策略:
- 对热门图书数据使用Redis缓存
- 实现Ehcache二级缓存减少数据库压力
-
异步处理:
- 将日志保存改为Kafka异步写入
- 复杂报表生成改用消息队列触发
-
安全加固:
- 增加SQL注入过滤器
- 敏感数据脱敏处理
java复制public String desensitizeId(String id) { if (id == null || id.length() < 3) return id; return id.substring(0, 3) + "****" + id.substring(id.length() - 2); } -
扩展性改进:
- 抽象数据采集接口,支持多种数据源
- 设计插件机制方便新增分析模型
这个项目让我深刻体会到,在传统技术栈下依然可以构建有价值的数据分析系统。关键在于对业务场景的深入理解和技术方案的合理选型。系统目前稳定运行2年,日均处理10万+行为记录,为图书馆的精准服务提供了有力支撑。
