使用easyui前端框架构建一个crud应用(看完这篇就够了)

easyui是博主最喜欢的前端框架,因为它提供了多种主题样式和各种好看的ui组件。

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

目录

一、快速开始

二、准备工作

三、开始使用

1、主题资源

2、常用组件

dialog

datagrid

textbox

passwordbox

四、表格渲染

1、后端代码

添加跨域配置

添加controller接口

添加service接口

2、前端代码

表格数据的Ajax请求方式

响应数据过滤处理

自适应列宽

表格自带花纹

开启表格分页

固定表格高度

五、构建应用

1、分页功能

后端代码

MybatisPlusConfig.java

JsonResult.java

Pager.java

SongController.java

SongService.java

SongServiceImpl.java

前端代码

2、增删改功能

添加、修改功能

基于对话框

创建表单

表单渲染

添加、修改功能

基于行内编辑

准备工作

添加功能

修改功能

其他功能

3、条件查询功能

前端代码

后端代码

FilterRule

Operator

Pager

StringToListOfFilterRuleConverter

Pager

SongServiceImpl

4、字段排序功能

前端代码

后端代码

Sorter

Pager

SongServiceImpl

Pager

SongServiceImpl

代码改进

Pager

SongServiceImpl

5、数据导出功能

前端代码

后端代码

添加依赖

SongController

SongService

SongServiceImpl


一、快速开始

这个章节主要介绍easyui前端框架的下载,easyui的官网地址如下:

JQuery EasyUI中文网icon-default.png?t=N7T8https://www.jeasyui.net/点击上方链接访问easyui中文官网,点击红框内的链接跳转到到下载页面。

在下载页面点击下载对应的版本,本篇文章将使用jquery easyui,点击红框内的按钮。

选择下载免费版即可~

二、准备工作

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

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

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

通过HBuilderx创建一个基本的html项目,项目名为easyui-crud

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

三、开始使用

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

1、主题资源

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

2、常用组件

dialog

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

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。

通过标签创建

<input class="easyui-textbox" style="width:150px;" />

使用Javascript创建

<input id="tb" type="text" />

$('#tb').textbox({
    width: 150
});

passwordbox

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

 通过标签创建

<input class="easyui-passwordbox" style="width:150px;" />

使用Javascript创建

<input id="tb" type="text" />

$('#tb').passwordbox({
    width: 150
});

四、表格渲染

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

相关的文章:

springboot+mybatis实现简单的增、删、查、改icon-default.png?t=N7T8https://blog.csdn.net/heyl163_/article/details/132197201

springboot+mybatis+mybatis-plus对crud项目进行改进icon-default.png?t=N7T8https://blog.csdn.net/heyl163_/article/details/132215660在springboot-crud1.0的基础上创建一个新的代码分支springboot-crud2.0

1、后端代码

添加跨域配置

首先要添加跨域配置,防止请求出现cors问题。在config包下创建SpringMvcConfig.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中添加一个selectList()接口方法

package com.example.springboot.controller;

import com.example.springboot.dto.SongInsertDTO;
import com.example.springboot.dto.SongUpdateDTO;
import com.example.springboot.entity.Song;
import com.example.springboot.restful.JsonResult;
import com.example.springboot.service.SongService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.List;

/**
 * @author heyunlin
 * @version 1.0
 */
@RestController
@RequestMapping(path = "/song", produces="application/json;charset=utf-8")
public class SongController {

    private final SongService songService;

    @Autowired
    public SongController(SongService songService) {
        this.songService = songService;
    }

    @RequestMapping(value = "/insert", method = RequestMethod.POST)
    public JsonResult<Void> insert(@Validated SongInsertDTO insertDTO) {
        songService.insert(insertDTO);

        return JsonResult.success("添加成功");
    }

    @RequestMapping(value = "/deleteById/{id}", method = RequestMethod.GET)
    public JsonResult<Void> deleteById(@PathVariable("id") String id) {
        songService.deleteById(id);

        return JsonResult.success("删除成功");
    }

    @RequestMapping(value = "/updateById", method = RequestMethod.POST)
    public JsonResult<Void> updateById(@Valid SongUpdateDTO updateDTO) {
        songService.updateById(updateDTO);

        return JsonResult.success("修改成功");
    }

    @RequestMapping(value = "/selectById/{id}", method = RequestMethod.GET)
    public Song selectById(@PathVariable("id") String id) {
        return songService.selectById(id);
    }

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

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

}

添加service接口

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

package com.example.springboot.service;

import com.example.springboot.dto.SongInsertDTO;
import com.example.springboot.dto.SongUpdateDTO;
import com.example.springboot.entity.Song;

import java.util.List;

/**
 * @author heyunlin
 * @version 1.0
 */
public interface SongService {

    void insert(SongInsertDTO songInsertDTO);

    void deleteById(String id);

    void updateById(SongUpdateDTO updateDTO);

    Song selectById(String id);

    List<Song> selectList();
}

SongServiceImpl

package com.example.springboot.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.springboot.dto.SongInsertDTO;
import com.example.springboot.dto.SongUpdateDTO;
import com.example.springboot.entity.Song;
import com.example.springboot.mapper.SongMapper;
import com.example.springboot.service.SongService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
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 void insert(SongInsertDTO insertDTO) {
        Song song = new Song();

        song.setId(uuid());
        song.setName(insertDTO.getName());
        song.setNote(insertDTO.getNote());
        song.setSinger(insertDTO.getSinger());

        songMapper.insert(song);
    }

    @Override
    public void deleteById(String id) {
        songMapper.deleteById(id);
    }

    @Override
    public void updateById(SongUpdateDTO updateDTO) {
        Song song = new Song();

        song.setId(updateDTO.getId());
        song.setName(updateDTO.getName());
        song.setNote(insertDTO.getNote());
        song.setSinger(updateDTO.getSinger());
        song.setLastUpdateTime(LocalDateTime.now());

        songMapper.updateById(song);
    }

    @Override
    public Song selectById(String id) {
        return songMapper.selectById(id);
    }

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

    /**
     * 根据当前时间生成UUID
     * @return String
     */
    private static String uuid() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        LocalDateTime localDate = LocalDateTime.now();

        return localDate.format(formatter);
    }

}

2、前端代码

修改index.html文件的内容,引入必要的css和js文件,修改表格的数据加载地址url为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: '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>

然后选择通过firefox运行,打开看到表格没有显示数据,F12打开控制台,查看到请求发生异常,不支持post请求。

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

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

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

表格数据的Ajax请求方式

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

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

为什么会这样呢?

其实是因为后端返回的数据不是一个list,而是封装的一个JsonResult对象,list放到这个对象的data里了。

响应数据过滤处理

