# easyui-admin
**Repository Path**: muyu-chengfeng/easyui-admin
## Basic Information
- **Project Name**: easyui-admin
- **Description**: Spring Boot + JQuery版EasyUI前端框架实现的管理系统项目
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 12
- **Forks**: 5
- **Created**: 2024-06-20
- **Last Updated**: 2025-09-21
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# easyui-admin
## 一、项目介绍
Spring Boot + JQuery版EasyUI前端框架实现的管理系统项目。
## 二、技术介绍
### 1、后端技术
| 技术 | 说明 | 官网 |
| ------------ | ---------------- | ------------------------------------------- |
| Spring Boot | 容器+MVC框架 | https://spring.io/projects/spring-boot |
| Apache Shiro | 认证和授权框架 | https://shiro.apache.org/ |
| MyBatis | ORM框架 | https://blog.mybatis.org/ |
| MyBatis-Plus | MyBatis增强工具 | https://www.baomidou.com/ |
| Knife4j | 接口文档生成工具 | https://doc.xiaominfo.com/docs/quick-start/ |
| Redis | 分布式缓存数据库 | https://redis.io/ |
| Fastjson | 序列化工具 | https://github.com/alibaba/fastjson |
| Easy Excel | 操作excel的工具 | https://easyexcel.opensource.alibaba.com/ |
### 2、前端技术
| 技术 | 说明 | 官网 |
| -------------- | ------------ | ----------------------------- |
| JQuery版Easyui | 前端UI框架 | https://www.jeasyui.cn/ |
| JQuery | Javascript库 | https://jquery.com/ |
| HTML | 网页编程语言 | https://html.com/ |
| CSS | 网页样式语言 | https://www.w3.org/Style/CSS/ |
## 三、功能介绍
### 1、数据过滤
基于easyui的js插件实现的表格数据过滤功能。
#### 第一步
在页面引入easyui目录下的datagrid-filter.js
```html
```
#### 第二步
在渲染数据网格datagrid(easyui表格)时指定两个选项,通过enableFilter方法设置哪些列需要开启过滤功能。
```js
const datagrid = $(selector).datagrid({
// 其他选项...
remoteFilter: true, // 开启远程过滤
clientPaging: false, // 关闭客户端分页
});
datagrid.datagrid("enableFilter", [{
field: "name", // 表格字段名
type: "textbox", // 组件类型名称
operator: ["equal", "contains"] // 展示的过滤选项
}]);
```
#### 实现原理
easyui datagrid组件的remoteFilter选项设置为true时,当使用过滤功能时,请求的URL会携带名为filterRules参数。
filterRules参数的格式是一个json数组的字符串,后端通过Spring的转换器将其转为List类型。
然后通过Pager类的getQueryWrapper()方法统一处理过滤的请求参数,并设置到QueryWrapper中。
```java
/**
* 根据Pager创建QueryWrapper对象
* @param pager Pager
* @return QueryWrapper
*/
public static QueryWrapper getQueryWrapper(Pager pager, boolean enableSort) {
QueryWrapper queryWrapper = new QueryWrapper<>();
List filterRules = pager.getFilterRules();
if (CollectionUtils.isNotEmpty(filterRules)) {
for (FilterRule filterRule : filterRules) {
// 字段名:转为小写字母+下划线的格式
String field = StringUtils.toLower(filterRule.getField());
// 字段值
String value = filterRule.getValue();
if (StringUtils.isNotEmpty(value)) {
switch (filterRule.getOperator()) {
case less:
queryWrapper.lt(field, value);
break;
case equal:
queryWrapper.eq(field, value);
break;
case greater:
queryWrapper.gt(field, value);
break;
case notequal:
queryWrapper.ne(field, value);
break;
case lessorequal:
queryWrapper.le(field, value);
break;
case greaterorequal:
queryWrapper.ge(field, value);
break;
case beginwith:
queryWrapper.likeLeft(field, value);
break;
case endwith:
queryWrapper.likeRight(field, value);
break;
case contains:
queryWrapper.like(field, value);
break;
default:
break;
}
}
}
}
if (enableSort) {
// 得到order by语句
String statement = getOrderByStatement(pager);
if (StringUtils.isNotEmpty(statement)) {
queryWrapper.last(statement);
}
}
return queryWrapper;
}
```
详情参考文件/js/menu_list.js和MenuServiceImpl类的selectByPage()方法。
```
cn.edu.sgu.www.easyui.service.impl.MenuServiceImpl#selectByPage()
```
##### FilterRule.java
```java
package cn.edu.sgu.www.easyui.support;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 过滤规则
* @author 沐雨橙风ιε
* @version 1.0
*/
@Data
@ApiModel
public class FilterRule implements Serializable {
private static final long serialVersionUID = 18L;
/**
* 字段名
*/
@ApiModelProperty(value = "字段名")
private String field;
/**
* 字段值
*/
@ApiModelProperty(value = "字段值")
private String value;
/**
* 比较符
*/
@ApiModelProperty(value = "比较符")
private Operator operator;
}
```
##### Operator.java
```java
package cn.edu.sgu.www.easyui.support;
/**
* 比较符
* @author 沐雨橙风ιε
* @version 1.0
*/
public enum Operator {
/**
* 包含
*/
contains,
/**
* 等于
*/
equal,
/**
* 不等于
*/
notequal,
/**
* 以...开始
*/
beginwith,
/**
* 以...结尾
*/
endwith,
/**
* 小于
*/
less,
/**
* 小于或等于
*/
lessorequal,
/**
* 大于
*/
greater,
/**
* 大于或等于
*/
greaterorequal
}
```
##### StringToListOfFilterRuleConverter.java
```java
package cn.edu.sgu.www.easyui.converter;
import cn.edu.sgu.www.easyui.support.FilterRule;
import com.alibaba.fastjson.JSON;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* String ==> List的转换器
* @author 沐雨橙风ιε
* @version 1.0
*/
@Component
public class StringToListOfFilterRuleConverter implements Converter> {
@Override
public List convert(@NonNull String source) {
return JSON.parseArray(source, FilterRule.class);
}
}
```
### 2、权限控制
基于RBAC模型实现的访问控制功能,通过一个过滤器PermsFilter完成鉴权。
```java
package cn.edu.sgu.www.easyui.shiro.filter;
import cn.edu.sgu.www.easyui.consts.ContentTypes;
import cn.edu.sgu.www.easyui.restful.JsonResult;
import cn.edu.sgu.www.easyui.restful.ResponseCode;
import cn.edu.sgu.www.easyui.util.HttpUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 定义PermsFilter过滤器(覆盖shiro的perms过滤器)
* @author 沐雨橙风ιε
* @version 1.0
*/
@Slf4j
@WebFilter
public class PermsFilter extends PermissionsAuthorizationFilter {
@Override
public boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object mappedValue) throws IOException {
boolean accessAllowed = super.isAccessAllowed(req, resp, mappedValue);
// 未授权的处理
if (!accessAllowed) {
// 获取HttpServletRequest对象
HttpServletRequest request = (HttpServletRequest) req;
// 定义错误消息
String errorMessage = "正在访问未授权的资源:" + request.getRequestURI();
log.error(errorMessage);
ResponseCode responseCode = ResponseCode.UNAUTHORIZED;
// 获取HttpServletResponse对象
HttpServletResponse response = HttpUtils.getResponse();
response.setStatus(responseCode.getValue());
response.setContentType(ContentTypes.APPLICATION_JSON_CHARSET_UTF_8);
// 构建返回对象
JsonResult jsonResult = JsonResult.error(responseCode, errorMessage);
try (PrintWriter writer = response.getWriter()) {
writer.write(JSON.toJSONString(jsonResult));
} catch (Exception e) {
e.printStackTrace();
}
}
return true; // 返回true,防止shiro重复处理未授权的访问
}
}
```
### 3、菜单管理
通过role_menu表实现:基于角色的菜单管理功能,菜单直接分配给角色;
通过user_menu表实现:用户可以自定义展示哪些菜单,勾选则代表显示,取消勾选则隐藏(在用户的角色菜单的基础上自定义)。

