目录

1.实现导出t_emp表数据到CSV文件

2.实现数据库模糊查询

2.1 概括

2.2 核心类功能 

2.3 具体实现过程

2.4 拓展知识点

2.4.1 设置游标可滚动并回到初始位置

2.4.2 构造函数中传递其他参数,并输出sql语句

3.实现分组查询以及最高值查询

3.1 查询数据库表中信息

3.2 分组查询

3.2 最高值查询

4.实现浏览器查询数据库(做跨域处理)

4.1 在eclipse中实现后端连接数据库并做跨域处理

4.2 网址查询成功

4.3 在HBuilder X中实现前端查询(数据是发送给浏览器)

4.4 html用表格显示数据库表格

4.5 html用饼图显示数据库表格


1.实现导出t_emp表数据到CSV文件

步骤一:数据库准备

-- 创建t_emps表 --
CREATE TABLE t_emps(
	eid INT PRIMARY KEY auto_increment, -- 员工的编号
	ename VARCHAR(20) NOT NULL, -- 员工的姓名
	epwd CHAR(8) NOT NULL, -- 员工的密码
	ebirthday datetime, -- 员工的出生年月,不设计年龄字段,会造成字段冗余
	esalary DOUBLE NOT NULL, -- 员工的工资
	eaddress VARCHAR(100), -- 员工的地址
	estate INT NOT NULL -- 员工的状态
)

-- 删除t_emps表 --
DROP TABLE t_emps

-- 插入数据 --
INSERT INTO t_emps(ename,epwd,ebirthday,esalary,eaddress,estate)
VALUES('张三','11111','2000-05-28',90000.56,'南京',1);

INSERT INTO t_emps(ename,epwd,ebirthday,esalary,eaddress,estate)
VALUES('李四','22222','2004-06-15',88000.69,'盐城',1);

INSERT INTO t_emps(ename,epwd,ebirthday,esalary,eaddress,estate)
VALUES('李老八','22222','1996-12-30',5600,'无锡',1);

INSERT INTO t_emps(ename,epwd,ebirthday,esalary,eaddress,estate)
VALUES('赵二','22222','1996-12-30',5800,'无锡',0);

-- 查询表 --
SELECT * FROM t_emps

实现效果:

步骤二:若是在eclipse新建Maven项目,需要在pom.xml文件中添加依赖,按Ctrl+S保存并加载

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.24</version>
</dependency>

步骤三:创建测试类用于实现导出t_emp表数据到CSV文件

注意:数据库名称,用户名和密码需要修改为自己的

package com.hy.chapter1;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.text.csv.CsvWriter;
import cn.hutool.core.util.CharsetUtil;

public class Test {

	// 声明一个连接对象
	Connection conn;

