数据分析-可视化
2023-02-07 本文已影响0人
CoderInsight
1.使用简单的 html+Servlet+DBUtils 实现可视化
jsp+Servlet可视化结果(主站最受欢迎的TopN课程).png(0).项目准备
1).新建 "maven-archetype-webapp" 的Maven项目
2).添加 pom.xml 依赖
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
3),项目依赖 “echarts.min.js” 和 jquery.js
(1).Domain(实体类)
package top.wangyq.domain;
/**
* TopN 实体类
*/
public class VideoAccessTopN {
// 这里定义的字段属性值要和图中表示数据的部分是一致的
// 属性名
private String name;
// 属性值
private long value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getValue() {
return value;
}
public void setValue(long value) {
this.value = value;
}
}
(2).DBUtils(数据库连接工具类)
package top.wangyq.utiles;
import java.sql.*;
/**
* 操作MySQL的工具类
*/
public class DBUtils {
private static final String USERNAME = "root";
private static final String PASSWORD = "111111";
private static final String DRIVERCLASS = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/imooclog";
/**
* 获取数据库的连接
* @return
*/
public static Connection getConnnection(){
Connection connection = null;
try {
// 获得字符串参数中指定的类,并初始化该类;将Driver类获取出来
Class.forName(DRIVERCLASS);
connection = DriverManager.getConnection(URL,USERNAME,PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
/**
* 释放数据库的连接资源
*/
public static void release(Connection connection, PreparedStatement pstmt, ResultSet rs){
if (rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (pstmt != null){
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (pstmt != null){
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 测试数据库连接是否获取成功
*/
public static void main(String[] args) {
System.out.println(getConnnection());
}
}
(3).Dao层(底层操作数据库)
package top.wangyq.dao;
import top.wangyq.domain.VideoAccessTopN;
import top.wangyq.utiles.DBUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 完整的讲是应该采用面向接口的方式进行编程
* 但是,我们这里直接是面向实现类进行编程的
*/
public class VideoAccessTopNDao {
// 课程和编号的映射一般是直接写在关系型数据库中,然后使用一个接口去调用
// 将课程编号与课程名称封装在map集合中
static Map<String,String> courses = new HashMap<>();
// 这里是在map集合中进行赋值,直接写死的,但是如果从数据中取值无非是将取出来的值遍历依次添加到Map中
static {
courses.put("2402", "机器学习");
courses.put("1309", "redis");
courses.put("3078", "神经网络");
courses.put("1336", "Docker");
courses.put("3369", "Java");
}
/**
* 定义查询课程编号与课程名称的对应关系的方法
*/
public String getCourseName(String courseId){
// 直接使用get方法将map中的元素进行获取即可
return courses.get(courseId);
}
/**
* 根据day查询当天最受欢迎的Top5课程
* 查询的结果保存在list集合中,那么在前端将数据获取出来的时候需要遍历list集合
*/
public List<VideoAccessTopN> query(String day){
List<VideoAccessTopN> list = new ArrayList<>();
// 设置数据库的连接信息
Connection connection = null; // 连接对象
PreparedStatement pstmt = null; // 预编译对象
ResultSet rs = null; // 结果对象
try {
// 初始化连接对象
connection = DBUtils.getConnnection();
// 编写sql语句的字符串
// 这里将条件都直接写死了,是不对的,应该将其写使用传递的方式实现(待测试更改:使用开头,再加$)
String sql = "select cms_id, times from day_video_access_topn_stat3 where day=? order by times desc limit 5";
// 初始化预编译对象
pstmt = connection.prepareStatement(sql);
// 给占位符进行赋值
pstmt.setString(1,day);
// 执行查询结果返回给ResultSet对象
rs = pstmt.executeQuery();
// 定义 VideoAccessTopN 实体类对象
VideoAccessTopN domain = null;
// 依次判断集合中是否有元素
while (rs.next()){
// 有则初始化对象
domain = new VideoAccessTopN();
/**
在页面中应该显示的是课程名称,而我们在数据库中存储的是课程编号,需要再转换
*
* 如何根据课程编号去获取课程名称呢?
* 编号和名称是有一个对应关系的,一般情况下可以将其对应关系写在关系型数据库中
* 但是此时我们直接写在了程序的开头的静态代码块
*/
// 1.由于数据库的课程编号的类型是Long类型的,所以需要通过getLong("字段名")来将字段中的值取出来
// 2.然后调用课程编号与客户才能名称的映射方法(getCourseName)
domain.setName(getCourseName(rs.getLong("cms_id")+""));
domain.setValue(rs.getLong("times"));
// 将保存好数据的domain对象封装在list集合中
list.add(domain);
}
}catch (Exception e){
e.printStackTrace();
}finally {
// 关闭资源
DBUtils.release(connection, pstmt, rs);
}
// 操作结束后将结果集合返回
return list;
}
public static void main(String[] args) {
VideoAccessTopNDao dao = new VideoAccessTopNDao();
List<VideoAccessTopN> list = dao.query("20191110");
for (VideoAccessTopN res : list) {
System.out.println(res.getName() + "\t" + res.getValue());
}
}
}
(4).Servlet(前端请求处理层)
将从数据库中查询出来的数据转成json类型的数据,再将结果传递到前端
package top.wangyq.servlet;
import top.wangyq.dao.VideoAccessTopNDao;
import top.wangyq.domain.VideoAccessTopN;
import net.sf.json.JSONArray;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
/**
* 最受欢迎的TopN课程
*
* 一般完成的项目时有三层的
* Web ==> Service ==> Dao
* 我们此时只有查询,并没有数据的添加等操作,所以我们只有两层
* Web ==> Dao
*/
public class VideoAccessTopNServlet extends HttpServlet {
// 定义操作数据库的实体类
private VideoAccessTopNDao dao;
@Override
public void init() throws ServletException {
// 初始化操作数据库的类
dao = new VideoAccessTopNDao();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 定义变量将前端请求中拼接的字符串的值获取出来
String day = req.getParameter("day");
// 将获取的月份传入数据库操作类中的query方法,其函数的返回值是一个 VideoAccessTopN(实体类)的集合
List<VideoAccessTopN> results = dao.query(day);
// 定义一个JSONArray对象,将list集合转换成json对象
JSONArray json = JSONArray.fromObject(results);
// 设置response的响应类型为html
resp.setContentType("text/html;charset=utf-8");
// 获取一个写对象,返回值是PrintWriter
PrintWriter writer = resp.getWriter();
// 将json数据响应给前端页面
writer.println(json);
// 刷新提交
writer.flush();
// 关闭写对象
writer.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req,resp);
}
}
(5).将servlet注册到web.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>Archetype Created Web Application</display-name>
<!-- 在写完servlet之后需要在web.xml中进行注册-->
<servlet>
<servlet-name>stat</servlet-name>
<servlet-class>top.wangyq.servlet.VideoAccessTopNServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>stat</servlet-name>
<url-pattern>/stat</url-pattern>
</servlet-mapping>
</web-app>
(6).topn.html(前端页面)
主要是编写对应js代码,使用Ajax技术将后端获取的数据进行拼接
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Echarts Demo </title>
<!-- 引入 ECharts 文件 -->
<script src="js/echarts.min.js"></script>
<script src="js/jquery.js"></script>
</head>
<body>
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<!-- 编写Echarts的脚本代码-->
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title : {
text: '主站最受欢迎的TopN课程',
x:'center'
},
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
orient: 'vertical',
left: 'left',
data: [] // 这里是设置图例的名称
},
series : [
{
name: '访问次数',
type: 'pie',
radius : '55%',
center: ['50%', '60%'],
data:(function(){
var courses = [];
$.ajax({
type:"GET", // 默认是get方式,也可指定为post方式,此时后端处理请求的时候是使用的get方式,所以在这里写就是get方式
url:"stat?day=20191110", // 这里是Servlet请求,请求的结果传递到回调函数中
dataType:'json', // 指定数据的响应类型是json
async:false, // 设置是否是异步提交数据为false(也就是同步提交)
// 在响应状态为success的时候执行回调函数
success:function(result) {
for(var i=0;i<result.length; i++){
// 将数据封装到数组对象中
courses.push({"name":result[i].name, "value": result[i].value});
}
}
})
// 最后将塞了数据的数组对象进行返回
return courses;
})(),
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>