使用easyui前端框架快速构建一个crud应用

本篇文章将会详细介绍jquery easyui前端框架的使用,通过创建一个crud应用来带大家快速掌握easyui的使用。

easyui是博主最喜欢的前端框架,没有之一,因为它提供了多种主题,而且有圆润的各种组件。

目录

一、快速开始

二、准备工作

三、开始使用

主题资源

常用组件

datagrid

textbox

passwordbox

dialog

四、表格渲染

后端代码

添加跨域配置

添加controller接口

前端代码

method属性

loadFilter属性

fitColumns属性

striped属性

pagination属性

height属性

五、构建应用

完成分页功能

后端代码

前端代码

增删查改功能

条件查询功能

前端代码

后端代码

FilterRule

Pager

StringToListOfFilterRuleConverter

Pager

SongServiceImpl


一、快速开始

easyui的官网地址:

JQuery EasyUI中文网https://www.jeasyui.net/点击上方链接访问easyui中文官网,下载easyui。

在下载页面点击下载对应的版本,本篇文章将使用jquery easyui

选择下载免费版

二、准备工作

下载完成后,得到一个压缩包jquery-easyui-1.7.0.zip。

然后把这个压缩包解压出来,我们需要的是红框内的几个文件及文件夹。

  • locale目录下是常用的一些js文件
  • themes目录下是easyui的样式文件

通过HBuilderx创建一个基本的html项目

接着,把themes文件夹复制到项目的css目录下,把locale/easyui-lang-zh_CN.js和红框内的两个js文件复制到项目的js目录下。

三、开始使用

完成前面两步之后,就可以开始愉快地使用easyui了。

主题资源

如图,themes下面提供了多种主题样式的资源文件,喜欢哪个主题,引入对应包下的easyui.css即可。

常用组件

datagrid

easyui里用的最多的莫过于数据表格了,datagrid是easyui的表格组件,支持分页功能。只需要在表格渲染的js代码中添加选项pagenation: true即可开启分页功能。

打开easyui的文档页面,找到通过javascript渲染表格的案例代码。

官网提供的渲染easyui datagrid的javascript代码为,url是加载表格数据的地址,columns是表格的列信息。#dg表示的是表格元素的选择器,这是id选择器,表示id为dg的DOM对象。

javascript 复制代码
    $('#dg').datagrid({
        url:'datagrid_data.json',
        columns:[[
    		{field:'code',title:'Code',width:100},
    		{field:'name',title:'Name',width:100},
    		{field:'price',title:'Price',width:100,align:'right'}
        ]]
    });

textbox

文本框,就是带了easyui样式的input输入框,与之对应的还有passwordbox。

passwordbox

密码框,带了easyui样式的input密码框<input type="password"></input>

dialog

对话框,通常会在对话框内嵌表单,实现数据的添加和修改功能。

四、表格渲染

为了方便快速学会datagird的使用,这里就直接拿之前写的springboot crud案例项目作为后端项目,演示datagird通过ajax异步加载表格数据。

项目git地址如下:

https://gitee.com/he-yunlin/springboot-crud/tree/springboot-crud1.0/https://gitee.com/he-yunlin/springboot-crud/tree/springboot-crud1.0/

后端代码

添加跨域配置

首先要添加跨域配置,防止使用过程中出现cors问题。

