原生ajax+ECharts
主要架构思想
- 在项目中,ajax主要实现一部分的数据更新,实现更新的话则需要使用到servlet,如果有多个ajax需要查不同的表,那么会需要多个servlet,实现起来会比较多冗。所以我们需要定义一个接口,来减少servlet与数据库的交互。
项目示例
-
我们有一个项目,需要使用到ECharts实现简单的各类图表的展示,我们实现起来主要的难点就在于:不同图表所需要的数据格式,比如柱状图和折线图等,需要两组数据,对应横坐标的参数和主要数据;但是饼状图不同它需要的则是类似于Json类数据的格式,所以不同的表类型不同导致所需要的数据也不相同。
-
接下来我们实现连接数据库的接口:
public interface SqlTableDao { /* * 我们这里只实现一个查询的功能,所以只有一个findall方法 * */ public <T> String findall(Class<T> tclass); }
面对请求的多样化,我们可以创建不同的接口实现类来接受查询不同的数据,但是在之前我们需要创建一个pojo类来进行封装:
比如我们创建了一个bardata表来封装创建柱状图需要的对象
public class Bardata { private int data;//对应实际数据 private String x_name;//对应x轴坐标 public Bardata(int data, String x_name) { this.data = data; this.x_name = x_name; } public Bardata() { } public int getData() { return data; } public void setData(int data) { this.data = data; } public String getX_name() { return x_name; } public void setX_name(String x_name) { this.x_name = x_name; } @Override public String toString() { return "Bardata{" + "data=" + data + ", x_name='" + x_name + '\'' + '}'; } }
那么封装类有了,我们就需要去实现接口。
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.sql.*; import java.util.ArrayList; /** * @author Sleep * @Create 2022/11/12 10:40 */ public class BarDao implements SqlTableDao{ @Override public <T> String findall(Class<T> tclass) { //获取数据库连接 try { Connection connection = DriverManager.getConnection("your url","your username","your password"); //通过反射获取对象的构造方法 Constructor<T> constructor = tclass.getConstructor(Integer.class, String.class); //查询数据库 String sql = "****"; //预处理 PreparedStatement prep = connection.prepareStatement(sql); //覆盖占位符的覆盖 /*只查询有效数据 *prst.setDouble(1, sal); *prst.setInt(2, empno); * */ //执行查询语句 ResultSet set = prep.executeQuery(); //创建容器封装 ArrayList<T> list = new ArrayList<>(); //遍历set集合 while (set.next()){ //获取其中的参数 int data = set.getInt("data"); String x_name = set.getString("x_data"); //利用之前的反射获取的构造方法,获得对象 T t = (T) constructor.newInstance(data,x_name); //添加进入集合 list.add(t); } //利用Gson工具类返回已经封装好的json字符串 return GsonUtils.getJson(list); } catch (SQLException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } }
我们就可以传入pojo类的class对象来实现查询柱状图需要的数据,我们创建一个servlet,来获取请求。
public class Barservlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /* * 设置请求和响应的编码格式,以及响应写入数据的格式 * 这一部分也可以使用Filter过滤器来写 * */ req.setCharacterEncoding("UTF-8"); resp.setCharacterEncoding("UTF-8"); //由于前后端的交互使用的是json数据格式的传输,所以我们使用起来也需要来规定格式 resp.setContentType("json/application;charset=utf-8"); //我们可以根据url来获取到额外的字段,得到想要请求的具体数据,可以是数据库中的表名 String database = req.getParameter("database"); //获取传输返回值 String json = ""; //对字段名进行判断,对应不同的pojo类的class对象,并调用方法接受 if (database.equals("bar")){ //我们调用服务层的ChartSqlFind类中的getchartdata来实现service层与dao层的分离 json = ChartSqlFind.getchartdata(new BarDao(),Bardata.class); }/*else if (database.equals("pie")){ .... }else { //else这一部分都是防止意外情况,比如传输的数据出错 ... }*/ //使用响应写回数据 resp.getWriter().print(json); } }
除此之外我们还需要去web.xml中去注册Servlet
<servlet> <servlet-name>Barservlet</servlet-name> <servlet-class>cn.sleep.servlets.Barservlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Barservlet</servlet-name> <url-pattern>/barchart</url-pattern> </servlet-mapping>
在上述代码中我们为了实现Dao层与Service层的分离,定义了一个服务类,来间接调用Dao层方法:
public class ChartSqlFind {
/* 我们定义一个静态方法,调用SqlTableDao的实现方法
* 这样可以将Dao层的功能分离出来
* */
public static <T> String getchartdata(SqlTableDao sql, Class<T> tClass){
return sql.findall(tClass);
}
}
那么接下来要做的事情就是需要为jsp写入数据和处理数据:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<!--一般写jsp页面时我们需要创建一个文件夹来存放静态文件,比如css、js、img等-->
<script src="static/js/echarts.js"></script>
</head>
<body>
<button onclick="ons()">显示图形</button>
<!--创建一个容纳图片的容器-->
<div id="main" style="width: 1000px;height:800px;"></div>
<script type="text/javascript">
function ons(){
//1、我们首先要创建 XMLHttpRequest
var xmlhttprequest = new XMLHttpRequest();
//2、调用 open 方法设置请求参数
xmlhttprequest.open("POST","/WebMod_war/barchart",true);
/*
* 关于open的参数,
* 第一个参数为请求的方式:GET、POST
* 第二个参数为:跳转的路径,一般来说是 项目配置路径+注册的servlet的url
* open方法一共有5个参数
* 其余参数为可选的
* */
//3、在 send 方法前绑定 onreadystatechange 事件,处理请求完成后的操作。
xmlhttprequest.onreadystatechange = function() {
//4、判断请求状态码来判断是否执行
if (xmlhttprequest.readyState == 4 && xmlhttprequest.status == 200){
//5、获取后端response返回的Json数据,并使用内置的JSON模块格式化
var Json = JSON.parse(xmlhttprequest.responseText);
//6、创建数组遍历接受数据
/*
* 不同的图表的对应的数据处理也不同,
* 比如bar柱状图需要两组数据,分别对应横坐标和具体的数据,
* 或者pie饼状图则需要一组json数据来直接使用
* */
var data = [];
var x_name = [];
//7、遍历Json数组
for(var o in Json){
//push函数尾部添加
data.push(Json[o].data);
x_name.push(Json[o].x_name);
}
}
}
xmlhttprequest.send();
//8、遍历完数组,调用图表显示函数
//需要设置一个请求完的执行函数
xmlhttprequest.onloadend = function (){
showChart(data,x_name);
}
}
//获取函数参数
function showChart(data,x_name){
//1、获取图表容器,封装为对象
var myChart = echarts.init(document.getElementById('main'));
//2、指定图表的配置项和数据
//在使用ECharts渲染date时,需要3-4s,我们需要提升用户感知
myChart.showLoading({text:'正在加载数据'})
var option = {
xAxis: {
type: 'category',
//传入特定的参数,通过参数传入
data: data
},
yAxis: {
type: 'value'
},
series: [
{
//传入特定的参数,通过参数传入
data: x_name,
type: 'bar',
showBackground: true,
backgroundStyle: {
color: 'rgba(180, 180, 180, 0.2)'
}
}
]
};
//
myChart.hideLoading();//将提示关闭
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
</script>
</body>
</html>
上述代码是bar柱状图,pie的饼状图需要使用的数据格式也不一样:
在ECharts官方文档里,饼状图数据需要的是json类型的格式的,所以我们可以直接传入
function ons(){
//由于Json的数据处理函数需要在函数体内部,所以我们需要定义变量来接收
var datamod=[];
// 1 、我们首先要创建 XMLHttpRequest
var xmlhttprequest = new XMLHttpRequest();
// 2 、调用 open 方法设置请求参数
xmlhttprequest.open("POST","/WebMod_war/ajex",true);
// 3 、在 send 方法前绑定 onreadystatechange 事件,处理请求完成后的操作。
xmlhttprequest.onreadystatechange = function() {
if (xmlhttprequest.readyState == 4 && xmlhttprequest.status == 200) {
var jsonObj = JSON.parse(xmlhttprequest.responseText);
datamod=jsonObj;
}
}
xmlhttprequest.send();
//需要设置一个请求完的执行函数
xmlhttprequest.onloadend = function (){
ens(datamod)
}
}
// 基于准备好的dom,初始化echarts实例
function ens(datamod){
var myChart = echarts.init(document.getElementById('main'));
myChart.showLoading();
//alert(typeof(datas));
// 指定图表的配置项和数据
var option = {
legend: {
top: 'bottom'
},
toolbox: {
show: true,
feature: {
mark: { show: true },
dataView: { show: true, readOnly: false },
restore: { show: true },
saveAsImage: { show: true }
}
},
series: [
{
name: 'Nightingale Chart',
type: 'pie',
radius: [50, 250],
center: ['50%', '50%'],
roseType: 'area',
itemStyle: {
borderRadius: 20
},
data:datamod
}
]
};
myChart.hideLoading();
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
更多的图表数据可以查看官方的文档Examples - Apache ECharts