8.1 构建javaweb系统查询用户行为
8.1.2 搭建并部署javaweb项目
tomcat的安装与配置
进入网址:https://tomcat.apache.org/download-90.cgi,选择图示版本
解压至windows本地文件夹即可
idea构建javaweb项目
在Idea中打开书中配套代码
点编辑配置
点配置,选择自己的文件夹
添加部署

添加完成将下述路径改成/newsWeb
将web.xml文件改成如下内容:

启动tomcat
pom.xml文件的json-lib库改成:
xml
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
启动之后:
访问网址如下:
http://localhost:8080/newsWeb/TestServlet
如图
8.1.3 用户行为查询代码开发
修改配置文件
修改my.properties
修改web.xml文件
8.2 用户行为数据展示与分析
javaweb项目配置与打包
把my.properties改成:
properites
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.datasource.size=5
jdbc.url=jdbc:mysql://192.168.255.139:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
jdbc.user=hive
jdbc.password=hive
JDBCHelper.java改成:
java
//第一步:加载驱动
/*static{
try {
ConfigurationManager.getProperty(Constants.JDBC_DRIVER);
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
static {
try {
// 直接用配置文件里的值,适配 8.x
Class.forName(ConfigurationManager.getProperty(Constants.JDBC_DRIVER));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
web.xml改成:
xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>newsWeb</display-name>
<servlet>
<servlet-name>NewsSvlt</servlet-name>
<servlet-class>com.djt.servlet.NewsSvlt</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>NewsSvlt</servlet-name>
<url-pattern>/news</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>jsp/news.jsp</welcome-file>
</welcome-file-list>
</web-app>
在webapp下新建目录jsp,在此下新建文件news.jsp
jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>新闻大屏展示</title>
<!-- 引入 ECharts 和 jQuery -->
<script src="<%=path%>/js/echarts.min.js"></script>
<script src="<%=path%>/js/jquery-3.2.1.js"></script>
</head>
<body>
<div id="loading" style="text-align:center;padding:50px;font-size:18px;color:#666;">
正在加载新闻数据...
</div>
<div id="content" style="display:none;">
<div id="main" style="width:700px;height:420px;float:left;"></div>
<div id="sum" style="width:730px;height:420px;float:left;"></div>
<div id="period" style="width:1430px;height:250px;float:left;"></div>
</div></body>
<script type="text/javascript">
var myChart, myChart_sum, myChart_period;
function initCharts() {
myChart = echarts.init(document.getElementById('main'));
myChart_sum = echarts.init(document.getElementById('sum'));
myChart_period = echarts.init(document.getElementById('period'));
}
$(document).ready(function(){
// 初始化图表
initCharts();
// 加载数据
initNewsNum();
// 每10秒刷新一次(减少频率避免过多请求)
setInterval(function() {
initNewsNum();
}, 10000);
});
function initNewsNum(){
var action = "<%=path%>/news"; // 调用后端 Servlet
$.ajax({
url: action,
type: 'GET',
dataType: 'json',
timeout: 10000,
success: function(data) {
console.log('接收到数据:', data);
if (data.error) {
console.error('服务器返回错误:', data.error);
return;
}
// 隐藏加载提示,显示内容
$('#loading').hide();
$('#content').show();
newsRank(data);
newsSum(data.newssum);
periodRank(data);
},
error: function(xhr, status, error) {
console.error('AJAX请求失败:', status, error);
console.error('响应内容:', xhr.responseText);
// 隐藏加载提示,显示错误信息
$('#loading').html('<div style="color:red;font-size:16px;">数据加载失败,请检查数据库连接<br/>错误信息: ' + error + '</div>');
// 可选:显示空的图表
$('#content').show();
var emptyData = {
name: [],
newscount: [],
logtime: [],
periodcount: [],
newssum: 0
};
newsRank(emptyData);
newsSum(emptyData.newssum);
periodRank(emptyData);
}
});
}
// 新闻浏览量排行
function newsRank(json){
var option = {
backgroundColor: '#ffffff',
title: {
text: '新闻话题浏览量【实时】排行',
subtext: '数据来自搜狗',
textStyle: { fontWeight: 'normal', color: '#408829' }
},
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: { data: ['浏览量'] },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: { type: 'value', boundaryGap: [0, 0.01] },
yAxis: { type: 'category', data: json.name },
series: [{
name: '浏览量',
type: 'bar',
label: { normal: { show: true, position: 'insideRight' } },
itemStyle:{ normal:{color:'#f47209'} },
data: json.newscount
}]
};
myChart.setOption(option);
}
// 新闻话题曝光总量
function newsSum(data){
var option = {
backgroundColor: '#fbfbfb',
title: { text: '新闻话题曝光量【实时】统计', subtext: '数据来自搜狗' },
tooltip: { formatter: "{a} <br/>{b} : {c}%" },
toolbox: { feature: { restore: {}, saveAsImage: {} } },
series: [{
name: '业务指标',
type: 'gauge',
max: 50000,
detail: { formatter:'{value}个话题' },
data: [{value: 0, name: '话题曝光量'}]
}]
};
option.series[0].data[0].value = data;
myChart_sum.setOption(option, true);
}
// 时段新闻浏览量排行
function periodRank(json){
var option = {
backgroundColor: '#ffffff',
color: ['#00FFFF'],
tooltip : { trigger: 'axis', axisPointer : { type : 'shadow' } },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis : [{ type : 'category', data : json.logtime, axisTick: { alignWithLabel: true } }],
yAxis : [{ type : 'value' }],
series : [{
name:'新闻话题曝光量',
type:'bar',
barWidth: '60%',
data: json.periodcount
}]
};
myChart_period.setOption(option, true);
}
</script>
</body>
</html>

把打包好的拷贝到tomcat的webapps目录下:
启动数据库
确认hadoop01的数据库启动,并在tomcat里把表清空
启动
来到tomcat的bin目录下,双击start.bat
访问 http://localhost:8080/newsWeb/
此时没数据所以显示空白
8.2.2 项目整体联调
启动 MySQL 服务
因为 Flink 处理结果要落到 MySQL 的 newscount
和 periodcount
表里,所以必须先启动数据库。
-
在
hadoop01
节点执行:bashservice mysql start
或
bashsystemctl start mysqld
-
验证:
bashmysql -uroot -p mysql> show databases;
确保有 test
数据库,以及表 newscount
、periodcount
已创建。
启动 Zookeeper 服务
Kafka 依赖 Zookeeper 协调。
-
在
hadoop01/hadoop02/hadoop03
各节点执行:bashcd /home/hadoop/app/zookeeper/bin ./zkServer.sh start
-
验证:
bash./zkServer.sh status
确保有一个是
leader
,其他是follower
。
启动 Kafka 集群
Flink DataStream 会消费 Kafka 的日志流。
-
在各节点执行:
bashcd /home/hadoop/app/kafka/bin ./kafka-server-start.sh -daemon ../config/server.properties
-
验证:
bashjps | grep Kafka
启动 Flink 实时应用
书里用的例子是 KafkaFlinkMySQL
,把 Kafka 数据实时处理后写入 MySQL。
- 在 IDEA 里找到
KafkaFlinkMySQL.java
- 右键 →
Run 'KafkaFlinkMySQL.main()'
- Flink 应用会本地运行,消费 Kafka 日志,计算新闻浏览量 → 写入 MySQL。

启动 Flume 聚合节点
Flume 负责把采集到的日志推送到 Kafka。
-
在
hadoop02
、hadoop03
上执行:bashcd /home/hadoop/app/flume bin/flume-ng agent -n a2 -c conf -f conf/xxx.conf -Dflume.root.logger=INFO,console &
启动 Flume 采集节点
-
在
hadoop01
上执行:bashcd /home/hadoop/app/flume bin/flume-ng agent -n a1 -c conf -f conf/xxx.conf -Dflume.root.logger=INFO,console &
这一步会把日志源源不断地推送到聚合节点,再写到 Kafka。
模拟产生数据
-
在
hadoop01
上执行:bashcd /home/hadoop/shell/bin ./sogoulogs.sh

查看 MySQL 结果

最终效果
-
Flume → Kafka → Flink → MySQL → Java Web 大屏
-
打开大屏地址:
http://localhost:8080/newsWeb/
页面会通过
NewsSvlt
查询 MySQL → 返回 JSON → ECharts 实时展示统计结果。
访问http://localhost:8080/newsWeb/