java 复制代码
package com.example.springboot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * springmvc配置类
 * @author heyunlin
 * @version 1.0
 */
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {

    /**
     * 解决跨域问题
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("*")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(5000);
    }

}

添加controller接口

然后在SongController中添加一个接口方法

java 复制代码
    @RequestMapping(value = "/selectList", method = RequestMethod.GET)
    public JsonResult<List<Song>> selectList() {
        List<Song> list = songService.selectList();

        return JsonResult.success("查询成功", list);
    }

对应地,在SongService接口添加selectList()方法

java 复制代码
List<Song> selectList();

SongServiceImpl

java 复制代码
    @Override
    public List<Song> selectList() {
        return songMapper.selectList(null);
    }

前端代码

在前端的easyui项目下创建html目录,在html目录下创建index.html。

修改表格的数据加载地址url为selectList接口的访问地址http://localhost:8083/song/selectList

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>datagrid案例代码</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/material/easyui.css" />
		<script src="../js/jquery.min.js"></script>
		<script src="../js/jquery.easyui.min.js"></script>
		<script src="../js/easyui-lang-zh_CN.js"></script>
	</head>
	
	<body>
		<div id="song_list"></div>
		
		<script>
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectList",
					columns: [[
						{field: 'code', title:'Code', width:100},
						{field: 'name', title:'Name', width:100},
						{field: 'price', title:'Price', width:100, align:'right'}
					]]
				});
			});
		</script>
	</body>
</html>

然后选择通过firefox运行,打开看到一个空白页面

F12打开浏览器控制台,刷新页面,发现请求接口发生了异常,不支持post请求。

这是因为easyui的datagrid默认是通过ajax post请求加载数据.

打开之前的文档页面,往下滚动,找到数据网格属性。

如图,method属性就是设置请求的类型,而这个属性的默认值是post,我们把它设置成get

method属性

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>datagrid案例代码</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/material/easyui.css" />
		<script src="../js/jquery.min.js"></script>
		<script src="../js/jquery.easyui.min.js"></script>
		<script src="../js/easyui-lang-zh_CN.js"></script>
	</head>
	
	<body>
		<div id="song_list"></div>
		
		<script>
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectList",
					method: "get",
					columns: [[
						{field: 'code', title:'Code', width:100},
						{field: 'name', title:'Name', width:100},
						{field: 'price', title:'Price', width:100, align:'right'}
					]]
				});
			});
		</script>
	</body>
</html>

页面代码修改完成之后,发现只显示了表头,表格数据没有显示出来,而且报了一个错,rows is undefined。

为什么会这样呢,其实问题就在于后端返回的数据不是一个list,而是封装的一个JsonResult对象,list放到这个对象的data里了。所以,这里要对返回的数据进行简单的处理,得到data里的list。

loadFilter属性

就是它了,loadFilter属性是一个方法,用于请求url过滤返回的数据。

注意:我们在后端封装一个JsonResult对象返回是为了能够带上一个请求的状态码code,当这个状态码为200时,表示请求被正确地执行了。

因此,这个过滤方法应该是下面这样:

javascript 复制代码
loadFilter: function(res) {
    if (res.code == 200) {
        return res.data;
    } else {
        return null;
    }
},

最后,正确的页面代码如下:

javascript 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>datagrid案例代码</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/material/easyui.css" />
		<script src="../js/jquery.min.js"></script>
		<script src="../js/jquery.easyui.min.js"></script>
		<script src="../js/easyui-lang-zh_CN.js"></script>
	</head>
	
	<body>
		<div id="song_list"></div>
		
		<script>
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectList",
					method: "get",
					loadFilter: function(res) {
						if (res.code == 200) {
							return res.data;
						} else {
							return null;
						}
					},
					columns: [[
						{field: 'id', title: 'id', width: 200},
						{field: 'name', title: 'name', width: 200},
						{field: 'singer', title: 'singer', width: 200},
						{field: 'note', title: 'note', width: 200},
						{field: 'lastUpdateTime', title: 'lastUpdateTime', width: 200},
					]]
				});
			});
		</script>
	</body>
</html>

而此时,页面的数据终于显示出来了,一共800多条数据。

fitColumns属性

上面的页面看起来非常丑,如果表格能占满整个页面会更好看一点,因此,easyui也实现了这种效果,只需要设置fitColumns属性的值为true即可,表格的列宽会自适应当前页面。

于是,在原来的代码基础上添加fitColumns属性,并设置为true

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>datagrid案例代码</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/material/easyui.css" />
		<script src="../js/jquery.min.js"></script>
		<script src="../js/jquery.easyui.min.js"></script>
		<script src="../js/easyui-lang-zh_CN.js"></script>
	</head>
	
	<body>
		<div id="song_list"></div>
		
		<script>
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectList",
					method: "get",
					fitColumns: true,
					loadFilter: function(res) {
						if (res.code == 200) {
							return res.data;
						} else {
							return null;
						}
					},
					columns: [[
						{field: 'id', title: 'id', width: 200},
						{field: 'name', title: 'name', width: 200},
						{field: 'singer', title: 'singer', width: 200},
						{field: 'note', title: 'note', width: 200},
						{field: 'lastUpdateTime', title: 'lastUpdateTime', width: 200},
					]]
				});
			});
		</script>
	</body>
</html>

修改页面代码后的效果,比原来看起来舒服的多。

striped属性

页面看起来差不多了,但是总感觉表格也太单调了,全是一种颜色,看起来总感觉怪怪的,能不能再美化一下呢。

答案是:当然可以,上面的页面很单调,是表格全部数据都是一个颜色,如果能给表格的行记录颜色不一样,那就完美了。

于是,striped属性腾空出世,这个属性的作用就是显示条纹,不出所料,这个属性默认值也是false。

把它设置成true看一下效果。

javascript 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>datagrid案例代码</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/material/easyui.css" />
		<script src="../js/jquery.min.js"></script>
		<script src="../js/jquery.easyui.min.js"></script>
		<script src="../js/easyui-lang-zh_CN.js"></script>
	</head>
	
	<body>
		<div id="song_list"></div>
		
		<script>
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectList",
					method: "get",
					striped: true,
					fitColumns: true,
					loadFilter: function(res) {
						if (res.code == 200) {
							return res.data;
						} else {
							return null;
						}
					},
					columns: [[
						{field: 'id', title: 'id', width: 200},
						{field: 'name', title: 'name', width: 200},
						{field: 'singer', title: 'singer', width: 200},
						{field: 'note', title: 'note', width: 200},
						{field: 'lastUpdateTime', title: 'lastUpdateTime', width: 200},
					]]
				});
			});
		</script>
	</body>
</html>

修改页面之后,视觉效果还不错,有了一点bootstrap的感觉了~

pagination属性

上面的表格外观已经很完美了,作为一个后端开发人员来说,这样的样式已经无可挑剔,但是,之前已经说过了,一共有800多条数据,这还算少的了,假如有几万条数据呢?如果一次性全部查询出来,每次查询的时候,后端服务的压力是很大的。

所以,一般数据量大的时候都会分页查询,每次只查询一部分数据。

easyui的datagrid支持分页功能,只需要设置pagination属性为true,而常用的分页属性还有另外两个pageSize和pageList。

修改前端页面代码,添加pagination属性为true。

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>datagrid案例代码</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/material/easyui.css" />
		<script src="../js/jquery.min.js"></script>
		<script src="../js/jquery.easyui.min.js"></script>
		<script src="../js/easyui-lang-zh_CN.js"></script>
	</head>
	
	<body>
		<div id="song_list"></div>
		
		<script>
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectList",
					method: "get",
					striped: true,
					fitColumns: true,
					pagination: true,
					loadFilter: function(res) {
						if (res.code == 200) {
							return res.data;
						} else {
							return null;
						}
					},
					columns: [[
						{field: 'id', title: 'id', width: 200},
						{field: 'name', title: 'name', width: 200},
						{field: 'singer', title: 'singer', width: 200},
						{field: 'note', title: 'note', width: 200},
						{field: 'lastUpdateTime', title: 'lastUpdateTime', width: 200},
					]]
				});
			});
		</script>
	</body>
</html>

此时,页面好像没有什么区别,好像也没有分页

其实,页面已经变了,只是在当前页面可浏览范围之外,页面滚动到末尾,会发现表格底部多了一个分页栏。

并且,请求携带了额外的参数page和rows

height属性

基于上面的的问题(需要拉到页面底部才能看到分页栏),现在给表格设置一个固定的高度,让它刚好够显示10条数据。通过不断调整,发现高度400比较适合。

javascript 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>datagrid案例代码</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/material/easyui.css" />
		<script src="../js/jquery.min.js"></script>
		<script src="../js/jquery.easyui.min.js"></script>
		<script src="../js/easyui-lang-zh_CN.js"></script>
	</head>
	
	<body>
		<div id="song_list"></div>
		
		<script>
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectList",
					method: "get",
					height: 400,
					striped: true,
					fitColumns: true,
					pagination: true,
					loadFilter: function(res) {
						if (res.code == 200) {
							return res.data;
						} else {
							return null;
						}
					},
					columns: [[
						{field: 'id', title: 'id', width: 200},
						{field: 'name', title: 'name', width: 200},
						{field: 'singer', title: 'singer', width: 200},
						{field: 'note', title: 'note', width: 200},
						{field: 'lastUpdateTime', title: 'lastUpdateTime', width: 200},
					]]
				});
			});
		</script>
	</body>
</html>

再次查看页面效果

五、构建应用

完成分页功能

上个章节,已经完成了基本的页面样式的调整,但是能发现,其实并没有分页,这是因为后端没有处理easyui框架传的两个参数page和rows。

这个部分首先需要解决的就是这个问题,要使用mybatis-plus的分页功能,需要添加分页插件。

后端代码

新增mp配置类,添加mybatis-plus分页插件。

java 复制代码
package com.example.springboot.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * MP配置类
 */
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = "com.example.springboot.mapper")
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 防全表更新与删除插件
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        // 分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        return interceptor;
    }

}