### 4、隐藏表格列
支持隐藏列的记忆功能,下次打开页面,之前操作设置隐藏的列不会显示在表格中。
在需要使用隐藏列功能的页面中引入classpath下的/js/columnMenu.js
```html
```
通过给表格增加一个onLoadSuccess事件来实现,在使用时,修改选择器的值为对应表格的ID选择器。
```js
// 给表格头部添加鼠标右键点击事件
onHeaderContextMenu: function(e){
e.preventDefault();
if (!columnMenu){
createColumnMenu("#permission_list");
}
columnMenu.menu("show", {
left: e.pageX,
top: e.pageY
});
},
onLoadSuccess: function () {
let selector = "#permission_list";
let fields = getFields(selector);
if (fields.length > 0) {
let datagrid = $(selector);
for (let i = 0; i < fields.length; i++) {
let field = fields[i];
// 隐藏未选中的字段
if (!field.selected) {
datagrid.datagrid("hideColumn", field.name);
}
}
datagrid.datagrid("fitColumns");
}
},
```
更多代码详情,参考src/main/resources/static/js/permission_list.js
## 四、常见问题
### 问题1
不小心把用户对应角色的权限管理相关的权限取消了,导致访问权限管理相关接口失败,无法重新为角色分配权限管理功能的权限。
把system.settings.enable-authorization设置为false,然后重启项目,为角色分配完权限之后,再恢复成true
```yaml
system:
settings:
enable-authorization: true # 是否开启鉴权
```
### 问题2
pom.xml文件报错,父依赖找不到
```xml
20250901
cn.edu.sgu.www
springcloud-parent
```
在Intellij IDEA中,通过Git拉取这个项目到本地
```
https://gitee.com/muyu-chengfeng/springcloud-parent.git
```
使用maven插件将项目到本地仓库,然后刷新当前项目的maven依赖。