所以,这里要对返回的数据进行简单的处理,得到data里的list,loadFilter属性是一个方法,用于过滤请求url返回的数据。

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

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

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

最后,添加loadFilter,调整表格的列信息

<!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多条数据。

自适应列宽

上面的页面看起来非常丑,如果表格能占满整个页面会更好看一点,因此,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属性腾空出世,这个属性的作用就是显示条纹,不出所料,这个属性默认值也是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",
					fitColumns: true,
					striped: 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的感觉了~

开启表格分页

上面的表格外观已经很完美了,作为一个后端开发人员来说,这样的样式已经无可挑剔,但是,之前已经说过了,一共有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

固定表格高度

基于上面的的问题(需要拉到页面底部才能看到分页栏),现在给表格设置一个固定的高度,让它刚好够显示20条数据。

<!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>
			let pageList = [20, 50, 100, 500, 1000];
			
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectList",
					method: "get",
					fitColumns: true,
					striped: true,
					height: 710,
					pagination: true,
					pageSize: pageList[0],
					pageList: pageList,
					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>

再次查看页面效果

五、构建应用

1、分页功能

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

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

后端代码
MybatisPlusConfig.java

config包下新增mybatis-plus配置类MybatisPlusConfig,添加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.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * Mybatis-Plus配置类
 * @author heyunlin
 * @version 1.0
 */
@Configuration
@EnableTransactionManagement
public class MybatisPlusConfig {

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

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

        return interceptor;
    }

}

JsonResult.java

JsonResult添加restPage()方法

    public static JsonResult<Map<String, Object>> restPage(Page<Song> page) {
        Map<String, Object> resultMap = new HashMap<>();
        
        resultMap.put("total", page.getTotal());
        resultMap.put("rows", page.getRecords());
        
        return success("请求成功", resultMap);
    }

完整的代码JsonResult.java

package com.example.springboot.restful;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.springboot.entity.Song;
import lombok.Data;

import java.util.HashMap;
import java.util.Map;

/**
 * 响应对象
 * @author heyunlin
 * @version 1.0
 */
@Data
public class JsonResult<T> {

    /**
     * 响应状态码
     */
    private Integer code;
    /**
     * 响应提示信息
     */
    private String message;
    /**
     * 响应数据
     */
    private T data;

    public static JsonResult<Void> success() {
        return success(null);
    }

    public static JsonResult<Void> success(String message) {
        return success(message, null);
    }

    public static <T> JsonResult<T> success(String message, T data) {
        JsonResult<T> jsonResult = new JsonResult<>();

        jsonResult.setCode(ResponseCode.OK.getValue());
        jsonResult.setMessage(message);
        jsonResult.setData(data);

        return jsonResult;
    }

    public static JsonResult<Void> error(String message) {
        JsonResult<Void> jsonResult = new JsonResult<>();

        jsonResult.setCode(ResponseCode.ERROR.getValue());
        jsonResult.setMessage(message);

        return jsonResult;
    }

    public static JsonResult<Void> error(ResponseCode responseCode, Throwable e) {
        return error(responseCode, e.getMessage() != null ? e.getMessage() : "系统发生异常,请联系管理员!");
    }

    public static JsonResult<Void> error(ResponseCode responseCode, String message) {
        JsonResult<Void> jsonResult = new JsonResult<>();

        jsonResult.setCode(responseCode.getValue());
        jsonResult.setMessage(message);

        return jsonResult;
    }

    public static JsonResult<Map<String, Object>> restPage(Page<Song> page) {
        Map<String, Object> resultMap = new HashMap<>();

        resultMap.put("total", page.getTotal());
        resultMap.put("rows", page.getRecords());

        return success("请求成功", resultMap);
    }

}

Pager.java

定义一个包含分页参数的对象Pager,继承自该类的实体类就拥有了这两个属性。

package com.example.springboot.base;

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

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

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

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

}

SongController.java

SongController中添加一个selectByPage()接口方法

package com.example.springboot.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.restful.JsonResult;
import com.example.springboot.service.SongService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.List;
import java.util.Map;

/**
 * @author heyunlin
 * @version 1.0
 */
@RestController
@RequestMapping(path = "/song", produces="application/json;charset=utf-8")
public class SongController {

    private final SongService songService;

    @Autowired
    public SongController(SongService songService) {
        this.songService = songService;
    }

    @RequestMapping(value = "/insert", method = RequestMethod.POST)
    public JsonResult<Void> insert(@Validated SongInsertDTO insertDTO) {
        songService.insert(insertDTO);

        return JsonResult.success("添加成功");
    }

    @RequestMapping(value = "/deleteById/{id}", method = RequestMethod.GET)
    public JsonResult<Void> deleteById(@PathVariable("id") String id) {
        songService.deleteById(id);

        return JsonResult.success("删除成功");
    }

    @RequestMapping(value = "/updateById", method = RequestMethod.POST)
    public JsonResult<Void> updateById(@Valid SongUpdateDTO updateDTO) {
        songService.updateById(updateDTO);

        return JsonResult.success("修改成功");
    }

    @RequestMapping(value = "/selectById/{id}", method = RequestMethod.GET)
    public Song selectById(@PathVariable("id") String id) {
        return songService.selectById(id);
    }

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

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

    @RequestMapping(value = "/selectByPage", method = RequestMethod.POST)
    public JsonResult<Map<String, Object>> selectByPage(SongPagerDTO songPagerDTO) {
        Page<Song> page = songService.selectByPage(songPagerDTO);

        return JsonResult.restPage(page);
    }

}

SongService.java

定义一个对应的抽象方法selectByPage()

package com.example.springboot.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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 java.util.List;

/**
 * @author heyunlin
 * @version 1.0
 */
public interface SongService {

    void insert(SongInsertDTO songInsertDTO);

    void deleteById(String id);

    void updateById(SongUpdateDTO updateDTO);

    Song selectById(String id);

    List<Song> selectList();

    Page<Song> selectByPage(SongPagerDTO songPagerDTO);
}

SongServiceImpl.java

在实现类中实现分页查询功能

package com.example.springboot.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
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.mapper.SongMapper;
import com.example.springboot.service.SongService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
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 void insert(SongInsertDTO insertDTO) {
        Song song = new Song();

        song.setId(uuid());
        song.setName(insertDTO.getName());
        song.setNote(insertDTO.getNote());
        song.setSinger(insertDTO.getSinger());

        songMapper.insert(song);
    }

    @Override
    public void deleteById(String id) {
        songMapper.deleteById(id);
    }

    @Override
    public void updateById(SongUpdateDTO updateDTO) {
        Song song = new Song();

        song.setId(updateDTO.getId());
        song.setName(updateDTO.getName());
        song.setNote(insertDTO.getNote());
        song.setSinger(updateDTO.getSinger());
        song.setLastUpdateTime(LocalDateTime.now());

        songMapper.updateById(song);
    }

    @Override
    public Song selectById(String id) {
        return songMapper.selectById(id);
    }

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

    @Override
    public Page<Song> selectByPage(SongPagerDTO songPagerDTO) {
        Page<Song> page = Pager.ofPage(songPagerDTO);

        return songMapper.selectPage(page, null);
    }

    /**
     * 根据当前时间生成UUID
     * @return String
     */
    private static String uuid() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        LocalDateTime localDate = LocalDateTime.now();

        return localDate.format(formatter);
    }

}