前端代码

我们把请求数据的接口改一下,改成selectByPage。

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>datagrid案例代码</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/material/easyui.css" />
		<script src="../js/jquery.min.js"></script>
		<script src="../js/jquery.easyui.min.js"></script>
		<script src="../js/easyui-lang-zh_CN.js"></script>
	</head>
	
	<body>
		<div id="song_list"></div>
		
		<script>
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectByPage",
					method: "get",
					height: 400,
					striped: true,
					fitColumns: true,
					pagination: true,
					loadFilter: function(res) {
						if (res.code == 200) {
							return res.data;
						} else {
							return null;
						}
					},
					columns: [[
						{field: 'id', title: 'id', width: 200},
						{field: 'name', title: 'name', width: 200},
						{field: 'singer', title: 'singer', width: 200},
						{field: 'note', title: 'note', width: 200},
						{field: 'lastUpdateTime', title: 'lastUpdateTime', width: 200},
					]]
				});
			});
		</script>
	</body>
</html>

页面效果

至此,分页功能完成~

增删查改功能

接下来完成数据的增删改功能。

给表格添加头部工具栏,新增添加、修改、删除三个按钮。

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>datagrid案例代码</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/material/easyui.css" />
		<script src="../js/jquery.min.js"></script>
		<script src="../js/jquery.easyui.min.js"></script>
		<script src="../js/easyui-lang-zh_CN.js"></script>
	</head>
	
	<body>
		<div id="song_list"></div>
		
		<div id="song_dialog" style="display: none;">
			<form id="song_form">
				<input type="hidden" id="id" name="id" />
				
				<table>
					<tr>
						<td>name:</td>
						<td><input id="name" name="name" /></td>
						
						<td>singer:</td>
						<td><input id="singer" name="singer" /></td>
					</tr>
					
					<tr>
						<td>note:</td>
						<td colspan="3"><input id="note" name="note" /></td>
					</tr>
				</table>
			</form>
		</div>
		
		<script>
			let requestUrl;
			let base = "http://localhost:8083";
			
			$(document).ready(function() {
				$('#name').textbox({
					width: 150,
					required: true
				});
				
				$('#singer').textbox({
					width: 150,
					required: true
				});
				
				$('#note').textbox({
					width: 366,
					height: 100,
					required: true,
					multiline: true
				});
				
				$('#song_dialog').dialog({
				    title: '歌曲信息',
				    closed: true,
				    cache: false,
				    modal: true,
					toolbar:[{
						text: '保存',
						iconCls: 'icon-save',
						handler: function() {
							let bool = $("#song_form").form("validate");
							
							if (!bool) {
								$.messager.alert("系统提示", "请填写正确的表单项", "warning");
							} else {
								let data = $("#song_form").serialize();
								
								$.post(base + requestUrl, data, function(res) {
									$.messager.show({
										title: '系统消息',
										timeout: 5000,
										showType: 'slide',
										msg: res.message,
									});
									
									$('#song_dialog').dialog('close');
									$("#song_list").datagrid("reload");
								}, "json");
							}
						}
					}, {
						text: '取消',
						iconCls: 'icon-cancel',
						handler: function() {
							$("#song_form").form('clear');
							$('#song_dialog').dialog('close');
						}
					}]
				});
									
				$("#song_list").datagrid({
					url: base + "/song/selectByPage",
					method: "get",
					height: 432,
					striped: true,
					filterBtnIconCls: "icon-filter",
					fitColumns: true,
					pagination: true,
					loadFilter: function(res) {
						if (res.code == 200) {
							return res.data;
						} else {
							return null;
						}
					},
					toolbar: [{
						iconCls: 'icon-add',
						text: '添加',
						handler: function() {
							requestUrl = "/song/insert";
							
							$('#song_dialog').dialog('open');
						}
					}, '-', {
						iconCls: 'icon-edit',
						text: '修改',
						handler: function() {
							let row = $("#song_list").datagrid('getSelected');
							
							if(row) {
								requestUrl = "/song/updateById";
								
								$('#id').val(row.id);
								$('#name').textbox('setValue', row.name);
								$('#singer').textbox('setValue', row.singer);
								$('#note').textbox('setValue', row.note);
								
								$('#song_dialog').dialog('open');
							} else {
								$.messager.alert("系统提示", "请选择要修改的数据!", "warning");
							}
						}
					}, '-', {
						iconCls: 'icon-delete',
						text: '删除',
						handler: function() {
							let rowData = $("#song_list").datagrid("getSelected");
							
							if (rowData) {
								$.messager.confirm("提示", "删除后数据无法恢复,是否确认删除?", function(bool) {
									if (bool) {
										$.get(base + "/song/deleteById/" + rowData.id, {}, function(res) {
											$.messager.show({
												title: '系统消息',
												timeout: 5000,
												showType: 'slide',
												msg: res.message,
											});
						
											$("#song_list").datagrid("reload");
										}, "json");
									}
								});
							} else {
								$.messager.alert("请选择要删除的数据!", "warning");
							}
						}
					}],
					columns: [[
						{field: 'id', title: 'id', width: 200},
						{field: 'name', title: 'name', width: 200},
						{field: 'singer', title: 'singer', width: 200},
						{field: 'note', title: 'note', width: 200},
						{field: 'lastUpdateTime', title: 'lastUpdateTime', width: 200},
					]]
				});
			});
		</script>
	</body>
