使用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.rhkb.cn/news/186867.html

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

相关文章

JS逆向爬虫---请求参数加密③【比特币交易爬虫】

查询参数确定 t无加密 请求头参数加密 X-Apikey参数加密确定 X-Apikey逆向 const API_KEY "a2c903cc-b31e-4547-9299-b6d07b7631ab" function encryptApiKey(){ var t API_KEY, e t.split(""), n e.splice(0, 8);return t e.concat(n).join("&…

利用Ansible实现批量Linux服务器安全配置

1.摘要 在上一篇<<初步利用Ansible实现批量服务器自动化管理>>文章中, 我初步实现了通过编写清单和剧本来实现多台服务器的自动化管理,在本章节中, 我将利用Ansible的剧本来实现更实用、更复杂一点的功能, 主要功能包括三个:1.同时在三台服务器中增加IP访问控制,只…

万宾科技智能井盖,实现对井盖的监测

随着人工智能和物联网技术的不断变化&#xff0c;各种适用于市政府提高管理能力和公共服务水平的高科技产品不断更新。在道路基础设施建设过程中&#xff0c;智能井盖传感器的出现时刻保护着城市地下生命线&#xff0c;而且可以对地下水道井盖进行实时的监测并完成数据上传等工…

Excel下拉填充时,如何使得数字不递增?

问题描述&#xff1a;Excel下拉填充时&#xff0c;如何使得数字不递增&#xff1f; 解决办法&#xff1a;先下拉填充数据之后&#xff0c;看到最后一个单元格的右下角有个填充设置的符号&#xff0c;右键选择复制单元格即可。其中这里的填充序列就是递增数字的操作。

使用Pytorch的一些小细节(一)

文章目录 前言数据结构-张量max函数索引函数赋值函数拼接函数 前言 由于不经常动手写代码&#xff0c;所以对于python语言中的常见数据结构的用法也不是很熟悉&#xff0c;对于pytorch中的数据结构就更加不熟悉了。之前的代码基础是基于C语言的&#xff0c;属性都是自己定义&a…

Selenium是什么,带你了解自动化测试的神奇之处

一、使用测试工具 工欲善其事&#xff0c;必先利其器。在开始具体的自动化测试之前&#xff0c;我们需要做好更多的准备&#xff0c;包括以下几个方面&#xff1a; 认识自动化测试 准备自动化测试工具 使用有效的方式 针对具体的测试对象 接下来的第一部分内容&#xff0c;我…

什么是数据库?数据库有哪些基本分类和主要特点?

数据库是以某种有组织的方式存储的数据集合。本文从数据库的基本概念出发&#xff0c;详细解读了数据库的主要类别和基本特点&#xff0c;并就大模型时代备受瞩目的数据库类型——向量数据库进行了深度剖析&#xff0c;供大家在了解数据库领域的基本概念时起到一点参考作用。 …

【chat】2:vs2022 连接远程ubuntu服务器远程cmake开发

大神们是使用vs远程连接和调试的:C++搭建集群聊天室(三):配置远程代码编辑神器 VScode我尝试过vs++ 和 clion 都不错。在 Visual Studio 中配置 Linux CMake 项目 比较麻烦的就是要配置CMakeSettings.json ,而且会自动做复制指定远程 Linux 目标,则会将源复制到远程系统 …

19、Flink 的Table API 和 SQL 中的自定义函数及示例(3)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

如何实现Debian工控电脑USB接口安全管控

Debian 作为工控电脑操作系统具有稳定性、安全性、自定义性和丰富的软件包等优势&#xff0c;适用于要求高度可靠性和安全性的工控应用。 Debian 作为工控电脑操作系统在工业控制领域有很大优势&#xff0c;包括&#xff1a; 稳定性&#xff1a;Debian 的发布版以其稳定性而闻…

小程序多文件上传 Tdesign

众所周知&#xff0c;小程序文件上传还是有点麻烦的&#xff0c;其实主要还是小程序对的接口有诸多的不便&#xff0c;比如说&#xff0c;文件不能批量提交&#xff0c;只能一个个的提交&#xff0c;小程序的上传需要专门的接口。 普通的小程序的页面也比普通的HTML复杂很多 现…

centos中安装的goland配置sdk报错:所选的目录不是Go SDK的有效主路经

选中目录后一直报错&#xff1a; 正确的位置&#xff1a; 原因竟然是使用 解压go1.21.4.linux-amd64.tar.gz 包出来&#xff0c;少了scr和test目录&#xff0c;重新解压后可以正确设定SDK主目录。 有同样问题的可以确认一下。 tar -C /usr/local -zxvf go1.19.2.linux-amd64.…

java项目之高校奖学金管理系统(ssm框架+源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的高校奖学金管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 管理员&#xff1a;首…

NodeJS 入门笔记

文档地址 课程地址 源码 提取码&#xff1a;963h hello wrold console.log(hello, world);node hello.jsnodejs 中不能使用 DOM(document) 和 BOM(window) 的 API&#xff1a; documentwindowhistorynavigatorlocation 但是下面的 API 是相通的&#xff1a; consoletimer…

自动化测试中的失败截图和存log

如果我们在执行自动化测试的时候&#xff0c;希望能在失败的时候保存现场&#xff0c;方便事后分析。 对于UI自动化&#xff0c;我们希望截图在测试报告中。 对于api自动化&#xff0c;我们希望截取出错的log在测试报告中。 我开始自己蛮干&#xff0c;写了两个出错截图的方法。…

试题:最大的矩形(给定直方图里面积最大的矩形)

问题描述 在横轴上放了n个相邻的矩形&#xff0c;每个矩形的宽度是1&#xff0c;而第i&#xff08;1 ≤ i ≤ n&#xff09;个矩形的高度是hi。这n个矩形构成了一个直方图。例如&#xff0c;下图中六个矩形的高度就分别是3, 1, 6, 5, 2, 3。 请找出能放在给定直方图里面积最大的…

ARMday04(开发版简介、LED点灯)

开发版简介 开发板为stm32MP157AAA,附加一个拓展版 硬件相关基础知识 PCB PCB&#xff08; Printed Circuit Board&#xff09;&#xff0c;中文名称为印制电路板&#xff0c;又称印刷线路板&#xff0c;是重要的电子部件&#xff0c;是电子元器件的支撑体&#xff0c;是电子…

什么是自动化测试框架?我们该如何搭建自动化测试框架?

无论是在自动化测试实践&#xff0c;还是日常交流中&#xff0c;经常听到一个词&#xff1a;框架。之前学习自动化测试的过程中&#xff0c;一直对“框架”这个词知其然不知其所以然。 最近看了很多自动化相关的资料&#xff0c;加上自己的一些实践&#xff0c;算是对“框架”…

uniapp使用vur-cli新建项目并打包

新建项目 npm install -g vue/cli vue create -p dcloudio/uni-preset-vue my-project选择默认模板npm run dev:h5 运行 安装sass和uview &#xff08;npm安装失败&#xff09; bug&#xff1a;使用uni.scss中的变量或样式&#xff0c;<style lang"scss"> 必…

『 Linux 』进程概念

文章目录 &#x1f5de;️ 冯诺依曼体系结构 &#x1f5de;️&#x1f4c3; 为什么在计算机当中需要使用内存充当中间介质而不使CUP与外设直接进行交互?&#x1f4c3; CPU如何读取数据 &#x1f5de;️ 操作系统(Operating system) &#x1f5de;️&#x1f4c3; 操作系统如何…