	public void connDB() {
		try {
			// 1. 加载MySQL JDBC驱动(MySQL 8.0+ 使用 com.mysql.cj.jdbc.Driver)
			Class.forName("com.mysql.cj.jdbc.Driver");

			// 2. 建立数据库连接(URL、用户名、密码)
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql2025", // 数据库地址:本地3306端口的mysql2025库
					"root", // 数据库用户名
					"yourpaaword" // 数据库密码
			);
		} catch (ClassNotFoundException e) {
			e.printStackTrace(); // 驱动类未找到异常(通常是驱动包缺失)
		} catch (SQLException e) {
			e.printStackTrace(); // 数据库连接异常(如URL、用户名、密码错误)
		}
	}

	public void exportCsv(String tableName) {
		// 定义SQL:sql1查总记录数,sql2查所有记录
		String sql1 = "select count(*) from " + tableName; // 查总记录数(用于初始化数组行数)
		String sql2 = "select * from " + tableName; // 查所有记录(含字段值)

		String[][] datas = null;

		try {
			// 步骤1:执行sql1,获取总记录数row
			PreparedStatement pstmt1 = conn.prepareStatement(sql1);
			ResultSet rs1 = pstmt1.executeQuery(); // 执行查询,返回结果集
			int row = 0;
			while (rs1.next()) {
				row = rs1.getInt(1); // 获取count(*)的结果(第一列),即总记录数
			}

			// 步骤2:执行sql2,获取所有记录和字段信息
			PreparedStatement pstmt2 = conn.prepareStatement(sql2);
			ResultSet rs2 = pstmt2.executeQuery(); // 执行查询,返回所有记录

			// Java8 Stream 对数据的一个流式处理
			// 从功耗的角度,我们对数据库动作了2次。
			// 步骤3:获取字段名(表头)
			ResultSetMetaData rsmd = rs2.getMetaData(); // 获取结果集元数据(含字段信息)
			int column = rsmd.getColumnCount(); // 总列数(字段数量)
			String[] heads = new String[column]; // 存储表头(字段名)
			for (int i = 0; i < column; i++) {
				// 获取第i+1列的字段名(元数据列索引从1开始)
				heads[i] = rsmd.getColumnName(i + 1);
				System.out.println(heads[i]); // 打印字段名(调试用)
			}

			// 步骤4:存储所有记录到二维数组datas
			datas = new String[row][column]; // 初始化数组(行数=总记录数,列数=总字段数)
			int count = 0; // 记录当前行数(数组索引)
			while (rs2.next()) { // 遍历每条记录
				for (int i = 0; i < column; i++) {
					// 获取第i+1列的字段值(转为字符串),存入数组
					datas[count][i] = rs2.getString(i + 1);
				}
				count++; // 行数+1,准备存储下一条记录
			}

			// 步骤5:创建CSV写入器(指定文件路径和编码)
			CsvWriter cwriter = CsvUtil.getWriter("d:/emps.csv", CharsetUtil.CHARSET_GBK);

			// 二维数组,数组中的数组,{{},{},{}};

			// 步骤6:写入表头(字段名数组)
			cwriter.writeHeaderLine(heads);

			// 步骤7:写入所有记录(遍历二维数组,逐行写入)
			for (int k = 0; k < datas.length; k++) {
				cwriter.write(datas[k]); // 写入一行数据
			}

		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (conn != null) { // 关闭数据库连接(避免资源泄漏)
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}

	}

	public static void main(String[] args) {
		Test t = new Test();
		t.connDB(); // 建立数据库连接
		t.exportCsv("t_emps"); // 导出t_emps表数据到CSV
	}

}

运行结果:

eid
ename
epwd
ebirthday
esalary
eaddress
estate

步骤四:在设置的文件路径中查看emp.csv文件

注:若ebirthday显示为“###”,适当调整列宽即可显示成功

2.实现数据库模糊查询

2.1 概括

基于 JDBC 实现 MySQL 数据库的查询操作,核心功能是通过模糊查询(like)获取指定表的符合条件数据,并以二维 Object 数组返回结果。

2.2 核心类功能 

  • Connection:数据库连接对象,是所有数据库操作的基础。
  • PreparedStatement:预编译 SQL 执行对象(虽被使用,但未发挥参数化优势,下文会分析)。
  • ResultSet:存储 SQL 查询结果的结果集。
  • ResultSetMetaData:获取结果集的 “元数据”(如列数、列名),用于动态处理结果结构。

2.3 具体实现过程