</html>

条件查询功能

最后,要实现表格数据的条件查询功能,在这里通过表格过滤来实现这个功能,需要引入额外的easyui插件。

更多详情可参考以下链接:

EasyUI 数据网格行过滤(DataGrid Filter Row)https://www.jeasyui.net/extension/192.html访问以上地址,页面拉到底部,把这个压缩包下载下来,我们需要它里面的datagrid-filter.js文件。

前端代码

博主下载下来之后,花了点时间看了一下datagrid-filter.js的源代码,发现一个关键的属性remoteFilter,意思是远程过滤,而通过页面的说明,发现这个属性的默认值为false。

根据我使用easyui的经验猜测,如果设置成true,应该会在加载表格数据的时候额外发送请求参数。于是照着葫芦画瓢,给歌曲列表开启行过滤,并设置remoteFilter属性值为true。

javascript 复制代码
let requestUrl;
let base = "http://localhost:8083";
let pageList = [20, 50, 100, 500, 1000];

$(document).ready(function() {
	$('#name').textbox({
		width: 150,
		required: true
	});
	
	$('#singer').textbox({
		width: 150,
		required: true
	});
	
	$('#note').textbox({
		width: 366,
		height: 100,
		required: true,
		multiline: true
	});
	
	$('#song_dialog').dialog({
		title: '歌曲信息',
		closed: true,
		cache: false,
		modal: true,
		toolbar:[{
			text: '保存',
			iconCls: 'icon-save',
			handler: function() {
				let bool = $("#song_form").form("validate");
				
				if (!bool) {
					$.messager.alert("系统提示", "请填写正确的表单项", "warning");
				} else {
					let data = $("#song_form").serialize();
					
					$.post(base + requestUrl, data, function(res) {
						$.messager.show({
							title: '系统消息',
							timeout: 5000,
							showType: 'slide',
							msg: res.message,
						});
						
						$('#song_dialog').dialog('close');
						$("#song_list").datagrid("reload");
					}, "json");
				}
			}
		}, {
			text: '取消',
			iconCls: 'icon-cancel',
			handler: function() {
				$("#song_form").form('clear');
				$('#song_dialog').dialog('close');
			}
		}]
	});
						
	let datagrid = $("#song_list").datagrid({
		url: base + "/song/selectByPage",
		title: "歌曲列表",
		height: 810,
		striped: true,
		fitColumns: true,
		pagination: true,
		remoteFilter: true,
		clientPaging: false,
		pageSize: pageList[0],
		pageList: pageList,
		loadFilter: function(res) {
			if (res.code == 200) {
				return res.data;
			} else {
				return null;
			}
		},
		toolbar: [{
			iconCls: 'icon-add',
			text: '添加',
			handler: function() {
				requestUrl = "/song/insert";
				
				$('#song_dialog').dialog('open');
			}
		}, '-', {
			iconCls: 'icon-edit',
			text: '修改',
			handler: function() {
				let row = $("#song_list").datagrid('getSelected');
				
				if(row) {
					requestUrl = "/song/updateById";
					
					$('#id').val(row.id);
					$('#name').textbox('setValue', row.name);
					$('#singer').textbox('setValue', row.singer);
					$('#note').textbox('setValue', row.note);
					
					$('#song_dialog').dialog('open');
				} else {
					$.messager.alert("系统提示", "请选择要修改的数据!", "warning");
				}
			}
		}, '-', {
			iconCls: 'icon-delete',
			text: '删除',
			handler: function() {
				let rowData = $("#song_list").datagrid("getSelected");
				
				if (rowData) {
					$.messager.confirm("提示", "删除后数据无法恢复,是否确认删除?", function(bool) {
						if (bool) {
							$.get(base + "/song/deleteById/" + rowData.id, {}, function(res) {
								$.messager.show({
									title: '系统消息',
									timeout: 5000,
									showType: 'slide',
									msg: res.message,
								});
			
								$("#song_list").datagrid("reload");
							}, "json");
						}
					});
				} else {
					$.messager.alert("请选择要删除的数据!", "warning");
				}
			}
		}],
		columns: [[
			{field: 'id', title: 'id', width: 200},
			{field: 'name', title: 'name', width: 200},
			{field: 'singer', title: 'singer', width: 200},
			{field: 'note', title: 'note', width: 200},
			{field: 'lastUpdateTime', title: 'lastUpdateTime', width: 200},
		]]
	});
	
	datagrid.datagrid('enableFilter', [{
		field: 'name',
		type: 'textbox',
		op: ['equal', 'contains']
	}, {
		field: 'singer',
		type: 'textbox',
		op: ['equal', 'contains'],
	}, {
		field: 'note',
		type: 'textbox',
		op: ['equal', 'contains']
	}]);

});

