学生提交材料清单
1.Spark 项目运行结果截图
2.Hive数据库查询截图
3.接口测试截图
4.数据可视化网页截图
5.分别导出Spark项目,前后端项目的Zip(压缩包)
注意:
1.所有截图请统一粘贴到一个 Word 文件中,命名为:
提交截图_姓名_班级.docx;2.最终考生提交内容打包为一个总压缩包,命名格式如下:
张三-大数据高23-1班-大数据实训.rar
一、Hive 环境启动
【题目要求】
启动 Hadoop 分布式文件系统(HDFS)与 YARN;
启动 Hive Metastore 与 HiveServer2 服务。
# 启动 Hadoop 文件系统
start-dfs.sh
start-yarn.sh
# 启动 Hive 服务
hive --service metastore &
hive --service hiveserver2 &
二、Hive 数据库与数据导入
【题目要求】
创建数据库
salesdb;创建表
salesinfo,包含字段 sale_date;从本地路径
/opt/exam_spark/sales_data.csv加载数据;确认数据中有多个年份存在。
DROP DATABASE IF EXISTS salesdb CASCADE;
CREATE DATABASE IF NOT EXISTS salesdb;
USE salesdb;
CREATE TABLE IF NOT EXISTS salesinfo (
order_id STRING,
customer_id STRING,
product_id STRING,
sale_date DATE,
quantity INT,
unit_price INT,
payment_method STRING,
region STRING,
product_name STRING,
category STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE
TBLPROPERTIES ("skip.header.line.count"="1");
LOAD DATA LOCAL INPATH '/opt/exam_spark/sales_data.csv' INTO TABLE salesinfo;
SELECT DISTINCT year(sale_date) AS sale_year FROM salesinfo;
三、Spark SQL 年度销售对比分析
【题目要求】
创建
Spark项目SparkTask,并导入Pom.xml文件;创建 Scala 类
YearSalesAnalysis,路径为:src/main/scala/org/example/YearSalesAnalysis.scala使用 Spark SQL 分析 Hive 表
salesinfo:从 Hive 表
salesinfo中提取sale_date中的年份;统计北京每年的订单总数、销售总额;
按年份升序排序;
保存结果到 Hive 表
year_sales_result;
【参考代码】
package org.example
import org.apache.spark.sql.SparkSession
object YearSalesAnalysis {
def main(args: Array[String]): Unit = {
// 设置 Hadoop 用户(避免权限问题)
System.setProperty("HADOOP_USER_NAME", "root")
// 1. 初始化 SparkSession,开启 Hive 支持
val spark = SparkSession.builder()
.appName("YearSalesStat")
.master("local[*]")
.enableHiveSupport()
.getOrCreate()
println("1.SparkSession 初始化成功,Hive 支持开启")
// 2. 使用 salesdb 数据库
spark.sql("USE salesdb")
// 3. 统计每年销售总额与订单数量
println("2.正在统计北京地区各年份的订单数量与销售总额...")
val result = spark.sql(
"""
|SELECT
| year(sale_date) AS sale_year,
| COUNT(*) AS order_count,
| ROUND(SUM(quantity * unit_price)/10000, 2) AS total_sales
|FROM salesinfo
|WHERE sale_date IS NOT NULL and region='北京'
|GROUP BY year(sale_date)
|ORDER BY sale_year ASC
|""".stripMargin)
// 4. 展示结果
val count = result.count()
println(s"3.查询完成,共获得 $count 条年度销售记录:")
result.show(truncate = false)
// 5. 保存结果为 Hive 表
println("4.正在将结果写入 Hive 表:salesdb.year_sales_result...")
result.write
.mode("overwrite")
.saveAsTable("salesdb.year_sales_result")
println("5.结果已成功写入 Hive 表:salesdb.year_sales_result")
// 6. 关闭 Spark
spark.stop()
println("6.程序结束,SparkSession 已关闭。")
}
}
四、Spring Boot 接口开发 + Vue 可视化
4.1 后端接口开发
【题目要求】
创建
Spring Boot项目 ,名称为Backend,并导入Pom.xml文件;创建类
YearController,路径为:src/main/java/com/example/backend/controller/YearController.java使用 Spring Boot 创建接口
/year-sales,请求方式为GET;在接口中通过 JDBC 查询 Hive 表
year_sales_result;查询字段包括:
sale_year,order_count,total_sales;将查询结果以 JSON 列表形式返回,每条记录包含上述字段键值对。
【参考代码】
package com.example.backend.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.sql.*;
import java.util.*;
@RestController // 标注为一个 REST 控制器,返回 JSON 数据
public class YearController {
@GetMapping("/year-sales") // 映射 GET 请求路径为 /year-sales
public List<Map<String, Object>> getYearSales() {
// 用于存放查询结果的列表,每个 Map 表示一条记录
List<Map<String, Object>> result = new ArrayList<>();
try {
// 加载 Hive JDBC 驱动类
Class.forName("org.apache.hive.jdbc.HiveDriver");
// 通过 JDBC 连接到 HiveServer2(地址、库名、用户名、密码)
Connection conn = DriverManager.getConnection(
"jdbc:hive2://master:10000/salesdb", "root", "123456");
// 创建 SQL 执行对象
Statement stmt = conn.createStatement();
// 执行 Hive 查询:按年汇总的订单数量和销售总额
ResultSet rs = stmt.executeQuery(
"SELECT sale_year, order_count, total_sales FROM year_sales_result");
// 遍历结果集,每行数据封装为一个 Map,添加到结果列表
while (rs.next()) {
Map<String, Object> map = new HashMap<>();
map.put("sale_year", rs.getInt("sale_year")); // 年份(如 2021)
map.put("order_count", rs.getInt("order_count")); // 对应年份的订单数量
map.put("total_sales", rs.getDouble("total_sales")); // 对应年份的销售总额
result.add(map); // 加入结果列表
}
// 关闭资源:结果集、语句、连接
rs.close();
stmt.close();
conn.close();
} catch (Exception e) {
// 捕获并打印异常信息(如连接失败、SQL 错误)
e.printStackTrace();
}
// 返回包含年份销售统计数据的列表,自动转换为 JSON
return result;
}
}
4.2 Vue + ECharts 可视化
【题目要求】
创建
VUE项目 ,名称为Frontend;创建组件文件
components/YearChart.vue和主页面App.vue,配置代理文件vite.config.js;使用 Vue3 + ECharts 创建折线图组件,并启用面积图效果;
从接口
/api/year-sales获取数据;显示北京各年份的销售额变化趋势(单位:万元),并通过折线图动态展示。
【参考代码】
vite.config.js
// 引入 Vite 的配置函数和 Vue 插件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 默认导出配置对象
export default defineConfig({
// 注册插件:使用 Vue 插件支持 .vue 文件
plugins: [vue()],
// 本地开发服务器配置
server: {
port: 5173, // 本地开发服务器端口(默认也是 5173,可自定义)
// 配置代理:解决前端开发中跨域请求后端的问题
proxy: {
'/api': {
target: 'http://localhost:8080', // 后端服务器地址(Spring Boot 或其他服务)
changeOrigin: true, // 修改请求头中的 origin 字段,避免跨域
rewrite: path => path.replace(/^\/api/, '')
// 将请求路径中的 `/api` 前缀去掉,例如:
// 前端请求:/api/region-sales → 实际转发为:http://localhost:8080/region-sales
}
}
}
})
App.vue
<!-- 页面结构区域 -->
<template>
<div class="chart-wrapper">
<h1>数据可视化</h1>
<h2>大数据高23-1班 张三</h2>
<!-- 引入的图表组件,用于展示区域销售数据 -->
<YearChart />
</div>
</template>
<!-- 脚本逻辑区域 -->
<script setup>
// 引入封装好的区域图表组件
import YearChart from './components/YearChart.vue'
</script>
<!-- 页面样式区域 -->
<style>
/* 设置整个页面的背景色和默认字体样式 */
body {
background-color: #f0f2f5; /* 浅灰背景色 */
margin: 0;
padding: 20px;
font-family: "Microsoft YaHei", sans-serif;
}
/* 图表容器样式:限制最大宽度、居中显示 */
.chart-wrapper {
max-width: 1400px;
margin: 40px auto; /* 上下间距 40px,左右居中 */
font-family: sans-serif;
}
</style>
YearChart.vue
<template>
<!-- 图表容器,通过 ref 引用,用于挂载 ECharts -->
<div class="chart-container" ref="chartRef"></div>
</template>
<script setup>
import { ref, onMounted } from 'vue' // Vue 的响应式变量 + 生命周期钩子
import * as echarts from 'echarts' // 引入 ECharts 主库
import axios from 'axios' // 引入 Axios 用于发送请求
// 1.定义响应式变量,用于绑定图表 DOM 节点
const chartRef = ref()
// 2.渲染图表函数:请求数据并绘制图表
const renderChart = async () => {
// 向后端发送请求,获取每年销售数据(格式:[{sale_year:2020, total_sales:123.45}, ...])
const res = await axios.get('/api/year-sales')
const data = res.data
// 拆分出图表的 X 轴(年份) 和 Y 轴(销售额)
const xData = data.map(item => item.sale_year) // 年份数组
const yData = data.map(item => item.total_sales.toFixed(2)) // 销售额数组,保留两位小数
// 初始化 ECharts 图表实例,挂载到 DOM 元素 chartRef 上
const chart = echarts.init(chartRef.value)
// 配置图表选项(option)
chart.setOption({
title: {
text: '北京各年份销售额趋势图', // 主标题
subtext: '单位:万元', // 副标题
left: 'center' // 居中显示
},
tooltip: {
trigger: 'axis', // 提示框触发条件:鼠标悬浮在坐标轴上
formatter: params => {
const d = params[0]
return `${d.name} 年<br/>销售额:${d.value} 万元` // 自定义提示框内容
}
},
grid: {
top: 80,
bottom: 60,
left: 80,
right: 30
},
xAxis: {
type: 'category', // 类目轴(x 轴显示文字)
data: xData, // 年份数组
boundaryGap: false, // 图线贴边
axisLabel: { fontSize: 14 } // 字体大小
},
yAxis: {
type: 'value', // 数值轴
name: '销售额(万元)', // y 轴名称
axisLabel: {
formatter: '{value} 万', // 格式化 y 轴单位
fontSize: 14
}
},
series: [
{
name: '销售额',
type: 'line', // 折线图
data: yData, // 销售额数据
smooth: true, // 平滑曲线
areaStyle: {opacity: 0.3}, // 填充面积颜色 → 成为“面积图”,并设置透明度 30%
symbol: 'circle', // 折线图上的点形状
lineStyle: {
width: 3,
color: '#2b6cb0' // 折线颜色
},
itemStyle: {
color: '#2b6cb0' // 数据点颜色
},
label: {
show: true, // 显示数据值
position: 'top' // 值显示在点上方
}
}
]
})
}
// 3.页面加载完成后自动执行渲染图表
onMounted(() => renderChart())
</script>
<style scoped>
.chart-container {
width: 100%;
height: 400px;
min-width: 700px;
margin: 10px auto;
background: #fff;
border-radius: 12px;
padding: 20px;
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08); /* 阴影效果 */
}
</style>