前端代码

我们把请求数据的接口改成/song/selectByPage,删除method属性,使用默认的post请求。

<!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>
			let pageList = [20, 50, 100, 500, 1000];
			
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectByPage",
					fitColumns: true,
					striped: true,
					height: 710,
					pagination: true,
					pageSize: pageList[0],
					pageList: pageList,
					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>

至此,分页功能完成~

2、增删改功能

一般页面的js代码和html是分离的,在这个部分,为了方便修改文件,把js代码单独保存到一个js文件,然后通过外部引入的方式引入。

接下来来实现数据的增、删、改功能。

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

<!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>
			let pageList = [20, 50, 100, 500, 1000];
			
			function addHandler() {
				// todo
			}
			
			function editHandler() {
				// todo
			}
			
			function deleteHandler() {
			    // todo
			}
			
			$(document).ready(function() {
				$("#song_list").datagrid({
					url: "http://localhost:8083/song/selectByPage",
					title: "歌曲列表",
					fitColumns: true,
					striped: true,
					height: 777,
					pagination: true,
					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() {
							addHandler();
						}
					}, '-', {
						iconCls: 'icon-edit',
						text: '修改',
						handler: function() {
							editHandler();
						}
					}, '-', {
						iconCls: 'icon-delete',
						text: '删除',
						handler: function() {
							deleteHandler();
						}
					}],
					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>

添加、修改功能

这个部分的功能通过选中一行数据,并点击修改按钮的事件分为有两种实现方案。

具体实现思路:根据点击的按钮动态设置请求地址requestUrl(添加/修改),在对话框中添加一个保存按钮,点击保存按钮则提交post请求到requestUrl,完成数据保存

  • 方案一:把行数据填充到一个对话框内包含的表单中,点击对话框中的保存按钮把修改后的数据提交到后台保存数据;
  • 方案二:开启行内编辑,在表格的行内编辑数据,在表格头部具栏增加两个按钮:保存和取消。

接下来就介绍两种实现方案的具体实现。

基于对话框

复制一份index.html,命名为easyui-crud-dialog.html

创建表单

既然是基于对话框,就要先提前创建好一个对话框,在对话框中嵌套一个表单,表单内定义需要通过前端提交的歌曲信息。

修改easyui-crud-dialog.html,添加一个div作为对话框

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>easyui crud应用-基于对话框</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/default/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>
		<script src="../js/easyui-crud-dialog.js"></script>
	</head>
	
	<body>
		<table id="song_list"></table>
		
		<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>
	</body>
</html>

如上所示,通过一个隐藏域保存歌曲的id字段的值,只有修改的时候才需要提交这个id字段。

表单渲染

js/easyui-crud-dialog.js

let base = "http://localhost:8083";
let pageList = [20, 50, 100, 500, 1000];
			
function addHandler() {
	// todo
}

function editHandler() {
	// todo
}

function deleteHandler() {
	// todo
}

$(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() {
				// todo
			}
		}, {
			text: '取消',
			iconCls: 'icon-cancel',
			handler: function() {
				// todo
			}
		}]
	});
		
	$("#song_list").datagrid({
		url: base + "/song/selectByPage",
		title: "歌曲列表",
		fitColumns: true,
		striped: true,
		height: 777,
		pagination: true,
		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() {
				addHandler();
			}
		}, '-', {
			iconCls: 'icon-edit',
			text: '修改',
			handler: function() {
				editHandler();
			}
		}, '-', {
			iconCls: 'icon-delete',
			text: '删除',
			handler: function() {
				deleteHandler();
			}
		}],
		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},
		]]
	});
});

添加、修改功能

所有都准备好了,接下来开始实现具体的功能。添加一个全局属性requestUrl,这个requestUrl属性会根据点击不同的按钮动态地设置。

  • 点击添加按钮时,设置为/song/insert
  • 点击修改按钮时,设置为/song/updateById

在点击添加和修改按钮时,都要打开对话框,修改的时候需要填充表格数据到表单对应字段的输入框中。

 js/index.js

let requestUrl;
let base = "http://localhost:8083";
let pageList = [20, 50, 100, 500, 1000];
			
function addHandler() {
	requestUrl = "/song/insert";
	
	$('#song_dialog').dialog('open');
}

function editHandler() {
	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");
	}
}

function deleteHandler() {
	// todo
}

$(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() {
				// todo
			}
		}, {
			text: '取消',
			iconCls: 'icon-cancel',
			handler: function() {
				// todo
			}
		}]
	});
		
	$("#song_list").datagrid({
		url: base + "/song/selectByPage",
		title: "歌曲列表",
		fitColumns: true,
		striped: true,
		height: 777,
		pagination: true,
		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() {
				addHandler();
			}
		}, '-', {
			iconCls: 'icon-edit',
			text: '修改',
			handler: function() {
				editHandler();
			}
		}, '-', {
			iconCls: 'icon-delete',
			text: '删除',
			handler: function() {
				deleteHandler();
			}
		}],
		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},
		]]
	});
});

点击对话框的保存按钮,会请求requestUrl,把表单的数据提高到后台接口;如果请求正确返回了,则提示操作结果,清空表单数据,并关闭对话框。

点击对话框的取消按钮,则清空表单数据,并关闭对话框。

let requestUrl;
let base = "http://localhost:8083";
let pageList = [20, 50, 100, 500, 1000];
			
function addHandler() {
	requestUrl = "/song/insert";
	
	$('#song_dialog').dialog('open');
}

function editHandler() {
	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");
	}
}

function deleteHandler() {
	// todo
}

$(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,
		buttons: [{
			text: '保存',
			iconCls: 'icon-save',
			handler: function() {
				let bool = $("#song_form").form("validate");
				
				if (bool) {
					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");
				} else {
					$.messager.alert("系统提示", "请填写正确的表单项", "warning");
				}
			}
		}, {
			text: '取消',
			iconCls: 'icon-cancel',
			handler: function() {
				$("#song_form").form('clear');
				$('#song_dialog').dialog('close');
			}
		}]
	});
		
	$("#song_list").datagrid({
		url: base + "/song/selectByPage",
		title: "歌曲列表",
		fitColumns: true,
		striped: true,
		height: 777,
		pagination: true,
		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() {
				addHandler();
			}
		}, '-', {
			iconCls: 'icon-edit',
			text: '修改',
			handler: function() {
				editHandler();
			}
		}, '-', {
			iconCls: 'icon-delete',
			text: '删除',
			handler: function() {
				deleteHandler();
			}
		}],
		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},
		]]
	});
});