果然,刷新页面,发现发送的请求中多了一个filterRules参数。

后端代码

FilterRule

于是在后端创建与之对应的java实体类FilterRule

java 复制代码
package com.example.springboot.base;

import com.example.springboot.enums.Operator;
import lombok.Data;

/**
 * 过滤规则
 * @author heyunlin
 * @version 1.0
 */
@Data
public class FilterRule {

    /**
     * 字段名
     */
    private String field;

    /**
     * 比较符
     */
    private Operator op;

    /**
     * 字段值
     */
    private String value;
}

并且考虑到这里过滤的比较符有多个,创建一个枚举来保存所有比较符。

java 复制代码
package com.example.springboot.enums;

/**
 * 比较符
 * @author heyunlin
 * @version 1.0
 */
public enum Operator {
    /**
     * 包含
     */
    contains,
    /**
     * 等于
     */
    equal,
    /**
     * 不等于
     */
    notequal,
    /**
     * 以...开始
     */
    beginwith,
    /**
     * 以...结尾
     */
    endwith,
    /**
     * 小于
     */
    less,
    /**
     * 小于或等于
     */
    lessorequal,
    /**
     * 大于
     */
    greater,
    /**
     * 大于或等于
     */
    greaterorequal
}
Pager

最后在Pager类上额外添加一个filterRules属性,让controller接口接收前端传递的filterRules参数,并将其转换为List<FilterRule>类型。

