使用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中文网icon-default.png?t=N7T8https://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对象。

    $('#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/icon-default.png?t=N7T8https://gitee.com/he-yunlin/springboot-crud/tree/springboot-crud1.0/

后端代码

添加跨域配置

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

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 {/*** 解决跨域问题*/@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOriginPatterns("*").allowedMethods("*").allowedHeaders("*").allowCredentials(true).maxAge(5000);}}

添加controller接口

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

    @RequestMapping(value = "/selectList", method = RequestMethod.GET)public JsonResult<List<Song>> selectList() {List<Song> list = songService.selectList();return JsonResult.success("查询成功", list);}

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

List<Song> selectList();

SongServiceImpl

    @Overridepublic List<Song> selectList() {return songMapper.selectList(null);}

前端代码

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

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

<!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属性

<!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时,表示请求被正确地执行了。

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

loadFilter: function(res) {if (res.code == 200) {return res.data;} else {return null;}
},

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

<!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

<!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看一下效果。

<!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。

<!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比较适合。

<!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分页插件。

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 {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 防全表更新与删除插件interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());// 分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}}

前端代码

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

<!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>

页面效果

至此,分页功能完成~

增删查改功能

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

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

<!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)icon-default.png?t=N7T8https://www.jeasyui.net/extension/192.html访问以上地址,页面拉到底部,把这个压缩包下载下来,我们需要它里面的datagrid-filter.js文件。

前端代码

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

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

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

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;
}

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

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>类型。

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>类型,这也是意料之中的事。

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来实现

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>> {@Overridepublic List<FilterRule> convert(String source) {return JSON.parseArray(source, FilterRule.class);}}

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

Pager

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

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对象,而不是自己构建。

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;@Autowiredpublic SongServiceImpl(SongMapper songMapper) {this.songMapper = songMapper;}// ...其它代码@Overridepublic 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.giticon-default.png?t=N7T8https://gitcode.net/heyl163_/easyui.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/137645.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序如何设置下单提示语句

下单提示会展示在购物车和提交订单页面&#xff0c;它可以帮助商家告知客户事项&#xff0c;提高用户体验和减少错误操作。例如提示&#xff1a;商品是否包邮、某些区域是否发货、商品送达时间等等。 在小程序管理员后台->配送设置处&#xff0c;填写下单提示。在设置下单提…

Java自学第8课:电商项目(3) - 重新搭建环境

由于之前用的jdk和eclipse&#xff0c;以及mysql并不是视频教程所采用的&#xff0c;在后面运行源码和使用作者提供源码时&#xff0c;总是报错&#xff0c;怀疑&#xff1a; 1 数据库有问题 2 jdk和引入的jar包不匹配 3 其他什么未知的错误&#xff1f; 所以决定卸载jdk e…

SQL入门语句

MySQL和SQL的区别是什么&#xff1f;之间是什么关系&#xff1f; SQL&#xff08;Structured Query Language&#xff09;是用于管理和操作关系型数据库&#xff08;RDBMS&#xff09;的标准语言。SQL还可以用于这些RDBMS&#xff1a;MySQL、Oracle、Microsoft SQL Server、Pos…

Kafka中遇到的错误:

1、原因&#xff1a;kafka是一个去中心化结果的&#xff0c;所以在启动Kafka的时候&#xff0c;每一个节点上都需要启动。 启动的命令&#xff1a;kafka-server-start.sh -daemon /usr/local/soft/kafka_2.11-1.0.0/config/server.properties

AMESim 2021安装教程

主要是AMESim的安装 写在前面&#xff0c;由于项目需要&#xff0c;需要自学AMESim&#xff0c;因此需要安装这个软件&#xff0c;目前仅仅安装使用&#xff0c;还不涉及到与MATLAB的联合仿真&#xff0c;老板说用 RT LAB半实物仿真平台&#xff0c;但是简单搜了一下&#xff0…

Flutter笔记:绘图示例 - 一个简单的(Canvas )时钟应用

Flutter笔记 绘图示例 - 一个简单的&#xff08;Canvas &#xff09;时钟应用 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_2855…

如何记录血压的波动情况

import pandas as pd from plotnine import * import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [Microsoft YaHei] 记录时间(time)、收缩压(SBP)、舒张压(DBP)&#xff1a; df pd.DataFrame({ time: [2023-11-01 08:30, 2023-11-02 21:00, 2023-11-0…

前端-第一部分-HTML

一.初识HTML 1.1 HTML 简介 HTML 全称为 HyperText Mark-up Language&#xff0c;翻译为超文本标签语言&#xff0c;标签也称作标记或者元素。HTML 是目前网络上应用最为广泛的技术之一&#xff0c;也是构成网页文档的主要基石之一。HTML文本是由 HTML 标签组成的描述性文本&a…

力扣最热一百题——每日温度