至此,基于对话框实现的添加和修改功能就完成了~

基于行内编辑

前面已经实现了基于对话框内镶嵌一个form表单实现了数据的添加、修改功能,这个部分,会通过更高级的方式来实现,在表格的行内开启编辑。

准备工作

项目的根目录的html目录下创建一个easyui-crud-inline.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>easyui crud应用-基于行内编辑</title>
		<link rel="stylesheet" href="../css/themes/icon.css" />
		<link rel="stylesheet" href="../css/themes/default/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>
		<script src="../js/easyui-crud-inline.js"></script>
	</head>
	
	<body>
		<table id="song_list"></table>
	</body>
</html>

js目录下创建easyui-crud-inline.js 

let requestUrl;
let base = "http://localhost:8083";
let pageList = [20, 50, 100, 500, 1000];
			
function addHandler() {
	// todo
}

function editHandler() {
	// todo
}

function saveHandler() {
	// todo
}

function cancelHandler() {
    // todo
}

function deleteHandler() {
	// todo
}

$(document).ready(function() {		
	$("#song_list").datagrid({
		url: base + "/song/selectByPage",
		title: "歌曲列表",
		fitColumns: true,
		striped: true,
		height: 777,
		pagination: true,
		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() {
				addHandler();
			}
		}, '-', {
			iconCls: 'icon-edit',
			text: '修改',
			handler: function() {
				editHandler();
			},
		}, "-", {
			iconCls: "icon-save",
			text: "保存",
			handler: function() {
				saveHandler();
			}
		}, "-", {
			iconCls: "icon-cancel",
			text: "取消",
			handler: function() {
				cancelHandler();
			}
		}, '-', {
			iconCls: 'icon-delete',
			text: '删除',
			handler: function() {
				deleteHandler();
			}
		}],
		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},
		]]
	});
});

添加功能

添加功能的实现思路相对修改功能较为简单,点击添加按钮,会请求后端接口,插入一条默认的数据。

function addHandler() {
	requestUrl = "/song/insert";
	
	$.post(base + requestUrl, {
		name: "*****",
		singer: "*****",
		note: "*****"
	}, function (res) {
		if(res.code === 200) {
			$.messager.show({
				title: '系统消息',
				timeout: 5000,
				showType: 'slide',
				msg: res.message,
			});
			
			$("#song_list").datagrid("reload");
		} else {
			$.messager.alert("系统提示", res.message, "error");
		}
	}, "json");
}

修改功能

这个功能相对复杂,需要依赖easyui datagrid的行编辑结束事件。

定义JSON对象保存修改后的数据

// 定义一个json对象保存歌曲数据
let data = {};

给歌曲列表添加表格行结束编辑事件

onAfterEdit: function (rowIndex, rowData, changes) { // 结束行内编辑事件
    data = {
        id: rowData.id,
        name: changes.name ? changes.name : rowData.name,
        note: changes.note ? changes.note : rowData.note,
        singer: changes.singer ? changes.singer : rowData.singer
    };
},

实现修改功能

function editHandler() {
	let datagrid = $("#song_list");

	if (editingId != null && editingId !== "") {
		datagrid.datagrid("selectRow", editingId);
	} else {
		let row = datagrid.datagrid("getSelected");
		
		if (row) {
			// 获取行索引,这个索引从0开始
			let rowIndex = datagrid.datagrid("getRowIndex", row);
			
			editingId = rowIndex;
			requestUrl = "/song/updateById";

			datagrid.datagrid("beginEdit", rowIndex);
		}
	}
}

其他功能

接下来就剩下保存和取消了

保存

function saveHandler() {
	if (editingId) {
		// 只有结束编辑才能获取到最新的值
		$("#song_list").datagrid("endEdit", editingId);
	
		$.post(base + requestUrl, data, function (res) {
			if(res.code === 200) {
				$.messager.show({
					title: '系统消息',
					timeout: 5000,
					showType: 'slide',
					msg: res.message,
				});
				
				editingId = "";
			} else {
				$.messager.alert("系统提示", res.message, "error");
			}
		}, "json");
	}
}

取消

function cancelHandler() {
	// editingId != null条件防止刷新页面带来的问题
	if (editingId != null && editingId !== "") {
		$("#song_list").datagrid("cancelEdit", editingId);
	
		editingId = "";
	}
}

到了这里,基于行内编辑的表格数据的添加、修改功能就完成了~

let editingId;
let requestUrl;
let base = "http://localhost:8083";
let pageList = [20, 50, 100, 500, 1000];

let data = {};
			
function addHandler() {
	requestUrl = "/song/insert";
	
	$.post(base + requestUrl, {
		name: "*****",
		singer: "*****",
		note: "*****"
	}, function (res) {
		if(res.code === 200) {
			$.messager.show({
				title: '系统消息',
				timeout: 5000,
				showType: 'slide',
				msg: res.message,
			});
			
			$("#song_list").datagrid("reload");
		} else {
			$.messager.alert("系统提示", res.message, "error");
		}
	}, "json");
}

function editHandler() {
	let datagrid = $("#song_list");

	if (editingId != null && editingId !== "") {
		datagrid.datagrid("selectRow", editingId);
	} else {
		let row = datagrid.datagrid("getSelected");
		
		if (row) {
			// 获取行索引,这个索引从0开始
			let rowIndex = datagrid.datagrid("getRowIndex", row);
			
			editingId = rowIndex;
			requestUrl = "/song/updateById";

			datagrid.datagrid("beginEdit", rowIndex);
		}
	}
}

function saveHandler() {
	if (editingId != null && editingId !== "") {
		// 只有结束编辑才能获取到最新的值
		$("#song_list").datagrid("endEdit", editingId);
	
		$.post(base + requestUrl, data, function (res) {
			if(res.code === 200) {
				$.messager.show({
					title: '系统消息',
					timeout: 5000,
					showType: 'slide',
					msg: res.message,
				});
				
				editingId = "";
			} else {
				$.messager.alert("系统提示", res.message, "error");
			}
		}, "json");
	}
}

function cancelHandler() {
	// editingId != null条件防止刷新页面带来的问题
	if (editingId != null && editingId !== "") {
		$("#song_list").datagrid("cancelEdit", editingId);
	
		editingId = "";
	}
}

function exportHandler() {
	location.href = base + "/song/export";
}