package com.hy.chapter1;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class Dao {

	Connection conn;

	public Dao() {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql2025",
					"root",
					"yourpassword"
			);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public void closeDB() {
		if (null != conn) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	public Object[][] queryDatas() {
		return null;
	}

	public Object[][] queryDatas(String columnsName, Object params, String tabelName) {

		String sql1 = "select count(*) from " + tabelName + " where " + columnsName + " like '" + params + "%" + "'";

		String sql2 = "select * from " + tabelName + " where " + columnsName + " like '" + params + "%" + "'";

		System.out.println("数据库查询语句sql1:" + sql1);
		System.out.println("数据库查询语句sql2:" + sql2);

		Object[][] datas = null;

		try {
			PreparedStatement pstmt = this.conn.prepareStatement(sql1);
			ResultSet rs1 = pstmt.executeQuery();

			int row = 0;
			while (rs1.next()) {
				row = rs1.getInt(1);
				System.out.println("sql1查询结果count的值:" + row);
			}

			// 把这个查询的句柄对象的游标(结果集),设置为可滚动
//			PreparedStatement pstmt2 = this.conn.prepareStatement(sql2,
//					ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);

			PreparedStatement pstmt2 = this.conn.prepareStatement(sql2);
			ResultSet rs2 = pstmt2.executeQuery();

			int column = 0;
			ResultSetMetaData rsmd = rs2.getMetaData();
			column = rsmd.getColumnCount();
			System.out.println("sql2查询结果数据的列数:" + column);

			datas = new Object[row][column];
			int count = 0;

			// 当遍历完成(rs2.next()返回 false)后,游标停在 “末尾”,此时若想再次读取数据(需重新遍历),
			// 直接调用 rs2.next() 会一直返回 false,必须通过 beforeFirst() 重置游标。
			// 前提:游标已经设置为可滚动
			// rs2.beforeFirst(); // 回到第一行

			while (rs2.next()) {
				for (int i = 0; i < column; i++) {
					datas[count][i] = rs2.getObject(i + 1);
				}
				count++; // 移动到下一行
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			this.closeDB();
		}
		return datas;
	}

	public static void main(String[] args) {
		Dao dao = new Dao();
		Object[][] datas = dao.queryDatas("ename", "李", "t_emps");

		System.out.println("输出sql2数据库查询结果:");
		for (int i = 0; i < datas.length; i++) {
			for (int j = 0; j < datas[i].length; j++) {
				System.out.print(datas[i][j] + ",");
			}
			System.out.println();
		}
	}

}

输出结果:

数据库查询语句sql1:select count(*) from t_emps where ename like '李%'
数据库查询语句sql2:select * from t_emps where ename like '李%'
sql1查询结果count数量:2
sql2查询结果数据的列数:7
输出sql2数据库查询结果:
2,李四,22222,2004-06-15T00:00,88000.69,盐城,1,
3,李老八,22222,1996-12-30T00:00,5600.0,无锡,1,

2.4 拓展知识点

2.4.1 设置游标可滚动并回到初始位置

① 当遍历完成(rs2.next()返回 false)后,游标停在 “末尾”,此时若想再次读取数据(重新遍历),直接调用 rs2.next() 会一直返回 false,必须通过 beforeFirst() 重置游标。

rs2.beforeFirst(); // 回到第一行

② 但前提是:所查询句柄对象的游标已经设置为可滚动

PreparedStatement pstmt2 = this.conn.prepareStatement(sql2,
    ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);

③ 应用:修正因遍历获取“sql2查询结果数据的列数”,导致游标停在“末尾”位置

// 将所查询句柄对象的游标(结果集),设置为可滚动
PreparedStatement pstmt2 = this.conn.prepareStatement(sql2, ResultSet.TYPE_SCROLL_INSENSITIVE,
		ResultSet.CONCUR_READ_ONLY);

ResultSet rs2 = pstmt2.executeQuery();
int column = 0;

// 当遍历完成(rs2.next()返回 false)后,游标停在 “末尾”,此时若想再次读取数据(需重新遍历),
// 直接调用 rs2.next() 会一直返回 false,必须通过 beforeFirst() 重置游标。
// 前提:游标已经设置为可滚动
// 用可滚动游标修正原因:这里不需要遍历结果集,可以直接获取ResultSetMetaData
while (rs2.next()) {
	ResultSetMetaData rsmd = rs2.getMetaData();
	column = rsmd.getColumnCount();
}

System.out.println("sql2查询结果数据的列数:" + column);

2.4.2 构造函数中传递其他参数,并输出sql语句

package com.hy.chapter1;

public class Dao1 {

	// 构造函数传入不同参数,打印查询语句
	public Object[][] queryDatas(String tableName, String column) {

		String sql = "select count(*), " + column + " from " + tableName + " group by " + column;

		System.out.println("数据库查询语句sql:" + sql);

		return null;
	}

	public Object[][] queryDatas(String columnsName, Object[] params, String tabelName) {

		String sql = "select * from " + tabelName + " where " + columnsName + " BETWEEN ";

		for (int i = 0; i < params.length; i++) {
			if (i == params.length - 1) {
				sql += params[i];
			} else {
				sql += params[i] + " and ";
			}
		}
		System.out.println("数据库查询语句sql:" + sql);
		return null;

	}

	public static void main(String[] args) {

		Dao1 dao1 = new Dao1();

		Object[][] data1 = dao1.queryDatas("esalary", new Object[] { 6000, 9000 }, "t_emps");

		Object[][] data2 = dao1.queryDatas("t_emps", "eaddress");
	}

}

输出结果:

数据库查询语句sql:select * from t_emps where esalary BETWEEN 6000 and 9000
数据库查询语句sql:select count(*), eaddress from t_emps group by eaddress

3.实现分组查询以及最高值查询

3.1 查询数据库表中信息

package com.hy.chapter6;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class Dao {

	Connection conn;

	public Dao() {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql2025",
					"root",
					"yourpassword"
			);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public void closeDB() {
		if (null != conn) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	public Object[][] queryDatas(String tableName) {
		Object[][] datas = null;

		try {
			// 第一个SQL:查询表的记录总数(用于初始化二维数组的行数)
			String sql = "select count(*) from " + tableName;
			PreparedStatement pstmt = conn.prepareStatement(sql);
			ResultSet rs = pstmt.executeQuery();
			int count = 0;
			while (rs.next()) {
				count = rs.getInt(1);
			}
			System.out.println("sql1查询结果count的值:" + count);

			// 第二个SQL:查询表中所有记录
			String sql1 = "select * from " + tableName;
			PreparedStatement pstmt1 = conn.prepareStatement(sql1);
			ResultSet rs1 = pstmt1.executeQuery();
			// 获取结果集元数据(用于获取列数)
			ResultSetMetaData rsmd = rs1.getMetaData();
			int columns = rsmd.getColumnCount();
			System.out.println("sql2查询结果数据的列数:" + columns);

			// 初始化二维数组
			datas = new Object[count][columns];
			// 把数据赋值给二维数组
			int row = 0;
			while (rs1.next()) {
				for (int i = 0; i < columns; i++) {
					datas[row][i] = rs1.getObject(i + 1);
				}
				row++;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		return datas;
	}

	public static void main(String[] args) {
		Dao dao1 = new Dao();
		Object[][] data1 = dao1.queryDatas("t_emps");

		for (int i = 0; i < data1.length; i++) {
			for (int j = 0; j < data1[i].length; j++) {
				System.out.print(data1[i][j] + ",");
			}
			System.out.println();
		}
	}

}

输出结果:

sql1查询结果count的值:4
sql2查询结果数据的列数:7
1,张三,11111,2000-05-28T00:00,90000.56,南京,1,
2,李四,22222,2004-06-15T00:00,88000.69,盐城,1,
3,李老八,22222,1996-12-30T00:00,5600.0,无锡,1,
4,赵二,22222,1996-12-30T00:00,5800.0,无锡,0,

3.2 分组查询

对地址(eaddress)进行分组,并统计每组的数量,打印每组数量和对应地址名

package com.hy.chapter6;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class Dao {

	Connection conn;

	public Dao() {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql2025",
					"root",
					"yourpassword"
			);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public void closeDB() {
		if (null != conn) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	public Object[][] queryDatas(String tableName, String column) {
		// 获取名为"column"的列,得到去重后的这一列
		String sql1 = "select DISTINCT " + column + " from t_emps";

		// 对列名为"column"中的值进行分组,并统计每组的数量,命名为cn
		// 查询得到两列,第一列名为cn,第二列名为"column"
		String sql2 = "select count(*) cn, " + column + " from " + tableName + " group by " + column;

		Object[][] datas = null;

		try {
            // 执行sql1得到结果
			PreparedStatement pstmt = this.conn.prepareStatement(sql1);
			ResultSet rs1 = pstmt.executeQuery();
            // 遍历rs1,统计去重后的行数
			int row = 0;
			while (rs1.next()) {
				row++;
			}

            // 执行sql2得到结果
			PreparedStatement pstmt2 = this.conn.prepareStatement(sql2);
			ResultSet rs2 = pstmt2.executeQuery();
            // 获取结果列数
			int columnCount = 0;
			ResultSetMetaData rsmd = rs2.getMetaData();
			columnCount = rsmd.getColumnCount();

            // 初始化二维数组
			datas = new Object[row][columnCount];
			int count = 0;
            // 遍历rs2,将每组统计数据存入数组
			while (rs2.next()) {
				for (int i = 0; i < columnCount; i++) {
					datas[count][i] = rs2.getObject(i + 1);
				}
				count++;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			this.closeDB();
		}
		return datas;
	}

	public static void main(String[] args) {
		// 对地址(eaddress)进行分组,并统计每组的数量,打印每组数量和对应地址名
		Dao dao1 = new Dao();
        // 调用查询方法:按 t_emps 表的 eaddress 列分组统计
		Object[][] data1 = dao1.queryDatas("t_emps", "eaddress");
        // 遍历二维数组,打印统计结果
		for (int i = 0; i < data1.length; i++) {
			for (int j = 0; j < data1[i].length; j++) {
				System.out.print(data1[i][j] + ",");
			}
			System.out.println();
		}
	}

}

输出结果:

1,南京,
1,盐城,
2,无锡,

3.2 最高值查询

获取薪资(esalary)最高的员工,打印其薪资经过处理后的值和员工姓名

package com.hy.chapter6;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class Dao {

	Connection conn;

	public Dao() {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql2025",
					"root",
					"yourpassword"
			);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public void closeDB() {
		if (null != conn) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	public Object[] queryDatas() {
		// 获取薪资(esalary)最高的员工,返回其薪资除以 100 四舍五入后的值和姓名
		String sql = "select round(esalary/100) salary, ename from t_emps "
				+ " where esalary = (select max(esalary) from t_emps)";

		Object[] datas = new Object[2];

		try {
			PreparedStatement pstmt = this.conn.prepareStatement(sql);
			ResultSet rs1 = pstmt.executeQuery();
            // 遍历结果集,将数据存入数组
			while (rs1.next()) {
                // 获取结果集第 1 列的值(对应 round(esalary/100))
				datas[0] = rs1.getObject(1);
                // 获取结果集第 2 列的值(对应 ename)
				datas[1] = rs1.getObject(2);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			this.closeDB();
		}
		return datas;
	}

	public static void main(String[] args) {
		// 获取薪资(esalary)最高的员工,打印其薪资经过处理后的值和员工姓名
		Dao dao2 = new Dao();
        // 调用查询方法,获取最高薪资员工数据
		Object[] data2 = dao2.queryDatas();
        // 打印结果(格式:处理后薪资,员工姓名)
		System.out.println(data2[0] + "," + data2[1]);
	}

}

输出结果:

900.0,张三

4.实现浏览器查询数据库(做跨域处理)

4.1 在eclipse中实现后端连接数据库并做跨域处理

package com.hy.chapter6;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class Dao {

	Connection conn;

	public Dao() {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql2025",
					"root",
					"yourpassword"
			);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public void closeDB() {
		if (null != conn) {
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}

	public Object[][] queryDatas(String tableName) {
		Object[][] datas = null;

		try {
			// 第一个SQL:查询表的记录总数(用于初始化二维数组的行数)
			String sql = "select count(*) from " + tableName;
			PreparedStatement pstmt = conn.prepareStatement(sql);
			ResultSet rs = pstmt.executeQuery();
			int count = 0;
			while (rs.next()) {
				count = rs.getInt(1);
			}
			System.out.println("sql1查询结果count的值:" + count);

			// 第二个SQL:查询表中所有记录
			String sql1 = "select * from " + tableName;
			PreparedStatement pstmt1 = conn.prepareStatement(sql1);
			ResultSet rs1 = pstmt1.executeQuery();
			// 获取结果集元数据(用于获取列数)
			ResultSetMetaData rsmd = rs1.getMetaData();
			int columns = rsmd.getColumnCount();
			System.out.println("sql2查询结果数据的列数:" + columns);

			// 初始化二维数组
			datas = new Object[count][columns];
			// 把数据赋值给二维数组
			int row = 0;
			while (rs1.next()) {
				for (int i = 0; i < columns; i++) {
					datas[row][i] = rs1.getObject(i + 1);
				}
				row++;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		return datas;
	}


	public Object[][] queryDatas(String tableName, String column) {
		// 获取名为"column"的列,得到去重后的这一列
		String sql1 = "select DISTINCT " + column + " from t_emps";

		// 对列名为"column"中的值进行分组,并统计每组的数量,命名为cn
		// 查询得到两列,第一列名为cn,第二列名为"column"
		String sql2 = "select count(*) cn, " + column + " from " + tableName + " group by " + column;

		Object[][] datas = null;

		try {
            // 执行sql1得到结果
			PreparedStatement pstmt = this.conn.prepareStatement(sql1);
			ResultSet rs1 = pstmt.executeQuery();
            // 遍历rs1,统计去重后的行数
			int row = 0;
			while (rs1.next()) {
				row++;
			}

            // 执行sql2得到结果
			PreparedStatement pstmt2 = this.conn.prepareStatement(sql2);
			ResultSet rs2 = pstmt2.executeQuery();
            // 获取结果列数
			int columnCount = 0;
			ResultSetMetaData rsmd = rs2.getMetaData();
			columnCount = rsmd.getColumnCount();

            // 初始化二维数组
			datas = new Object[row][columnCount];
			int count = 0;
            // 遍历rs2,将每组统计数据存入数组
			while (rs2.next()) {
				for (int i = 0; i < columnCount; i++) {
					datas[count][i] = rs2.getObject(i + 1);
				}
				count++;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			this.closeDB();
		}
		return datas;
	}

	public Object[] queryDatas() {
		// 获取薪资(esalary)最高的员工,返回其薪资除以 100 四舍五入后的值和姓名
		String sql = "select round(esalary/100) salary, ename from t_emps "
				+ " where esalary = (select max(esalary) from t_emps)";

		Object[] datas = new Object[2];

		try {
			PreparedStatement pstmt = this.conn.prepareStatement(sql);
			ResultSet rs1 = pstmt.executeQuery();
            // 遍历结果集,将数据存入数组
			while (rs1.next()) {
                // 获取结果集第 1 列的值(对应 round(esalary/100))
				datas[0] = rs1.getObject(1);
                // 获取结果集第 2 列的值(对应 ename)
				datas[1] = rs1.getObject(2);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			this.closeDB();
		}
		return datas;
	}

}
package com.hy.chapter6;

import java.nio.charset.Charset;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import cn.hutool.http.ContentType;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.server.SimpleServer;

public class Server {

	public void SendTabDatas(SimpleServer server) {
		server.addAction("/querytabdatas", (request, response) -> {

			System.out.println("querytabdatas  is  start...........");

			// 设置字符集不乱码
			response.setCharset(Charset.forName("UTF-8"));

			// 设置可以跨域,让不同IP和端口的请求可以访问
			response.setHeader("Access-Control-Allow-Origin", "*");

			Dao dao1 = new Dao();
			Object[][] datas = dao1.queryDatas("t_emps");

			JSONArray arrays = new JSONArray();

			for (int i = 0; i < datas.length; i++) {
				JSONObject obj = new JSONObject();
				obj.put("eid", datas[i][0]);
				obj.put("ename", datas[i][1]);
				obj.put("epwd", datas[i][2]);
				obj.put("ebirthday", datas[i][3].toString().substring(0, 10));
				obj.put("esalary", datas[i][4]);
				obj.put("eaddress", datas[i][5]);

				if (datas[i][6].toString().equals("1")) {
					obj.put("estate", "在职");
				} else {
					obj.put("estate", "离职");
				}

				arrays.add(obj);

			}

			response.write(arrays.toString(), ContentType.JSON.toString());

		});
	}

	public void SendGroupAddressDatas(SimpleServer server) {
		server.addAction("/querygroupaddressdatas", (request, response) -> {

			System.out.println("querygroupaddressdatas  is  start...........");

			// 设置字符集不乱码
			response.setCharset(Charset.forName("UTF-8"));

			// 设置可以跨域,让不同IP和端口的请求可以访问
			response.setHeader("Access-Control-Allow-Origin", "*");

			Dao dao1 = new Dao();
			Object[][] datas = dao1.queryDatas("t_emps", "eaddress");

			JSONArray arrays = new JSONArray();

			for (int i = 0; i < datas.length; i++) {
				JSONObject obj = new JSONObject();
				obj.put("value", Integer.parseInt(datas[i][0].toString()));
				obj.put("name", datas[i][1].toString());

				arrays.add(obj);

			}

			response.write(arrays.toString(), ContentType.JSON.toString());

		});
	}

	public void sendSalaryDatas(SimpleServer server) {
		server.addAction("/querysalarydatas", (request, response) -> {

			System.out.println("querysalarydatas  is  start...........");

			// 设置字符集不乱码
			response.setCharset(Charset.forName("UTF-8"));

			// 设置可以跨域,让不同IP和端口的请求可以访问
			response.setHeader("Access-Control-Allow-Origin", "*");

			Dao dao1 = new Dao();
			Object[] datas = dao1.queryDatas();

			String result = JSONArray.toJSONString(datas);

			response.write(result, ContentType.JSON.toString());

		});
	}

	public Server() {
		SimpleServer server = HttpUtil.createServer(8891);

		this.SendTabDatas(server);

		this.SendGroupAddressDatas(server);

		this.sendSalaryDatas(server);

		server.start();
	}

	public static void main(String[] args) {

		Server s = new Server();
	}

}

输出结果:

Hutool Simple Http Server listen on 【0:0:0:0:0:0:0:0:8891】
querytabdatas  is  start...........
sql1查询结果count的值:4
sql2查询结果数据的列数:7
querygroupaddressdatas  is  start...........
querysalarydatas  is  start...........

4.2 网址查询成功

4.3 在HBuilder X中实现前端查询(数据是发送给浏览器)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>

	</body>
	<script type="text/javascript">
		function queryTabData() {
			//1.创建原生ajax请求对象
			let ajaxObj = new XMLHttpRequest();

			//2.设置请求方法和链接
			ajaxObj.open("get", "http://127.0.0.1:8891/querytabdatas");

			//3.发送请求
			ajaxObj.send();

			//4.回调,得到服务器传送的数据
			ajaxObj.onreadystatechange = () => {

				if (ajaxObj.readyState == 4 && ajaxObj.status == 200) {
					let result = ajaxObj.responseText;
					console.log('服务器端传回的数据为:' + result);
				}
			}
		}

		queryTabData();
	</script>
</html>

输出结果:

网址查询:

拓展:

readyState总共有5个状态值,分别为0~4,每个值代表了不同的含义

  • 0:初始化,XMLHttpRequest对象还没有完成初始化
  • 1:载入,XMLHttpRequest对象开始发送请求
  • 2:载入完成,XMLHttpRequest对象的请求发送完成
  • 3:解析,XMLHttpRequest对象开始读取服务器的响应
  • 4:完成,XMLHttpRequest对象读取服务器响应结束

所以说readyState == 4表示已经完成了ajax请求

4.4 html用表格显示数据库表格

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<style type="text/css">
			table {
				width: 100%;
				height: 20vh;
			}

			td {
				text-align: center;
				font-weight: bold;
			}

			tr:hover {
				background-color: azure;
			}
		</style>
	</head>
	<body>

	</body>
	<script type="text/javascript">
		function queryTabData() {

			//1.创建原生ajax请求对象
			let ajaxObj = new XMLHttpRequest();

			//2.设置请求方法和链接
			ajaxObj.open("get", "http://127.0.0.1:8891/querytabdatas");

			//3.发送请求
			ajaxObj.send();

			//4.回调,得到服务器传送的数据
			ajaxObj.onreadystatechange = () => {

				if (ajaxObj.readyState == 4 && ajaxObj.status == 200) {
					let result = ajaxObj.responseText;
					console.log('服务器端传回的数据为:' + result);
					console.log(typeof result);

					//eval函数把这个文本转换成js对象:json的字符串对象
					let re1 = eval(result)

					if (re1 != undefined) {
						let objdatas = JSON.parse(JSON.stringify(re1));
						console.log(objdatas);
						console.log(typeof objdatas);
						createTabel(objdatas);
					}
				}

			}
		}

		function createTabel(objdatas) {

			//获取body对象
			let bodyObj = document.body

			//创建表格对象标签	 
			let tabObj = document.createElement("table");

			//设置表格边框
			tabObj.border = 1;

			let trObj1 = document.createElement("tr");

			//加载key  es6语法
			Object.keys(objdatas[0]).forEach(function(key) {

				console.log("->" + key);
				if (key == 'eid') {
					key = "员工编号"
				}
				if (key == 'ename') {
					key = "员工姓名"
				}
				if (key == 'eaddress') {
					key = "员工地址"
				}
				if (key == 'esalary') {
					key = "员工工资"
				}
				if (key == 'epwd') {
					key = "员工密码"
				}
				if (key == 'estate') {
					key = "员工状态"
				}
				if (key == 'ebirthday') {
					key = "员工出生年月"
				}

				let thObj0 = document.createElement("th");
				thObj0.innerText = key;
				trObj1.appendChild(thObj0);

			});
			//添加到表格中
			tabObj.appendChild(trObj1);


			//加载数据
			for (let i = 0; i < objdatas.length; i++) {
				//创建行
				let trObj = document.createElement("tr");

				//创建td
				let tdObj0 = document.createElement("td");
				let tdObj1 = document.createElement("td");
				let tdObj2 = document.createElement("td");
				let tdObj3 = document.createElement("td");
				let tdObj4 = document.createElement("td");
				let tdObj5 = document.createElement("td");
				let tdObj6 = document.createElement("td");

				tdObj0.innerText = objdatas[i].eid;
				tdObj1.innerText = objdatas[i].eaddress;
				tdObj2.innerText = objdatas[i].ename;
				tdObj3.innerText = objdatas[i].esalary;
				tdObj4.innerText = objdatas[i].epwd;
				tdObj5.innerText = objdatas[i].estate;
				tdObj6.innerText = objdatas[i].ebirthday;

				trObj.appendChild(tdObj0);
				trObj.appendChild(tdObj1);
				trObj.appendChild(tdObj2);
				trObj.appendChild(tdObj3);
				trObj.appendChild(tdObj4);
				trObj.appendChild(tdObj5);
				trObj.appendChild(tdObj6);

				//添加到表格中
				tabObj.appendChild(trObj);
			}

			//表格添加到body标签中
			bodyObj.appendChild(tabObj);
		}
		queryTabData();
	</script>
</html>

运行结果:

显示效果:

网址查询:

4.5 html用饼图显示数据库表格

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			#main {
				width: 90vh;
				height: 60vh;
			}
		</style>
		<script src="https://cdn.jsdelivr.net/npm/echarts@6.0.0/dist/echarts.min.js"></script>
	</head>
	<body>
		<div id="main"></div>
	</body>
	<script type="text/javascript">
		function loadView() {
			// 1. 创建AJAX核心对象:XMLHttpRequest是浏览器原生API,负责发起HTTP请求、接收服务器响应
			let ajaxObj = new XMLHttpRequest();

			// 2. 配置AJAX请求参数:open(请求方法, 请求地址)
			// - 请求方法:"get"(适合查询类操作,参数会拼在URL后,此处无额外参数)
			// - 请求地址:http://127.0.0.1:8891/querygroupaddressdatas(本地服务器接口,需确保服务器已启动且接口存在)
			ajaxObj.open("get", "http://127.0.0.1:8891/querygroupaddressdatas");

			// 3. 发送AJAX请求:向配置的服务器地址发起请求,触发数据获取流程
			ajaxObj.send();

			// 4. 监听AJAX请求状态变化:当请求状态(readyState)或响应状态(status)变化时触发回调
			ajaxObj.onreadystatechange = () => {

				// - readyState=4:服务器已返回所有数据,请求流程完全结束
				// - status=200:HTTP响应状态码为200,表示请求成功
				if (ajaxObj.readyState == 4 && ajaxObj.status == 200) {
					// 获取服务器返回的原始数据:responseText是字符串格式(服务器通常返回JSON格式的字符串)
					let result = ajaxObj.responseText;
					// 控制台打印原始数据和数据类型,用于开发调试(查看数据是否符合预期)
					console.log('服务器端传回的数据为:' + result);
					console.log(typeof result); // 此时输出"string",因为原始响应是文本

					// 将字符串格式的数据转为JavaScript对象:使用eval函数
					let re1 = eval(result)

					// 数据校验:若解析后的数据不为空,进行深拷贝并调用饼图渲染函数
					if (re1 != undefined) {
						// 深拷贝数据:通过JSON.stringify转为字符串再JSON.parse转回对象,避免原数据被后续操作污染
						let objdatas = JSON.parse(JSON.stringify(re1));
						// 打印深拷贝后的数据,确认数据格式
						console.log(objdatas);
						console.log(typeof objdatas); // 此时输出"object"(数组属于object类型)
						// 调用饼图渲染函数,传入处理后的有效数据
						loadPieView(objdatas)
					}
				}

			}

		}


		function loadPieView(objdatas) {
			// 1. 初始化ECharts实例:绑定到id为"main"的DOM容器(即图表挂载载体)
			let echartObj = echarts.init(document.getElementById("main"));

			// 2. 配置ECharts图表选项:option是ECharts的核心配置,定义图表类型、数据、样式等
			let option = {
				series: [{
					type: 'pie',
					data: objdatas // 饼图数据:传入服务器返回的统计数据,决定扇区的名称和大小
				}]
			};

			// 3. 应用图表配置:将option中的配置渲染到ECharts实例,生成最终的可视化饼图
			echartObj.setOption(option);
		}

		loadView();
	</script>
</html>

运行结果:

显示效果:

更多推荐