Python后面的文章&#xff0c;内容都比较多&#xff0c;但是同时我又想保持每天更新的速度&#xff0c;所以Python的文章我继续打磨打磨&#xff0c;先更新一篇算法的文章。 一身正气报国家&#xff0c;旁无乱境不恋她 ヾ(◍∇◍)&#xff89;&#xff9e; 力扣题号&#xff1a…

css呼吸效果实现

实现一个图片有规律的大小变化&#xff0c;呈现呼吸效果&#xff0c;怎么用CSS实现这个呼吸效果呢 一.实现 CSS实现动态效果可以使用动画( animation)来属性实现&#xff0c;放大缩小效果可以用transform: scale来实现&#xff0c;在这基础上有了动画&#xff0c;就可以设置一个…

ps人像怎么做渐隐的效果?

photoshop怎么制作人像渐隐的图片效果&#xff1f;渐隐效果需要使用渐变来实现&#xff0c;下面我们就来看看详细的教程。 首先&#xff0c;我们打开Photoshop&#xff0c;点击屏幕框选的【打开】&#xff0c;打开一张背景图片。 下面&#xff0c;我们点击左上角【文件】——【…

Exploration by random network distillation论文笔记

Exploration by Random Network Distillation (2018) 随机网络蒸馏探索 0、问题 这篇文章提出的随机网络蒸馏方法与Curiosity-driven Exploration by Self-supervised Prediction中提出的好奇心机制的区别&#xff1f; 猜想&#xff1a;本文是基于随机网络蒸馏提出的intrin…

楼宇天台视频AI智能监管方案,时刻保障居民安全

一、背景需求分析 我们经常能看到这样的新闻报道&#xff0c;小孩登上小区的天台玩耍&#xff0c;因为家长和物业人员发现得晚&#xff0c;没有及时制止&#xff0c;结果导致意外事故的发生。此前&#xff0c;在某小区就有居民拍下多名儿童在小区高层住宅的楼顶玩耍跳跃&#…

Pytorch R-CNN目标检测-汽车car

概述 目标检测(Object Detection)就是一种基于目标几何和统计特征的图像分割,它将目标的分割和识别合二为一,通俗点说就是给定一张图片要精确的定位到物体所在位置,并完成对物体类别的识别。其准确性和实时性是整个系统的一项重要能力。 R-CNN的全称是Region-CNN(区域卷积神经…

Nginx实现tcp代理并支持TLS加密实验

Nginx源码编译 关于nginx的搭建配置具体参考笔者之前的一篇文章&#xff1a;实时流媒体服务器搭建试验&#xff08;nginxrtmp&#xff09;_如何在线测试流媒体rtmp搭建成功了吗-CSDN博客中的前半部分&#xff1b;唯一变化的是编译参数&#xff08;添加stream模块并添加其对应ss…

无线城市WiFi解决方案【完整Word】

wx供重浩&#xff1a;创享日记 获取完整无水印高清Word版 文章目录 第1章 项目背景1.1“无线城市”的定义1.2 国内外“无线城市”发展概况1.3 典型案例分析1.4 建设无线城市的必要性1.5 无线城市能为政府带来的价值 第2章 项目需求分析2.1 无线城市的现状分析2.2 无线城市的总体…

Excel中功能区的存放位置很灵活,可以根据需要隐藏或显示

在这个简短的教程中,你将找到5种快速简单的方法来恢复Excel功能区,以防丢失,并学习如何隐藏功能区,为工作表腾出更多空间。 功能区是Excel中所有操作的中心点,也是大多数可用功能和命令所在的区域。你觉得功能区占用了你太多的屏幕空间吗?没问题,只需单击鼠标,它就被隐…

Wsl2 Ubuntu在不安装Docker Desktop情况下使用Docker

目录 1. 前提条件 2.安装Distrod 3. 常见问题 3.1.docker compose 问题无法使用问题 3.1. docker-compose up报错 参考文档 1. 前提条件 win10 WSL2 Ubuntu(截止202308最新版本是20.04.xx) 有不少的博客都是建议直接安装docker desktop&#xff0c;这样无论在windows…

秋招进入尾声了,还有哪些公司和岗位可以投递?

24届秋招基本已经进入尾声了&#xff0c;接下来就是秋招补录了&#xff0c;最近在微信群看到一些同学再问哪些公司还在招人的。 在这里跟大家分享一份2024届秋招信息汇总表&#xff0c;目前已更新2000家&#xff0c;不仅有互联网公司&#xff0c;还有外企、国企、各类研究所&am…

EM@解三角形@正弦定理@余弦定理

文章目录 abstract解三角形基本原理不唯一性 正弦定理直角三角形中的情形推广锐角三角形钝角情形 小结:正弦定理 余弦定理直角三角形中的情形非直角情形小结:余弦定理公式的角余弦形式 abstract 解直角三角形问题正弦定理和余弦定理的推导 对于非直角情形,都是直角情形的推广同…