function deleteHandler() {
	let rowData = $("#song_list").datagrid("getSelected");
	
	if (rowData) {
		$.messager.confirm("系统确认", "删除后数据无法恢复,是否确认删除?", function(bool) {
			if (bool) {
				$.get(base + "/song/deleteById/" + rowData.id, {}, function(res) {
					if(res.code === 200) {
						$.messager.show({
							title: '系统消息',
							timeout: 5000,
							showType: 'slide',
							msg: res.message,
						});
										
						$("#song_list").datagrid("reload");
					} else {
						$.messager.alert("系统提示", res.message, "error");
					}
				}, "json");
			}
		});
	} else {
		$.messager.alert("系统提示", "请选择要删除的数据!", "warning");
	}
}

$(document).ready(function() {		
	let datagrid = $("#song_list").datagrid({
		url: base + "/song/selectByPage",
		title: "歌曲列表",
		fitColumns: true,
		striped: true,
		height: 810,
		pagination: true,
		pageSize: pageList[0],
		pageList: pageList,
		remoteFilter: true,
		clientPaging: false,
		loadFilter: function(res) {
			if (res.code === 200) {
				return res.data;
			} else {
				return null;
			}
		},
		onAfterEdit: function (rowIndex, rowData, changes) { // 结束行内编辑事件
			data = {
				id: rowData.id,
				name: changes.name ? changes.name : rowData.name,
				note: changes.note ? changes.note : rowData.note,
				singer: changes.singer ? changes.singer : rowData.singer
			};
		},
		toolbar: [{
			iconCls: 'icon-add',
			text: '添加',
			handler: function() {
				addHandler();
			}
		}, '-', {
			iconCls: 'icon-edit',
			text: '修改',
			handler: function() {
				editHandler();
			},
		}, "-", {
			iconCls: "icon-save",
			text: "保存",
			handler: function() {
				saveHandler();
			}
		}, "-", {
			iconCls: "icon-cancel",
			text: "取消",
			handler: function() {
				cancelHandler();
			}
		}, '-', {
			iconCls: 'icon-ok',
			text: '导出',
			handler: function() {
				exportHandler();
			}
		}, '-', {
			iconCls: 'icon-delete',
			text: '删除',
			handler: function() {
				deleteHandler();
			}
		}, '-', {
			iconCls: 'icon-reload',
			text: '切换版本',
			handler: function() {
				location.href = "./easyui-crud-dialog.html";
			}
		}],
		columns: [[
			{field: 'id', title: 'id', width: 200},
			{field: 'name', title: 'name', width: 200, editor: "textbox"},
			{field: 'singer', title: 'singer', width: 200, editor: "textbox"},
			{field: 'note', title: 'note', width: 200, editor: "textbox"},
			{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']
	}]);

});

删除功能

删除功能功能很简单,选中一行,点击删除按钮即可,删除之前弹出询问框,点击确定就会发送ajax get请求到后台接口,完成数据删除,删除完成后接口正常返回200,则刷新表格。

function deleteHandler() {
	let rowData = $("#song_list").datagrid("getSelected");
	
	if (rowData) {
		$.messager.confirm("系统确认", "删除后数据无法恢复,是否确认删除?", function(bool) {
			if (bool) {
				$.get(base + "/song/deleteById/" + rowData.id, {}, function(res) {
					if(res.code === 200) {
						$.messager.show({
							title: '系统消息',
							timeout: 5000,
							showType: 'slide',
							msg: res.message,
						});
										
						$("#song_list").datagrid("reload");
					} else {
						$.messager.alert("系统提示", res.message, "error");
					}
				}, "json");
			}
		});
	} else {
		$.messager.alert("系统提示", "请选择要删除的数据!", "warning");
	}
}

3、条件查询功能

最后,要实现表格数据的条件查询功能,在这里通过表格过滤来实现这个功能,需要引入额外的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];
			
function addHandler() {
	requestUrl = "/song/insert";
	
	$.post(base + requestUrl, {
		name: "*****",
		singer: "*****",
		note: "*****"
	}, function (res) {
		if(res.code === 200) {
			$.messager.show({
				title: '系统消息',
				timeout: 5000,
				showType: 'slide',
				msg: res.message,
			});
			
			$("#song_list").datagrid("reload");
		} else {
			$.messager.alert("系统提示", res.message, "error");
		}
	}, "json");
}

function editHandler() {
	let datagrid = $("#song_list");

	if (editingId != null && editingId !== "") {
		datagrid.datagrid("selectRow", editingId);
	} else {
		let row = datagrid.datagrid("getSelected");
		
		if (row) {
			// 获取行索引,这个索引从0开始
			let rowIndex = datagrid.datagrid("getRowIndex", row);
			
			editingId = rowIndex;
			requestUrl = "/song/updateById";

			datagrid.datagrid("beginEdit", rowIndex);
		}
	}
}

function saveHandler() {
	if (editingId) {
		// 只有结束编辑才能获取到最新的值
		$("#song_list").datagrid("endEdit", editingId);
	
		$.post(base + requestUrl, data, function (res) {
			if(res.code === 200) {
				$.messager.show({
					title: '系统消息',
					timeout: 5000,
					showType: 'slide',
					msg: res.message,
				});
				
				editingId = "";
			} else {
				$.messager.alert("系统提示", res.message, "error");
			}
		}, "json");
	}
}

function cancelHandler() {
	// editingId != null条件防止刷新页面带来的问题
	if (editingId != null && editingId !== "") {
		$("#song_list").datagrid("cancelEdit", editingId);
	
		editingId = "";
	}
}

function deleteHandler() {
	let rowData = $("#song_list").datagrid("getSelected");
	
	if (rowData) {
		$.messager.confirm("系统确认", "删除后数据无法恢复,是否确认删除?", function(bool) {
			if (bool) {
				$.get(base + "/song/deleteById/" + rowData.id, {}, function(res) {
					if(res.code === 200) {
						$.messager.show({
							title: '系统消息',
							timeout: 5000,
							showType: 'slide',
							msg: res.message,
						});
										
						$("#song_list").datagrid("reload");
					} else {
						$.messager.alert("系统提示", res.message, "error");
					}
				}, "json");
			}
		});
	} else {
		$.messager.alert("系统提示", "请选择要删除的数据!", "warning");
	}
}

$(document).ready(function() {		
	let datagrid = $("#song_list").datagrid({
		url: base + "/song/selectByPage",
		title: "歌曲列表",
		fitColumns: true,
		striped: true,
		height: 777,
		pagination: true,
		pageSize: pageList[0],
		pageList: pageList,
		remoteFilter: true,
		clientPaging: false,
		loadFilter: function(res) {
			if (res.code === 200) {
				return res.data;
			} else {
				return null;
			}
		},
		toolbar: [{
			iconCls: 'icon-add',
			text: '添加',
			handler: function() {
				addHandler();
			}
		}, '-', {
			iconCls: 'icon-edit',
			text: '修改',
			handler: function() {
				editHandler();
			},
		}, "-", {
			iconCls: "icon-save",
			text: "保存",
			handler: function() {
				saveHandler();
			}
		}, "-", {
			iconCls: "icon-cancel",
			text: "取消",
			handler: function() {
				cancelHandler();
			}
		}, '-', {
			iconCls: 'icon-delete',
			text: '删除',
			handler: function() {
				deleteHandler();
			}
		}],
		columns: [[
			{field: 'id', title: 'id', width: 200},
			{field: 'name', title: 'name', width: 200, editor: "textbox"},
			{field: 'singer', title: 'singer', width: 200, editor: "textbox"},
			{field: 'note', title: 'note', width: 200, editor: "textbox"},
			{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;
}

Operator

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

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

添加fastjson依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.9</version>
        <relativePath />
    </parent>

    <groupId>com.example</groupId>
    <artifactId>springboot-crud</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-crud</name>
    <description>springboot+mybatis+mybatis-plus实现增删查改项目</description>

    <properties>
        <java.version>1.8</java.version>
        <mysql.version>8.0.28</mysql.version>
        <druid.version>1.1.21</druid.version>
        <lombok.version>1.18.22</lombok.version>
        <mybatis.version>2.2.2</mybatis.version>
        <fastjson.version>2.0.8</fastjson.version>
        <mybatis-plus.version>3.5.1</mybatis-plus.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--validation-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

        <!--lombok:自动生成getter、setter工具-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>

        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!--druid数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>

        <!--spring boot整合mybatis的依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>

        <!--spring boot整合mybatis-plus的依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

StringToListOfFilterRuleConverter.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类值统一处理过滤

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 java.util.List;

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

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

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

    /**
     * 根据Pager创建Page对象
     * @param pager Pager
     * @return Page
     */
    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 = toLower(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;
    }

    /**
     * 驼峰命名转下划线命名
     * @param str 待转换的字符串
     * @return String
     */
    private static String toLower(String str) {
        // 小写和大写紧挨一起的地方加上分隔符_,然后全部转为小写
        str = str.replaceAll("([a-z])([A-Z])", "$1_$2");

        return str.toLowerCase();
    }

}

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;

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

    // ...其它代码

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

        return songMapper.selectPage(page, wrapper);
    }

}

4、字段排序功能

easyui同样支持字段排序功能,而且支持多个字段的排序。

修改前端的代码,在需要排序的列后面增加sortable: true的选项

例如,开启lastUpdateTime字段的排序,排序时请求会额外添加两个参数sort和order。

当多个字段同时排序时,sort的值为多个字段通过逗号拼接成的字符串,order的值为多个字段的排序方式通过逗号拼接成的字符串。 比如:

{
    sort: "name,singer",
    order: "asc,desc"
}

前端代码

在表格的lastUpdateTime字段选项添加sortable: true

let editingId;
let requestUrl;
let base = "http://localhost:8083";
let pageList = [20, 50, 100, 500, 1000];

let data = {};
			
function addHandler() {
	requestUrl = "/song/insert";
	
	$.post(base + requestUrl, {
		name: "*****",
		singer: "*****",
		note: "*****"
	}, function (res) {
		if(res.code === 200) {
			$.messager.show({
				title: '系统消息',
				timeout: 5000,
				showType: 'slide',
				msg: res.message,
			});
			
			$("#song_list").datagrid("reload");
		} else {
			$.messager.alert("系统提示", res.message, "error");
		}
	}, "json");
}

function editHandler() {
	let datagrid = $("#song_list");

	if (editingId != null && editingId !== "") {
		datagrid.datagrid("selectRow", editingId);
	} else {
		let row = datagrid.datagrid("getSelected");
		
		if (row) {
			// 获取行索引,这个索引从0开始
			let rowIndex = datagrid.datagrid("getRowIndex", row);
			
			editingId = rowIndex;
			requestUrl = "/song/updateById";

			datagrid.datagrid("beginEdit", rowIndex);
		}
	}
}

function saveHandler() {
	if (editingId != null && editingId !== "") {
		// 只有结束编辑才能获取到最新的值
		$("#song_list").datagrid("endEdit", editingId);
	
		$.post(base + requestUrl, data, function (res) {
			if(res.code === 200) {
				$.messager.show({
					title: '系统消息',
					timeout: 5000,
					showType: 'slide',
					msg: res.message,
				});
				
				editingId = "";
			} else {
				$.messager.alert("系统提示", res.message, "error");
			}
		}, "json");
	}
}

function cancelHandler() {
	// editingId != null条件防止刷新页面带来的问题
	if (editingId != null && editingId !== "") {
		$("#song_list").datagrid("cancelEdit", editingId);
	
		editingId = "";
	}
}

function exportHandler() {
	location.href = base + "/song/export";
}

function deleteHandler() {
	let rowData = $("#song_list").datagrid("getSelected");
	
	if (rowData) {
		$.messager.confirm("系统确认", "删除后数据无法恢复,是否确认删除?", function(bool) {
			if (bool) {
				$.get(base + "/song/deleteById/" + rowData.id, {}, function(res) {
					if(res.code === 200) {
						$.messager.show({
							title: '系统消息',
							timeout: 5000,
							showType: 'slide',
							msg: res.message,
						});
										
						$("#song_list").datagrid("reload");
					} else {
						$.messager.alert("系统提示", res.message, "error");
					}
				}, "json");
			}
		});
	} else {
		$.messager.alert("系统提示", "请选择要删除的数据!", "warning");
	}
}

$(document).ready(function() {		
	let datagrid = $("#song_list").datagrid({
		url: base + "/song/selectByPage",
		title: "歌曲列表",
		height: 810,
		striped: true,
		fitColumns: true,
		singleSelect: true,
		pagination: true,
		pageSize: pageList[0],
		pageList: pageList,
		remoteFilter: true,
		remoteSort: true,
		multiSort: true,
		clientPaging: false,
		loadFilter: function(res) {
			if (res.code === 200) {
				return res.data;
			} else {
				return null;
			}
		},
		onAfterEdit: function (rowIndex, rowData, changes) { // 结束行内编辑事件
			data = {
				id: rowData.id,
				name: changes.name ? changes.name : rowData.name,
				note: changes.note ? changes.note : rowData.note,
				singer: changes.singer ? changes.singer : rowData.singer
			};
		},
		toolbar: [{
			iconCls: 'icon-add',
			text: '添加',
			handler: function() {
				addHandler();
			}
		}, '-', {
			iconCls: 'icon-edit',
			text: '修改',
			handler: function() {
				editHandler();
			},
		}, "-", {
			iconCls: "icon-save",
			text: "保存",
			handler: function() {
				saveHandler();
			}
		}, "-", {
			iconCls: "icon-cancel",
			text: "取消",
			handler: function() {
				cancelHandler();
			}
		}, '-', {
			iconCls: 'icon-ok',
			text: '导出',
			handler: function() {
				exportHandler();
			}
		}, '-', {
			iconCls: 'icon-delete',
			text: '删除',
			handler: function() {
				deleteHandler();
			}
		}, '-', {
			iconCls: 'icon-reload',
			text: '切换版本',
			handler: function() {
				location.href = "./easyui-crud-dialog.html";
			}
		}],
		columns: [[
			{field: 'id', title: 'id', width: 200},
			{field: 'name', title: 'name', width: 200, editor: "textbox"},
			{field: 'singer', title: 'singer', width: 200, editor: "textbox"},
			{field: 'note', title: 'note', width: 200, editor: "textbox"},
			{field: 'lastUpdateTime', title: 'lastUpdateTime', width: 200, sortable: true}
		]]
	});
	
	datagrid.datagrid('enableFilter', [{
		field: 'name',
		type: 'textbox',
		op: ['equal', 'contains']
	}, {
		field: 'singer',
		type: 'textbox',
		op: ['equal', 'contains'],
	}, {
		field: 'note',
		type: 'textbox',
		op: ['equal', 'contains']
	}]);

});

后端代码

根据请求的参数格式,定义一个Sorter类,该类中定义sort和order两个属性,并实现处理排序的方法。

Sorter
package com.example.springboot.base;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.springboot.exception.GlobalException;
import com.example.springboot.restful.ResponseCode;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;

/**
 * 基础排序对象,包含排序字段和排序方式
 * @author heyunlin
 * @version 1.0
 */
@Data
public class Sorter {

    /**
     * 空字符串
     */
    private static final String EMPTY_STR = "";

    /**
     * 分割符
     */
    private static final String SEPARATOR = ",";

    /**
     * 排序方式
     */
    private static final List<String> ORDER_STYLES = new ArrayList<>(2);

    static {
        ORDER_STYLES.add("asc");
        ORDER_STYLES.add("desc");
    }

    /**
     * 排序字段
     */
    private String sort;

    /**
     * 排序方式:asc/desc
     */
    private String order;

    /**
     * 根据查询条件拼接得到order by语句
     * @param sorter 分页查询条件
     * @return String
     */
    public static String getStatement(Sorter sorter) {
        String sort;
        String sortColumn = sorter.getSort();

        // 处理排序字段
        String[] sortArray = {};

        if (StringUtils.isNotEmpty(sortColumn)) {
            // 驼峰命名转为下划线
            sort = toLower(sortColumn);

            if (sort.contains(SEPARATOR)) {
                sortArray = sort.split(SEPARATOR);
            }
        } else {
            return EMPTY_STR;
        }

        // 处理排序方式
        String[] orderArray = {};
        String order = sorter.getOrder();

        if (StringUtils.isNotEmpty(order)) {
            if (order.contains(SEPARATOR)) {
                orderArray = order.split(SEPARATOR);
            }
        } else {
            return EMPTY_STR;
        }

        StringBuilder statement = new StringBuilder();

        if (sortArray.length > 0 && orderArray.length > 0) {
            int length = sortArray.length;

            for (int i = 0; i < length; i++) {
                String pagerSort = sortArray[i];
                String pagerOrder = orderArray[i];

                boolean result = validate(pagerSort, pagerOrder);

                if (result) {
                    statement.append(pagerSort);
                    statement.append(" ");
                    statement.append(pagerOrder);

                    if (i < length - 1 ) {
                        statement.append(", ");
                    }
                }
            }
        } else {
            // " #{sort} #{order}“
            statement.append(sort);
            statement.append(" ");
            statement.append(order);
        }

        return statement.toString();
    }

    /**
     * 根据查询条件拼接得到order by语句
     * @param sorter 分页查询条件
     * @return String
     */
    public static String getOrderByStatement(Sorter sorter) {
        String statement = getStatement(sorter);

        if (StringUtils.isNotEmpty(statement)) {
            return " order by " + statement;
        } else {
            return EMPTY_STR;
        }
    }

    /**
     * 往Pager的排序字段中添加排序
     * @param pager Pager Pager对象
     * @param sort String 排序字段
     * @param order String 排序方式
     * @return Pager<?> 返回重新设置排序字段和排序方式后的Pager对象
     */
    public static Pager<?> append(Pager<?> pager, String sort, String order) {
        boolean result = validatePager(pager);

        if (result) {
            String pagerSort = pager.getSort();
            String pagerOrder = pager.getOrder();

            pager.setSort(pagerSort.concat(SEPARATOR).concat(sort));
            pager.setOrder(pagerOrder.concat(SEPARATOR).concat(order));

            return pager;
        }

        return null;
    }

    /**
     * 验证Pager对象的sort和order的值是否合法
     * @param pager Pager<?>
     * @return boolean
     */
    private static boolean validatePager(Pager<?> pager) {
        String sort = pager.getSort();
        String order = pager.getOrder();

        return validate(sort, order);
    }

    /**
     * 验证sort和order的值是否合法
     * @param sort 排序字段
     * @param order 排序方式
     * @return boolean
     */
    private static boolean validate(String sort, String order) {
        if (StringUtils.isEmpty(sort)) {
            throw new GlobalException(ResponseCode.FORBIDDEN, "排序字段不允许为空!");
        } else if (StringUtils.isEmpty(order)) {
            throw new GlobalException(ResponseCode.FORBIDDEN, "排序方式不允许为空!");
        } else if(!ORDER_STYLES.contains(order.toLowerCase())) {
            throw new GlobalException(ResponseCode.FORBIDDEN, "排序方式不合法!");
        }

        return true;
    }

    /**
     * 驼峰命名转下划线命名
     * @param str 待转换的字符串
     * @return String
     */
    private static String toLower(String str) {
        // 小写和大写紧挨一起的地方加上分隔符_,然后全部转为小写
        str = str.replaceAll("([a-z])([A-Z])", "$1_$2");

        return str.toLowerCase();
    }

}

Pager

让Pager类继承自Sorter

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
 */
@EqualsAndHashCode(callSuper = true)
@Data
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
     */
    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 = toLower(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;
    }

    /**
     * 驼峰命名转下划线命名
     * @param str 待转换的字符串
     * @return String
     */
    private static String toLower(String str) {
        // 小写和大写紧挨一起的地方加上分隔符_,然后全部转为小写
        str = str.replaceAll("([a-z])([A-Z])", "$1_$2");

        return str.toLowerCase();
    }

}

SongServiceImpl

最后,修改分页查询的实现代码,添加获取order by语句,并设置到查询条件的代码。


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

        // 得到order by语句
        if (wrapper != null) {
            String statement = Sorter.getOrderByStatement(songPagerDTO);
            wrapper.last(statement);
        }

        return songMapper.selectPage(page, wrapper);
    }

至此,字段排序功能也完成了,但是测试发现了一个小问题,并没有排序

,原来是因为Pager的getQueryWrapper()方法在没有过滤条件的时候会返回null,导致排序语句并没有设置进去。

Pager

于是再次修改Pager.getQueryWrapper(),让方法返回一个非空的对象。

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
 */
@EqualsAndHashCode(callSuper = true)
@Data
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
     */
    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();
        QueryWrapper<T> wrapper = new QueryWrapper<>();

        if (filterRules != null && !filterRules.isEmpty()) {
            for (FilterRule filterRule : filterRules) {
                // 字段名:转为小写字母+下划线的格式
                String field = toLower(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;
    }

    /**
     * 驼峰命名转下划线命名
     * @param str 待转换的字符串
     * @return String
     */
    private static String toLower(String str) {
        // 小写和大写紧挨一起的地方加上分隔符_,然后全部转为小写
        str = str.replaceAll("([a-z])([A-Z])", "$1_$2");

        return str.toLowerCase();
    }

}

SongServiceImpl

同时,删除SongServiceImpl中null判断的代码

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

        // 得到order by语句
        String statement = Sorter.getOrderByStatement(songPagerDTO);
        wrapper.last(statement);

        return songMapper.selectPage(page, wrapper);
    }

至此,排序功能圆满完成~

代码改进

基于上面的功能,又设置了一个小小的改进,提高代码复用。

Pager

添加一个参数,控制要不要在这里处理排序。

为什么要设置这样一个参数呢?

  • 提高扩展性:有些情况下未必在Pager的这个方法内就能确定需要通过哪些字段排序,比如我在某个查询接口想要设置默认的字段排序,而每个表的字段不相同,可能设置的默认排序字段就无法动态确定了,只有在实际业务的Service层代码中指定。
  • 提高代码复用:当不需要设置默认排序时,enableSort设置为true即可,此时就实现了一个排序功能的统一处理。
    /**
     * 根据Pager创建QueryWrapper对象
     * @param pager Pager
     * @return QueryWrapper<T>
     */
    public static <T> QueryWrapper<T> getQueryWrapper(Pager<T> pager, boolean enableSort) {
        List<FilterRule> filterRules = pager.getFilterRules();
        QueryWrapper<T> wrapper = new QueryWrapper<>();

        if (filterRules != null && !filterRules.isEmpty()) {
            for (FilterRule filterRule : filterRules) {
                // 字段名:转为小写字母+下划线的格式
                String field = toLower(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;
                }
            }
        }
        
        if (enableSort) {
            // 得到order by语句
            String statement = getOrderByStatement(pager);
            wrapper.last(statement);
        }

        return wrapper;
    }

SongServiceImpl

修改了Pager的方法,对应的selectByPage()代码也要多传一个参数。

并且删除排序的处理代码:

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

        return songMapper.selectPage(page, wrapper);
    }

5、数据导出功能

前端代码

只需要在表格的头部工具栏中添加一个【导出】的按钮。

后端代码
添加依赖

pom.xml中添加easyexcel的maven依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.2</version>
</dependency>

SongController

在SongController中新增一个接口方法export()

    @RequestMapping(value = "/export", method = RequestMethod.GET)
    public void export(HttpServletResponse response) {
        songService.export(response);
    }

SongService

SongService接口中新增export()抽象方法

package com.example.springboot.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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 javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * @author heyunlin
 * @version 1.0
 */
public interface SongService {

    void insert(SongInsertDTO songInsertDTO);

    void deleteById(String id);

    void updateById(SongUpdateDTO updateDTO);

    Song selectById(String id);

    List<Song> selectList();

    Page<Song> selectByPage(SongPagerDTO songPagerDTO);

    void export(HttpServletResponse response);
}

SongServiceImpl

实现export()方法

    @Override
    public void export(HttpServletResponse response) {
        String fileName = "songs.xlsx";

        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

        try {
            List<Song> songs = songMapper.selectList(null);

            EasyExcel.write(response.getOutputStream(), Song.class).sheet("歌曲列表").doWrite(songs);
        } catch (Exception e) {
            e.printStackTrace();

            response.reset();
            response.setContentType("application/json;charset=utf-8");
            JsonResult<Void> jsonResult = JsonResult.success("数据导出异常");

            try {
                response.getWriter().write(jsonResult.toString());
            } catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }
    }

最后的页面效果如下:

好了,文章就分享到这里了,博主也是非常用心的创作,这篇文章总结了easyui实现数据管理所涉及的几乎所有常用功能,看完这篇文章不要忘了点赞+收藏哦~


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

  • 前端项目地址:

使用easyui前端框架构建一个crud应用icon-default.png?t=N7T8https://gitcode.net/heyl163_/easyui-crud.git

  • 后端项目地址:

springboot+mybatis实现增删查改的入门项目。icon-default.png?t=N7T8https://gitee.com/he-yunlin/springboot-crud.git


  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用EasyUI框架来创建一个简单的前端文件资源管理系统。以下是一个基本的示例: ```html <!DOCTYPE html> <html> <head> <title>文件资源管理系统</title> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-easyui/1.9.21/themes/default/easyui.css"> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easyui/1.9.21/jquery.easyui.min.js"></script> </head> <body> <h2>文件资源管理系统</h2> <table id="fileTable" class="easyui-datagrid" style="width:500px;height:300px" url="get_files.php" toolbar="#toolbar" pagination="true" rownumbers="true" fitColumns="true"> <thead> <tr> <th field="name" width="50%">文件名</th> <th field="size" width="30%">大小</th> <th field="dateModified" width="20%">修改日期</th> </tr> </thead> </table> <div id="toolbar"> <a href="#" class="easyui-linkbutton" iconCls="icon-add" plain="true">上传文件</a> <a href="#" class="easyui-linkbutton" iconCls="icon-edit" plain="true">重命名</a> <a href="#" class="easyui-linkbutton" iconCls="icon-remove" plain="true">删除文件</a> </div> <script type="text/javascript"> $(function(){ $('#fileTable').datagrid({}); }); </script> </body> </html> ``` 上述代码中,我们使用EasyUI框架的DataGrid组件来展示文件列表。通过设置`url`属性,可以指定从服务器获取文件数据的接口(例如`get_files.php`)。在工具栏中,我们添加了上传文件、重命名和删除文件的按钮。 请注意,这只是一个简单的前端示例,没有后端支持。你需要自己实现服务器端的文件管理逻辑,并提供相应的接口供前端调用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值