java 复制代码
package com.example.springboot.base;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.List;

/**
 * 基础分页参数对象,包含页数和每页的记录数
 * @author heyunlin
 * @version 1.0
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class Pager<T> extends Sorter {
    /**
     * 页数
     */
    private Integer page = 1;

    /**
     * 每页记录数
     */
    private Integer rows = 10;

    /**
     * 过滤规则
     */
    private List<FilterRule> filterRules;

    /**
     * 根据Pager创建Page对象
     * @param pager Pager
     * @return Page<T>
     */
    public static <T> Page<T> ofPage(Pager<T> pager) {
        return new Page<>(pager.getPage(), pager.getRows());
    }
}

测试请求一下,发现请求返回400状态码,参数转换异常。

具体的错误提示如下:不能从String类型转换到List<FilterRule>类型,这也是意料之中的事。

java 复制代码
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'songPagerDTO' on field 'filterRules': rejected value [[{"field":"name","op":"contains","value":"宠坏"}]]; codes [typeMismatch.songPagerDTO.filterRules,typeMismatch.filterRules,typeMismatch.java.util.List,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [songPagerDTO.filterRules,filterRules]; arguments []; default message [filterRules]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property 'filterRules'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.example.springboot.base.FilterRule' for property 'filterRules[0]': no matching editors or conversion strategy found]
	at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:175)
	at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)
	at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
