分享一个基于easyui前端框架开发的后台管理系统模板

这是博主自己在使用的一套easyui前端框架的后台管理系统模版,包含了后端的Java代码,已经实现了菜单控制、权限控制功能,可以直接拿来使用。

springboot + mybatis + mybatis-plus实现的增删查改完整项目,前端使用了easyui前端框架。icon-default.png?t=N7T8https://gitee.com/he-yunlin/easyui-crud.git

目录

功能介绍

一、菜单管理

菜单列表

角色-菜单列表

二、权限管理

权限列表

角色-权限列表

三、用户管理

用户列表

用户-角色列表

四、歌曲管理

歌曲列表

五、系统功能

系统设置

初始化权限

代码介绍

响应状态码

统一响应实体类

全局异常处理类

统一数据格式处理类

datagrid数据格式对象

获取用户登录信息的工具类

基于easyui的表格过滤插件功能实现

基础的分页器

基础的排序器


功能介绍

这是对本系统的一些简单的功能介绍。

一、菜单管理

菜单列表

点击表格头部工具栏的【添加】按钮,会添加一条模板数据

/*** 添加*/
function insert() {requestUrl = "/menu/insert";ajaxPost(requestUrl, {type: 1,name: "xxx",url: "/html/xxx_list.html",icon: "icon-script"}, function (response) {showMsg(response.message);$("#menu_list").datagrid("reload");}, error);
}

修改功能是基于easyui的表格行内编辑完成的,鼠标选择一行数据,点击头部工具栏的【修改】按钮,会开启该行的编辑。

点击保存会向后台控制器提交修改后的数据,点击取消则只会取消行内编辑。

通过给表格添加结束编辑事件,当表格行结束编辑,也就是调用了endEdit方法时触发事件,会把data修改为修改后的行数据。

