新增: list和page支持关联查询,支持自定义返回结果类型,并可以在init方法中初始化返回字段类型及数据组装函数定义

调整:优化角色修改循环单个处理为批量处理,并异步进行刷新用户权限
This commit is contained in:
ruying408
2024-08-25 01:37:10 +08:00
parent 8a6ea0e436
commit 6296f328ae
7 changed files with 202 additions and 34 deletions

View File

@@ -1,11 +1,16 @@
package com.cool.core.base;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.lang.Editor;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.cool.core.enums.QueryModeEnum;
import com.cool.core.exception.CoolPreconditions;
import com.cool.core.request.CrudOption;
import com.cool.core.request.R;
@@ -20,6 +25,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.Getter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
@@ -27,6 +33,8 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* 控制层基类
@@ -60,6 +68,12 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
@ModelAttribute
protected void preHandle(HttpServletRequest request,
@RequestAttribute JSONObject requestParams) {
String requestPath = ((ServletRequestAttributes) Objects.requireNonNull(
RequestContextHolder.getRequestAttributes())).getRequest().getRequestURI();
if (!requestPath.endsWith("/page") && !requestPath.endsWith("/list")) {
// 非page或list不执行
return;
}
this.pageOption.set(new CrudOption<>(requestParams));
this.listOption.set(new CrudOption<>(requestParams));
this.requestParams.set(requestParams);
@@ -133,7 +147,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
@PostMapping("/update")
protected R update(@RequestBody T t, @RequestAttribute() JSONObject requestParams) {
Long id = t.getId();
JSONObject info = JSONUtil.parseObj(JSONUtil.toJsonStr(service.info(id)));
JSONObject info = JSONUtil.parseObj(JSONUtil.toJsonStr(service.getById(id)));
requestParams.forEach(info::set);
info.set("updateTime", new Date());
service.update(requestParams, JSONUtil.toBean(info, currentEntityClass()));
@@ -161,7 +175,14 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
@PostMapping("/list")
protected R list(@RequestAttribute() JSONObject requestParams,
@RequestAttribute(COOL_LIST_OP) CrudOption<T> option) {
return R.ok(service.list(requestParams, option.getQueryWrapper(entityClass)));
QueryModeEnum queryModeEnum = option.getQueryModeEnum();
List list = (List) switch (queryModeEnum) {
case ENTITY_WITH_RELATIONS -> service.listWithRelations(requestParams, option.getQueryWrapper(entityClass));
case CUSTOM -> transformList(service.list(requestParams, option.getQueryWrapper(entityClass), option.getAsType()), option.getAsType());
default -> service.list(requestParams, option.getQueryWrapper(entityClass));
};
invokerTransform(option, list);
return R.ok(list);
}
/**
@@ -175,9 +196,24 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
@RequestAttribute(COOL_PAGE_OP) CrudOption<T> option) {
Integer page = requestParams.getInt("page", 1);
Integer size = requestParams.getInt("size", 20);
return R.ok(
pageResult((Page<T>) service.page(requestParams, new Page<>(page, size),
option.getQueryWrapper(entityClass))));
QueryModeEnum queryModeEnum = option.getQueryModeEnum();
Object obj = switch (queryModeEnum) {
case ENTITY_WITH_RELATIONS -> service.pageWithRelations(requestParams, new Page<>(page, size), option.getQueryWrapper(entityClass));
case CUSTOM -> transformPage(service.page(requestParams, new Page<>(page, size), option.getQueryWrapper(entityClass), option.getAsType()), option.getAsType());
default -> service.page(requestParams, new Page<>(page, size), option.getQueryWrapper(entityClass));
};
Page pageResult = (Page) obj;
invokerTransform(option, pageResult.getRecords());
return R.ok(pageResult(pageResult));
}
/**
* 转换参数,组装数据
*/
private void invokerTransform(CrudOption<T> option, List list) {
if (ObjUtil.isNotEmpty(option.getTransform())) {
option.getTransform().apply(list);
}
}
/**
@@ -185,7 +221,7 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
*
* @param page 分页返回数据
*/
protected Map<String, Object> pageResult(Page<T> page) {
protected Map<String, Object> pageResult(Page page) {
Map<String, Object> result = new HashMap<>();
Map<String, Object> pagination = new HashMap<>();
pagination.put("size", page.getPageSize());
@@ -223,4 +259,21 @@ public abstract class BaseController<S extends BaseService<T>, T extends BaseEnt
return Convert.toList(Long.class, ids);
}
/**
* 适用于自定义返回值为 mapmap 的key为数据库字段转驼峰命名
*/
protected List transformList(List records, Class<?> asType) {
if (ObjUtil.isEmpty(asType) || !Map.class.isAssignableFrom(asType)) {
return records;
}
List<Map> list = new ArrayList<>();
Editor<String> keyEditor = property -> StrUtil.toCamelCase(property);
records.forEach(o ->
list.add(BeanUtil.beanToMap(o, new HashMap(), false, keyEditor)));
return list;
}
protected Page transformPage(Page page, Class<?> asType) {
page.setRecords(transformList(page.getRecords(), asType));
return page;
}
}

View File

@@ -76,6 +76,15 @@ public interface BaseService<T> extends IService<T> {
*/
Object list(JSONObject requestParams, QueryWrapper queryWrapper);
/**
* 查询所有
*
* @param requestParams 请求参数
* @param queryWrapper 查询条件
* @return 列表信息
*/
<R> List<R> list(JSONObject requestParams, QueryWrapper queryWrapper, Class<R> asType);
/**
* 查询所有
* 带关联查询
@@ -95,6 +104,16 @@ public interface BaseService<T> extends IService<T> {
*/
Object page(JSONObject requestParams, Page<T> page, QueryWrapper queryWrapper);
/**
* 分页查询
*
* @param requestParams 请求参数
* @param page 分页信息
* @param queryWrapper 查询条件
* @return 分页信息
*/
<R> Page<R> page(JSONObject requestParams, Page page, QueryWrapper queryWrapper, Class<R> asType);
/**
* 分页查询
* 带关联查询

View File

@@ -78,6 +78,11 @@ public class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseEntity<T>> e
return this.list(queryWrapper);
}
@Override
public <R> List<R> list(JSONObject requestParams, QueryWrapper queryWrapper, Class<R> asType) {
return mapper.selectListByQueryAs(queryWrapper, asType);
}
@Override
public Object listWithRelations(JSONObject requestParams, QueryWrapper queryWrapper) {
return mapper.selectListWithRelationsByQuery(queryWrapper);
@@ -88,6 +93,12 @@ public class BaseServiceImpl<M extends BaseMapper<T>, T extends BaseEntity<T>> e
return this.page(page, queryWrapper);
}
@Override
public <R> Page<R> page(JSONObject requestParams, Page page, QueryWrapper queryWrapper,
Class<R> asType) {
return mapper.paginateAs(page, queryWrapper, asType);
}
@Override
public Object pageWithRelations(JSONObject requestParams, Page<T> page,
QueryWrapper queryWrapper) {

View File

@@ -1,6 +1,8 @@
package com.cool.core.config;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -30,4 +32,10 @@ public class ThreadPoolConfig {
executor.initialize();
return executor;
}
@Bean(name = "cachedThreadPool")
public ExecutorService cachedThreadPool() {
// 创建一个虚拟线程池,每个任务使用一个虚拟线程执行
return Executors.newCachedThreadPool();
}
}

View File

@@ -0,0 +1,10 @@
package com.cool.core.enums;
/**
* 查询模式决定返回值
*/
public enum QueryModeEnum {
ENTITY, // 实体(默认)
ENTITY_WITH_RELATIONS, // 实体关联查询(如实体字段上加 @RelationOneToMany 等注解)
CUSTOM , // 自定义默认为Map
}

View File

@@ -2,11 +2,13 @@ package com.cool.core.request;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import com.cool.core.enums.QueryModeEnum;
import com.mybatisflex.annotation.Table;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.query.QueryCondition;
@@ -14,6 +16,7 @@ import com.mybatisflex.core.query.QueryTable;
import com.mybatisflex.core.query.QueryWrapper;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import lombok.Data;
import org.springframework.core.env.Environment;
@@ -31,17 +34,26 @@ public class CrudOption<T> {
private QueryColumn[] select;
private JSONObject requestParams;
private QueryModeEnum queryModeEnum;
private Transform<List> transform;
public interface Transform<List> {
void apply(List list);
}
/**
* queryModeEnum 为 CUSTOM,可设置 默认为Map
*/
private Class<?> asType;
private Environment evn;
public CrudOption(JSONObject requestParams) {
this.requestParams = requestParams;
this.queryWrapper = QueryWrapper.create();
this.evn = SpringUtil.getBean(Environment.class);
}
public CrudOption<T> fieldEq(QueryColumn... fields) {
this.fieldEq = fields;
return this;
queryModeEnum = QueryModeEnum.ENTITY;
}
public QueryWrapper getQueryWrapper(Class<T> entityClass) {
@@ -53,16 +65,58 @@ public class CrudOption<T> {
return this;
}
/**
* 按前端传上来的字段值做eq
*/
public CrudOption<T> fieldEq(QueryColumn... fields) {
this.fieldEq = fields;
return this;
}
/**
* 按前端传上来的字段值做like
*/
public CrudOption<T> keyWordLikeFields(QueryColumn... fields) {
this.keyWordLikeFields = fields;
return this;
}
/**
* 需要返回给前端的字段
*/
public CrudOption<T> select(QueryColumn... selects) {
this.select = selects;
return this;
}
/**
* 查询模式决定返回值
* 目前有三种模式,按实体查询返回、关联查询返回(实体字段上加 @RelationOneToMany 等注解)、自定义返回结果
*/
public CrudOption<T> queryModeEnum(QueryModeEnum queryModeEnum) {
this.queryModeEnum = queryModeEnum;
if (ObjUtil.equal(queryModeEnum, QueryModeEnum.CUSTOM)
&& ObjUtil.isEmpty(asType)) {
asType = Map.class;
}
return this;
}
/**
* 自定义返回结果对象类型
*/
public CrudOption<T> asType(Class<?> asType) {
this.asType = asType;
return this;
}
/**
* 转换参数,组装数据
*/
public CrudOption<T> transform(Transform<List> transform) {
this.transform = transform;
return this;
}
/**
* 构建查询条件

View File

@@ -19,6 +19,7 @@ import com.cool.modules.base.service.sys.BaseSysPermsService;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import java.util.*;
import java.util.concurrent.ExecutorService;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.userdetails.UserDetailsService;
@@ -41,6 +42,8 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
final private BaseSysDepartmentMapper baseSysDepartmentMapper;
final private ExecutorService cachedThreadPool;
@Override
public Long[] loginDepartmentIds() {
String username = CoolSecurityUtil.getAdminUsername();
@@ -173,27 +176,37 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService {
public void updatePerms(Long roleId, Long[] menuIdList, Long[] departmentIds) {
// 更新菜单权限
baseSysRoleMenuMapper.deleteByQuery(QueryWrapper.create().eq(BaseSysRoleMenuEntity::getRoleId, roleId));
List<BaseSysRoleMenuEntity> batchRoleMenuList = new ArrayList<>();
for (Long menuId : menuIdList) {
BaseSysRoleMenuEntity roleMenuEntity = new BaseSysRoleMenuEntity();
roleMenuEntity.setRoleId(roleId);
roleMenuEntity.setMenuId(menuId);
baseSysRoleMenuMapper.insert(roleMenuEntity);
batchRoleMenuList.add(roleMenuEntity);
}
if (ObjectUtil.isNotEmpty(batchRoleMenuList)) {
baseSysRoleMenuMapper.insertBatch(batchRoleMenuList);
}
// 更新部门权限
baseSysRoleDepartmentMapper
.deleteByQuery(QueryWrapper.create().eq(BaseSysRoleDepartmentEntity::getRoleId, roleId));
List<BaseSysRoleDepartmentEntity> batchRoleDepartmentList = new ArrayList<>();
for (Long departmentId : departmentIds) {
BaseSysRoleDepartmentEntity roleDepartmentEntity = new BaseSysRoleDepartmentEntity();
roleDepartmentEntity.setRoleId(roleId);
roleDepartmentEntity.setDepartmentId(departmentId);
baseSysRoleDepartmentMapper.insert(roleDepartmentEntity);
batchRoleDepartmentList.add(roleDepartmentEntity);
}
if (ObjectUtil.isNotEmpty(batchRoleDepartmentList)) {
baseSysRoleDepartmentMapper.insertBatch(batchRoleDepartmentList);
}
cachedThreadPool.submit(() -> {
// 刷新对应角色用户的权限
List<BaseSysUserRoleEntity> userRoles = baseSysUserRoleMapper
.selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, roleId));
for (BaseSysUserRoleEntity userRole : userRoles) {
refreshPerms(userRole.getUserId());
}
});
}
@Override