StringToListOfFilterRuleConverter

于是添加一个类型转换器,完成String到List<FilterRule>的转换。这里使用alibaba的fastjson来实现

java 复制代码
package com.example.springboot.base;

import com.alibaba.fastjson.JSON;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author heyunlin
 * @version 1.0
 */
@Component
public class StringToListOfFilterRuleConverter implements Converter<String, List<FilterRule>> {

    @Override
    public List<FilterRule> convert(String source) {
        return JSON.parseArray(source, FilterRule.class);
    }

}

完成以上修改之后,请求总算是通了,正常返回了数据。

Pager

最后,在后端实现数据过滤功能,根据filterRules参数动态添加查询条件。在Pager类值统一处理过滤

java 复制代码
package com.example.springboot.base;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.List;

/**
 * 基础分页参数对象,包含页数和每页的记录数
 * @author heyunlin
 * @version 1.0
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class Pager<T> extends Sorter {
    /**
     * 页数
     */
    private Integer page = 1;

    /**
     * 每页记录数
     */
    private Integer rows = 10;

    /**
     * 过滤规则
     */
    private List<FilterRule> filterRules;

    /**
     * 根据Pager创建Page对象
     * @param pager Pager
     * @return Page<T>
     */
    public static <T> Page<T> ofPage(Pager<T> pager) {
        return new Page<>(pager.getPage(), pager.getRows());
    }

    /**
     * 根据Pager创建QueryWrapper对象
     * @param pager Pager
     * @return QueryWrapper<T>
     */
    public static <T> QueryWrapper<T> getQueryWrapper(Pager<T> pager) {
        List<FilterRule> filterRules = pager.getFilterRules();

        if (filterRules != null && !filterRules.isEmpty()) {
            QueryWrapper<T> wrapper = new QueryWrapper<>();

            for (FilterRule filterRule : filterRules) {
                String field = filterRule.getField();
                String value = filterRule.getValue();

                switch (filterRule.getOp()) {
                    case less:
                        wrapper.lt(field, value);
                        break;
                    case equal:
                        wrapper.eq(field, value);
                        break;
                    case greater:
                        wrapper.gt(field, value);
                        break;
                    case notequal:
                        wrapper.ne(field, value);
                        break;
                    case lessorequal:
                        wrapper.le(field, value);
                        break;
                    case greaterorequal:
                        wrapper.ge(field, value);
                        break;
                    case beginwith:
                        wrapper.likeLeft(field, value);
                        break;
                    case endwith:
                        wrapper.likeRight(field, value);
                        break;
                    case contains:
                        wrapper.like(field, value);
                        break;
                    default:
                        break;
                }
            }

            return wrapper;
        }

        return null;
    }

}
SongServiceImpl