let data = {};/*** 保存*/
function save() {if (editingId != null) {let datagrid = $("#menu_list");// 只有结束编辑才能获取到最新的值datagrid.datagrid("endEdit", editingId);ajaxPost(requestUrl, data, function () {editingId = null;datagrid.datagrid("reload");}, error);}
}$(document).ready(function() {    $("#menu_list").datagrid({url: "/menu/selectByPage",method: "get",height: 680,fitColumns: true,pagination: true,onAfterEdit: function (index, row, changes) {data = {id: row.id,type: row.type,parentId: row.parentId,url: changes.url ? changes.url : row.url,name: changes.name ? changes.name : row.name,icon: changes.icon ? changes.icon : row.icon};},.....};};

删除功能比较简单,就不介绍了~

角色-菜单列表

就是对角色的菜单进行管理,目前只是基于父级菜单实现,只需要给角色添加对应的父类菜单即可让该角色获得该菜单下的所有子菜单的权限。

二、权限管理

权限列表

对系统资源权限(也就是控制器接口权限)进行管理

父级权限的编号格式为为服务名_控制器名,子级权限的编号为服务名_控制器名_方法名。

权限初始化功能:一键自动完成权限的初始化功能,会先删除原来的权限,然后扫描控制器类的包,获取所有控制器接口信息,并保存到数据库。

涉及的后端代码

    @Overridepublic void resources() throws ClassNotFoundException {// 删除原来的权限permissionMapper.delete(null);// 扫描路径String basePackage = "cn.edu.sgu.www.controller";// 获取扫描结果List<Permission> permissions = resourceScanner.scan(basePackage);for (Permission permission : permissions) {permissionMapper.insert(permission);}}

扫描工具类的代码

package cn.edu.sgu.www.util;import cn.edu.sgu.www.EasyuiCrud;
import cn.edu.sgu.www.annotation.AnonymityAccess;
import cn.edu.sgu.www.entity.Permission;
import cn.edu.sgu.www.enums.RequestMethod;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;/*** 接口资源扫描工具类* @author heyunlin* @version 1.0*/
@Component
public class ResourceScanner {/*** 服务名*/@Value("${spring.application.name}")private String SERVICE_NAME;private static List<String> classPaths = new ArrayList<>();private static final List<Permission> resources = new ArrayList<>();/*** 扫描controller包下的目录,生成权限* @param basePackage controller包* @return List<Permission>* @throws ClassNotFoundException 类找不到时抛出异常*/public List<Permission> scan(String basePackage) throws ClassNotFoundException {// 删除掉上一次的数据if (!resources.isEmpty()) {resources.clear();}if (!classPaths.isEmpty()) {classPaths.clear();}String classpath = EasyuiCrud.class.getResource("/").getPath();String searchPath = classpath + basePackage.replace(".", "/");classpath = classpath.replaceFirst("/", "");classPaths = getClassPaths(new File(searchPath));for(String classPath : classPaths) {// 得到类的全限定名classPath = classPath.replace(classpath.replace("/", "\\").replaceFirst("\\\\", ""), "").replace("\\", ".").replace(".class", "");classpath = classPath.substring(classPath.indexOf(basePackage));// 通过反射获取类的信息Class<?> cls = Class.forName(classpath);// 获取标注在类上的@RequestMapping注解RequestMapping requestMapping = cls.getAnnotation(RequestMapping.class);// 构建父权限Permission parent = new Permission();// 控制器类上的路径String prefix = "";if(requestMapping != null) {// path或者valueprefix = requestMapping.value().length > 0 ? requestMapping.value()[0] : requestMapping.path()[0];parent.setType(0);parent.setUrl(prefix);parent.setId(SERVICE_NAME + "_" + cls.getSimpleName());// 设置nameif (cls.isAnnotationPresent(Api.class)) {Api api = cls.getAnnotation(Api.class);if (api != null) {// 类的接口文档@Api注解的tags属性值String name = api.tags()[0];parent.setName(name);}}resources.add(parent);}Method[] methods = cls.getDeclaredMethods();for (Method method : methods) {getClassAnnotation(method, prefix, cls.getSimpleName(), parent.getId());}}return resources;}/*** 得到类上面的注解信息* @param method Method* @param prefix String 控制器类上@RequestMapping注解指定的路径* @param controllerName 控制器名称* @param parentId String 父级权限ID*/public void getClassAnnotation(Method method, String prefix, String controllerName, String parentId) {// 构建子权限Permission permission = new Permission();String url = null;// 获取urlif (method.isAnnotationPresent(RequestMapping.class)) {RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);url = prefix + (requestMapping.value().length > 0 ? requestMapping.value()[0] : requestMapping.path()[0]);String requestMethod = requestMapping.method().length > 0 ? requestMapping.method()[0].name() : "get";permission.setMethod(RequestMethod.getValueByName(requestMethod));} else if (method.isAnnotationPresent(GetMapping.class)) {GetMapping getMapping = method.getAnnotation(GetMapping.class);url = prefix + getMapping.value()[0];permission.setMethod(RequestMethod.GET.getValue());} else if (method.isAnnotationPresent(PostMapping.class)) {PostMapping postMapping = method.getAnnotation(PostMapping.class);url = prefix + postMapping.value()[0];permission.setMethod(RequestMethod.POST.getValue());}// 处理URLif(url != null && url.endsWith("/")) {url = url.substring(0, url.length() - 1);}permission.setUrl(url);// 设置valueif (method.isAnnotationPresent(ApiOperation.class)) {ApiOperation operation = method.getAnnotation(ApiOperation.class);if (operation != null) {String name = operation.value();permission.setName(name);}}// 默认值0permission.setAnonymity(0);if (method.isAnnotationPresent(AnonymityAccess.class)) {AnonymityAccess annotation = method.getAnnotation(AnonymityAccess.class);if (annotation != null) {permission.setAnonymity(annotation.value() ? 1 : 0);}}permission.setType(1);permission.setParentId(parentId);permission.setId(SERVICE_NAME + "_" + controllerName + "_" + method.getName());resources.add(permission);}private List<String> getClassPaths(File path) {if (path.isDirectory()) {File[] files = path.listFiles();if (files != null) {for (File file : files) {getClassPaths(file);}}} else {if (path.getName().endsWith(".class")) {classPaths.add(path.getPath());}}return classPaths;}}

角色-权限列表

角色权限的维护,包括简单的增删改和基于easyui树实现的授权功能,以及超管账户的权限初始化功能。

授权功能:通过简单的复选框勾选/取消勾选来给角色分配权限

权限初始化功能:其实非常简单,就是查询所有的资源权限,然后分配给超管用户。

    @Overridepublic void init(String userId) {// 删除用当前户所有角色的权限rolePermissionMapper.deleteByUserId(userId);// 查询全部子权限List<Permission> list = permissionMapper.selectByType(PermissionType.ZQX.getValue());list.forEach(permission -> {RolePermission rolePermission = new RolePermission();rolePermission.setId(null);rolePermission.setRoleId(1);rolePermission.setPermissionId(permission.getId());rolePermissionMapper.insert(rolePermission);});}

三、用户管理

因为这个部分的功能很简单,只有简单的crud,不做过多介绍。

用户列表

用户-角色列表

四、歌曲管理

歌曲列表

歌曲的维护、歌单导入/导出功能。

五、系统功能

系统设置

鼠标移动到右上方的下拉菜单,点击【系统设置】打开系统设置窗口。

修改密码功能

 对密码进行加密存储

    @Overridepublic void updatePassword(UserPassUpdateDTO userPassUpdateDTO) {// 用户名String username = userPassUpdateDTO.getUsername();// 旧密码String oldPass = userPassUpdateDTO.getOldPass();// 新密码String password = userPassUpdateDTO.getPassword();// 验证两次输入的密码是否相等if (password.equals(userPassUpdateDTO.getRePass())) {// 查询用户信息String encodedPassword = selectByUsername(username).getPassword();// 验证输入的旧密码是否正确if (PasswordEncoder.matches(oldPass, encodedPassword)) {UpdateWrapper<User> wrapper = new UpdateWrapper<>();wrapper.eq("username", username);wrapper.set("password", PasswordEncoder.encode(password));userMapper.update(wrapper.getEntity(), wrapper);} else {throw new GlobalException(ResponseCode.FORBIDDEN, "输入的密码不正确");}} else {throw new GlobalException(ResponseCode.FORBIDDEN, "两次输入的密码不一样");}}

菜单控制功能:就是控制左侧菜单的显示,勾选/取消勾选对应的菜单,然后点击窗口右下角的【确定】按钮提交修改。

初始化权限

这个按钮的功能和权限列表的【初始化】按钮是一样的。

代码介绍

前面已经对这个系统做了一些简单的介绍,接下来介绍一下博主经过多次实践产出的一部分公共的Java代码,可以直接使用。

响应状态码

在枚举中自定义了几种响应状态码

package cn.edu.sgu.www.restful;/*** 响应状态码* @author heyunlin* @version 1.0*/
public enum ResponseCode {/*** 请求成功*/OK(200),/*** 失败的请求*/BAD_REQUEST(400),/*** 未授权*/UNAUTHORIZED(401),/*** 禁止访问*/FORBIDDEN(403),/*** 找不到*/NOT_FOUND(404),/*** 不可访问*/NOT_ACCEPTABLE(406),/*** 冲突*/CONFLICT(409),/*** 服务器发生异常*/ERROR(500);private final Integer value;ResponseCode(Integer value) {this.value = value;}public Integer getValue() {return value;}}

统一响应实体类

包含提示信息、响应数据和响应状态码的web响应实体类。

package cn.edu.sgu.www.restful;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;import java.io.Serializable;/*** 响应实体类* @param <T>* @author heyunlin* @version 1.0*/
@Data
public class JsonResult<T> implements Serializable {private static final long serialVersionUID = 18L;/*** 响应数据*/private T data;/*** 响应状态码*/private Integer code;/*** 响应提示信息*/private String message;/*** 成功提示*/private static final String successMessage = "请求成功";public static JsonResult<Void> success() {return success(successMessage);}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 <T> JsonResult<JsonPage<T>> restPage(Page<T> page) {JsonPage<T> jsonPage = JsonPage.restPage(page);return success(successMessage, jsonPage);}}

全局异常处理类

package cn.edu.sgu.www.restful.handler;import cn.edu.sgu.www.exception.GlobalException;
import cn.edu.sgu.www.restful.JsonResult;
import cn.edu.sgu.www.restful.ResponseCode;
import cn.edu.sgu.www.util.UserUtils;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;import javax.servlet.http.HttpServletResponse;
import java.util.Objects;/*** 全局异常处理类* @author heyunlin* @version 1.0*/
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 处理GlobalException* @param e GlobalException* @return JsonResult<Void>*/@ExceptionHandlerpublic JsonResult<Void> handleGlobalException(GlobalException e) {printMessage(e);HttpServletResponse response = UserUtils.getResponse();response.setStatus(e.getResponseCode().getValue());return JsonResult.error(e.getResponseCode(), e);}/*** 处理BindException* @param e BindException* @return JsonResult<Void>*/@ExceptionHandler@ResponseStatus(HttpStatus.BAD_REQUEST)public JsonResult<Void> handleBindException(BindException e) {printMessage(e);BindingResult bindingResult = e.getBindingResult();FieldError fieldError = bindingResult.getFieldError();String defaultMessage = Objects.requireNonNull(fieldError).getDefaultMessage();return JsonResult.error(ResponseCode.BAD_REQUEST, defaultMessage);}/*** 处理Exception* @param e Exception* @return JsonResult<Void>*/@ExceptionHandler@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)public JsonResult<Void> handleException(Exception e) {printMessage(e);return JsonResult.error(ResponseCode.ERROR, e);}private void printMessage(Exception e) {e.printStackTrace();}}

统一数据格式处理类

这个类需要注意的是,knife4j的接口路径不能被处理,否则接口文档的页面内容不能正常显示。

# 配置统一数据格式返回处理类忽略的路径
response:ignore:- /error- /v2/api-docs- /swagger-resources
package cn.edu.sgu.www.restful.handler;import cn.edu.sgu.www.config.property.ResponseProperties;
import cn.edu.sgu.www.restful.JsonResult;
import cn.edu.sgu.www.util.UserUtils;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import java.util.List;/*** 统一数据格式返回处理类* @author heyunlin* @version 1.0*/
@Slf4j
@RestControllerAdvice
public class GlobalResponseHandler implements ResponseBodyAdvice {private final List<String> ignore;@Autowiredpublic GlobalResponseHandler(ResponseProperties responseProperties) {ignore = responseProperties.getIgnore();}@Overridepublic boolean supports(MethodParameter parameter, Class type) {return true;}@Overridepublic Object beforeBodyWrite(Object body, MethodParameter parameter, MediaType mediaType, Class type, ServerHttpRequest request, ServerHttpResponse response) {// 返回值类型为JsonResult,则直接返回if (body instanceof JsonResult) {return body;}// 忽略的请求地址String requestURI = UserUtils.getRequest().getRequestURI();if (ignore.contains(requestURI)) {return body;}log.debug("接口{}的返回值为:{}", requestURI, body.toString());// 将返回值类型修改为JsonResultJsonResult<Object> jsonResult = JsonResult.success(null, body);if (body instanceof String) {return JSON.toJSONString(jsonResult);}return jsonResult;}}

datagrid数据格式对象

基于easyui的datagrid组件要求返回的数据格式,封装成的对象。

package cn.edu.sgu.www.restful;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;import java.io.Serializable;
import java.util.List;/*** easyui datagrid数据格式对象* @param <T>* @author heyunlin* @version 1.0*/
@Data
public class JsonPage<T> implements Serializable {private static final long serialVersionUID = 18L;/*** 总记录数*/private Long total;/*** 查询结果*/private List<T> rows;/*** 页脚数据*/private T footer;public static <T> JsonPage<T> restPage(Page<T> page) {JsonPage<T> jsonPage = new JsonPage<>();jsonPage.setTotal(page.getTotal());jsonPage.setRows(page.getRecords());return jsonPage;}}

获取用户登录信息的工具类

基于shiro的获取用户登录信息的工具类

package cn.edu.sgu.www.util;import cn.edu.sgu.www.entity.User;
import cn.edu.sgu.www.exception.GlobalException;
import cn.edu.sgu.www.restful.ResponseCode;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 获取用户信息的工具类* @author heyunlin* @version 1.0*/
public class UserUtils {/*** 得到Subject对象* @return Subject*/public static Subject getSubject() {return SecurityUtils.getSubject();}/*** 获取登录的用户信息* @return User*/public static User getUserInfo() {Object object =  getSubject().getPrincipal();if (object == null) {throw new GlobalException(ResponseCode.BAD_REQUEST, "获取登录信息失败,当前没有用户登录。");}return (User) object;}/*** 获取登录用户的ID* @return String*/public static String getUserId() {return getUserInfo().getId();}/*** 获取登录的用户名* @return String*/public static String getLoginUsername() {return getUserInfo().getUsername();}public static HttpServletRequest getRequest() {RequestAttributes attributes = RequestContextHolder.getRequestAttributes();if (attributes != null ) {return ((ServletRequestAttributes) attributes).getRequest();}throw new GlobalException(ResponseCode.ERROR, "获取request对象失败");}public static HttpServletResponse getResponse() {RequestAttributes attributes = RequestContextHolder.getRequestAttributes();if (attributes != null ) {return ((ServletRequestAttributes) attributes).getResponse();}throw new GlobalException(ResponseCode.ERROR, "获取response对象失败");}}

基于easyui的表格过滤插件功能实现

package cn.edu.sgu.www.base;import lombok.Data;import java.io.Serializable;/*** 过滤规则* @author heyunlin* @version 1.0*/
@Data
public class FilterRule implements Serializable {private static final long serialVersionUID = 18L;/*** 字段名*/private String field;/*** 比较符*/private Operator op;/*** 字段值*/private String value;
}
package cn.edu.sgu.www.base;/*** 比较符* @author heyunlin* @version 1.0*/
public enum Operator {/*** 包含*/contains,/*** 等于*/equal,/*** 不等于*/notequal,/*** 以...开始*/beginwith,/*** 以...结尾*/endwith,/*** 小于*/less,/*** 小于或等于*/lessorequal,/*** 大于*/greater,/*** 大于或等于*/greaterorequal
}

基础的分页器

提供了分页的功能,需要分页功能的接口的参数类型只需要集成该类即可,将自动获得分页功能。

package cn.edu.sgu.www.base;import cn.edu.sgu.www.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
import lombok.EqualsAndHashCode;import java.io.Serializable;
import java.util.List;/*** 基础分页参数对象,包含页数和每页的记录数* @author heyunlin* @version 1.0*/
@EqualsAndHashCode(callSuper = true)
@Data
public class Pager<T> extends Sorter implements Serializable {private static final long serialVersionUID = 18L;/*** 页数*/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, boolean enableSort) {QueryWrapper<T> wrapper = new QueryWrapper<>();List<FilterRule> filterRules = pager.getFilterRules();if (filterRules != null && !filterRules.isEmpty()) {for (FilterRule filterRule : filterRules) {// 字段名:转为小写字母+下划线的格式String field = StringUtils.toLower(filterRule.getField());// 字段值String value = filterRule.getValue();if (StringUtils.isNotEmpty(value)) {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);if (StringUtils.isNotEmpty(statement)) {wrapper.last(statement);}}return wrapper;}}

基础的排序器

因为前端的基础分页器Pager已经继承了Sorter,所以开启了分页功能后自动获得排序功能。

package cn.edu.sgu.www.base;import cn.edu.sgu.www.exception.GlobalException;
import cn.edu.sgu.www.restful.ResponseCode;
import cn.edu.sgu.www.util.StringUtils;
import lombok.Data;import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;/*** 基础排序对象,包含排序字段和排序方式* @author heyunlin* @version 1.0*/
@Data
public class Sorter implements Serializable {private static final long serialVersionUID = 18L;/*** 空字符串*/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 = StringUtils.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;}}

好了,文章就分享到这里了,自己的一个小成果,分享给大家,希望对大家有所帮助~

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

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

相关文章

【Java】HttpServlet类中前后端交互三种方式(query string、form表单、JSON字符串)

在前后端的交互中&#xff0c;前端通过以下三种方式来与后端进行交互&#x1f31f; ✅query string ✅form表单 ✅JSON字符串 下面我们将书写这三种方式的后端代码并进行讲解 1、Query String QueryString即在url中写入键值对&#xff0c;一般用doGet方法进行交互 代码如下 …

Cleanmymac for mac 4.14.7无弹窗注册版

Cleanmymac for mac是一款先进的、集所有功能于一身的实用系统清理工具&#xff0c;删除系统缓存文件 , 多余的应用程序语言包 , 它能帮助保持您的Mac保持清洁。只需两个简单的点击&#xff0c;就可以删除无用的文件&#xff0c;以节省您宝贵的磁盘空间。 对于很多喜爱摄影朋友…

【LeetCode: 215. 数组中的第K个最大元素 + 堆】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

linux|操作系统|centos7物理机安装网卡驱动8188gu(内核升级,firmware固件,USB设备管理,module管理)

前言&#xff1a; 目前服务器领域centos7基本是主流的操作系统&#xff0c;而linux相对于Windows来说&#xff0c;软硬件方面的支持是差很多的&#xff0c;在硬件方面来说&#xff0c;以一个免驱的网卡为例&#xff0c;window xp可能不会自动识别到&#xff0c;但Windows10基本…

DAY04_Spring—Aop案例引入代理机制

目录 1 AOP1.1 AOP案例引入1.1.1 数据库事务说明 1.2 Spring实现事务控制1.2.1 代码结构如下1.2.2 编辑User1.2.3 编辑UserMapper/UserMapperImpl1.2.4 编辑UserService/UserServiceImpl1.2.5 编辑配置类1.2.6 编辑测试类 1.3 代码问题分析1.4 代理模式1.4.1 生活中代理案例1.4…

vue3 实现简单计数器示例——一个html文件展示vue3的效果

目的&#xff1a;作为一个新手开发&#xff0c;我想使用 Vue 3 将代码封装在 HTML 文件中时&#xff0c;进行界面打开展示。 一、vue计数示例 学了一个简单计数器界面展示&#xff0c;代码如下&#xff1a; <!DOCTYPE html> <html lang"en"><head&…

R语言【paleobioDB】——pbdb_temporal_resolution():展示化石数据的时空分辨率

Package paleobioDB version 0.7.0 paleobioDB 包在2020年已经停止更新&#xff0c;该包依赖PBDB v1 API。 可以选择在Index of /src/contrib/Archive/paleobioDB (r-project.org)下载安装包后&#xff0c;执行本地安装。 Usage pbdb_temporal_resolution (data, do.plotTRUE…

uniapp + node.js 开发问卷调查小程序

前后端效果图 后端&#xff1a;nodejs 12.8 ; mongoDB 4.0 前端&#xff1a;uniapp 开发工具&#xff1a;HBuilderX 3.99 前端首页代码 index.vue <!-- 源码下载地址 https://pan.baidu.com/s/1AVB71AjEX06wpc4wbcV_tQ?pwdl9zp --><template><view class&q…

十二、Qt 操作PDF文件(2)

一、在《十、Qt 操作PDF文件-CSDN博客》中我们用Poppler类库打开了PDF文件&#xff0c;并显示到窗体上&#xff0c;但只能显示一页&#xff0c;功能还没完善&#xff0c;在本章节中&#xff0c;加入了&#xff1a; 通过选择框选择PDF文件并打开&#xff0c;默认打开第一页。通…

Spring Boot 配置文件和日志

目录 配置文件格式 properties配置文件说明 1.properties基本语法 2.读取配置文件 3.properties缺点 yml配置文件说明 1.yml基本语法 2.配置不同数据类型 3.字符串特殊情况 4.配置对象 properties和yml对比 日志 日志的使用 日志级别 日志持久化 Lombok Lombo…

C++大学教程(第九版)5.18进制表

目录 题目 代码 运行截图 题目 &#xff08;进制表&#xff09;编写一个程序要求打印一张表&#xff0c;内容是1~256范围内每个十进制数对应的二进制、八进制和十六进制形式。如果还不熟悉这些计数系统&#xff0c;可先阅读附录 D。提示:可以使用流操纵符dec、oct 和 hex来…

网络部署实战具体学习内容总结

网络部署实战具体学习内容总结 &#x1f4bb;网络部署实战课程通常旨在教授学生如何规划、配置、维护和优化计算机网络。这些课程涵盖了广泛的主题&#xff0c;以确保学生具备网络部署和管理所需的技能。 网络部署实战课程具体学习内容&#x1f447; 1️⃣网络架构设计及网络原…

ARM 1.12

norflash与nandflash的区别&#xff1a; 一、NAND flash和NOR flash的性能比较 1、NOR的读速度比NAND稍快一些。 2、NAND的写入速度比NOR快很多。 3、NAND的4ms擦除速度远比NOR的5s快。 4、大多数写入操作需要先进行擦除操作。 5、NAND的擦除单元更小&#xff0c;相应的擦除电…

yolo9000:Better, Faster, Stronger的目标检测网络

目录 一、回顾yolov1二、yolov2详细讲解2.1 Better部分创新点&#xff08;1&#xff09;Batch Normalization(批量归一化)&#xff08;2&#xff09;High Resolution Classifier---高分辨率分类器&#xff08;3&#xff09;Anchor Boxes---锚框&#xff08;4&#xff09;Dimens…

4D毫米波雷达——原理、对比、优势、行业现状

前言 4D 毫米波雷达是传统毫米波雷达的升级版&#xff0c;4D指的是速度、距离、水平角度、垂直高度四个维度。 相比传统 3D 毫米波雷达&#xff0c;4D 毫米波雷达增加了“高度”的探测&#xff0c;将第四个维度整合到传统毫米波雷达中。 4D毫米波雷达被视为未来车载雷达的一…

Elasticsearch:和 LIamaIndex 的集成

LlamaIndex 是一个数据框架&#xff0c;供 LLM 应用程序摄取、构建和访问私有或特定领域的数据。 LlamaIndex 是开源的&#xff0c;可用于构建各种应用程序。 在 GitHub 上查看该项目。 安装 在 Docker 上设置 Elasticsearch 使用以下 docker 命令启动单节点 Elasticsearch 实…

【Go面试向】rune和byte类型的认识与使用

【Go】rune和byte类型的认识与使用 大家好 我是寸铁&#x1f44a; 总结了一篇rune和byte类型的认识与使用的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; byte和rune类型定义 byte,占用1个字节&#xff0c;共8个比特位&#xff0c;所以它实际上和uint8没什么本质区别,它表示…

基于Docker的Nginx的安装与配置

基于Docker的Nginx的安装与配置 1 为Nginx创建一个容器1.1 学习docker run1.2 通过docker run为Nginx创建并启动一个容器 2 配置Nginx2.1 学习docker的bind mount技术2.2 在Nginx容器中找到想修改的文件所在的目录2.2.1 认识nginx.conf文件2.2.2 访问Nginx服务&#xff0c;默认…

【陈老板赠书活动 - 22期】- 人工智能(第三版)

陈老老老板&#x1f9d9;‍♂️ &#x1f46e;‍♂️本文专栏&#xff1a;赠书活动专栏&#xff08;为大家争取的福利&#xff0c;免费送书&#xff09; &#x1f934;本文简述&#xff1a;活就像海洋,只有意志坚强的人,才能到达彼岸。 &#x1f473;‍♂️上一篇文章&#xff…

学习JavaEE的日子 day13 封装 static private this 类加载机制

Day13 1. private – 私有化 理解&#xff1a;private是访问修饰符的一种&#xff0c;访问修饰符规定了访问权限. 作用&#xff1a; ​ 1.private修饰属性&#xff1a;该属性只能在类的内部使用 ​ 2.private修饰方法&#xff1a;该方法只能在类的内部使用 应用场景&#xff1…