最后修改一下selectByPage()方法的具体实现,从Pager类获取QueryWrapper对象,而不是自己构建。

java 复制代码
package com.example.springboot.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.springboot.base.Pager;
import com.example.springboot.dto.SongInsertDTO;
import com.example.springboot.dto.SongPagerDTO;
import com.example.springboot.dto.SongUpdateDTO;
import com.example.springboot.entity.Song;
import com.example.springboot.exception.GlobalException;
import com.example.springboot.mapper.SongMapper;
import com.example.springboot.restful.ResponseCode;
import com.example.springboot.service.SongService;
import com.example.springboot.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @author heyunlin
 * @version 1.0
 */
@Service
public class SongServiceImpl implements SongService {

    private final SongMapper songMapper;

    @Autowired
    public SongServiceImpl(SongMapper songMapper) {
        this.songMapper = songMapper;
    }

    // ...其它代码

    @Override
    public Page<Song> selectByPage(SongPagerDTO pagerDTO) {
        QueryWrapper<Song> wrapper = Pager.getQueryWrapper(pagerDTO);
        Page<Song> page = Pager.ofPage(pagerDTO);

        return songMapper.selectPage(page, wrapper);
    }

}

至此,所有功能都已经完成。

好了,文章就分享到这里了,看完不要忘了点赞+收藏哦~

前端项目地址如下,可按需获取

https://gitcode.net/heyl163_/easyui.githttps://gitcode.net/heyl163_/easyui.git

相关推荐
王哲晓10 分钟前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_41113 分钟前
无网络安装ionic和运行
前端·npm
理想不理想v14 分钟前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云24 分钟前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
微信:1379712058726 分钟前
web端手机录音
前端
齐 飞32 分钟前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
神仙别闹1 小时前
基于tensorflow和flask的本地图片库web图片搜索引擎
前端·flask·tensorflow
GIS程序媛—椰子2 小时前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_0012 小时前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端2 小时前
Content Security Policy (CSP)
前端·javascript·面试