diff --git a/src/main/java/com/cool/core/base/BaseController.java b/src/main/java/com/cool/core/base/BaseController.java index 75d257f..e802a75 100644 --- a/src/main/java/com/cool/core/base/BaseController.java +++ b/src/main/java/com/cool/core/base/BaseController.java @@ -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, 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, 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, T extends BaseEnt @PostMapping("/list") protected R list(@RequestAttribute() JSONObject requestParams, @RequestAttribute(COOL_LIST_OP) CrudOption 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, T extends BaseEnt @RequestAttribute(COOL_PAGE_OP) CrudOption option) { Integer page = requestParams.getInt("page", 1); Integer size = requestParams.getInt("size", 20); - return R.ok( - pageResult((Page) 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 option, List list) { + if (ObjUtil.isNotEmpty(option.getTransform())) { + option.getTransform().apply(list); + } } /** @@ -185,7 +221,7 @@ public abstract class BaseController, T extends BaseEnt * * @param page 分页返回数据 */ - protected Map pageResult(Page page) { + protected Map pageResult(Page page) { Map result = new HashMap<>(); Map pagination = new HashMap<>(); pagination.put("size", page.getPageSize()); @@ -223,4 +259,21 @@ public abstract class BaseController, T extends BaseEnt return Convert.toList(Long.class, ids); } + /** + * 适用于自定义返回值为 map,map 的key为数据库字段,转驼峰命名 + */ + protected List transformList(List records, Class asType) { + if (ObjUtil.isEmpty(asType) || !Map.class.isAssignableFrom(asType)) { + return records; + } + List list = new ArrayList<>(); + Editor 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; + } } \ No newline at end of file diff --git a/src/main/java/com/cool/core/base/BaseService.java b/src/main/java/com/cool/core/base/BaseService.java index a199f27..dff2fda 100644 --- a/src/main/java/com/cool/core/base/BaseService.java +++ b/src/main/java/com/cool/core/base/BaseService.java @@ -76,6 +76,15 @@ public interface BaseService extends IService { */ Object list(JSONObject requestParams, QueryWrapper queryWrapper); + /** + * 查询所有 + * + * @param requestParams 请求参数 + * @param queryWrapper 查询条件 + * @return 列表信息 + */ + List list(JSONObject requestParams, QueryWrapper queryWrapper, Class asType); + /** * 查询所有 * 带关联查询 @@ -95,6 +104,16 @@ public interface BaseService extends IService { */ Object page(JSONObject requestParams, Page page, QueryWrapper queryWrapper); + /** + * 分页查询 + * + * @param requestParams 请求参数 + * @param page 分页信息 + * @param queryWrapper 查询条件 + * @return 分页信息 + */ + Page page(JSONObject requestParams, Page page, QueryWrapper queryWrapper, Class asType); + /** * 分页查询 * 带关联查询 @@ -108,7 +127,7 @@ public interface BaseService extends IService { /** * 查询信息 * - * @param id ID + * @param id ID */ Object info(Long id); diff --git a/src/main/java/com/cool/core/base/BaseServiceImpl.java b/src/main/java/com/cool/core/base/BaseServiceImpl.java index 2969d3d..f4380cc 100644 --- a/src/main/java/com/cool/core/base/BaseServiceImpl.java +++ b/src/main/java/com/cool/core/base/BaseServiceImpl.java @@ -78,6 +78,11 @@ public class BaseServiceImpl, T extends BaseEntity> e return this.list(queryWrapper); } + @Override + public List list(JSONObject requestParams, QueryWrapper queryWrapper, Class 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, T extends BaseEntity> e return this.page(page, queryWrapper); } + @Override + public Page page(JSONObject requestParams, Page page, QueryWrapper queryWrapper, + Class asType) { + return mapper.paginateAs(page, queryWrapper, asType); + } + @Override public Object pageWithRelations(JSONObject requestParams, Page page, QueryWrapper queryWrapper) { diff --git a/src/main/java/com/cool/core/config/ThreadPoolConfig.java b/src/main/java/com/cool/core/config/ThreadPoolConfig.java index b7bc67a..9fc6dc7 100644 --- a/src/main/java/com/cool/core/config/ThreadPoolConfig.java +++ b/src/main/java/com/cool/core/config/ThreadPoolConfig.java @@ -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(); + } } diff --git a/src/main/java/com/cool/core/enums/QueryModeEnum.java b/src/main/java/com/cool/core/enums/QueryModeEnum.java new file mode 100644 index 0000000..8ab1e25 --- /dev/null +++ b/src/main/java/com/cool/core/enums/QueryModeEnum.java @@ -0,0 +1,10 @@ +package com.cool.core.enums; + +/** + * 查询模式决定返回值 + */ +public enum QueryModeEnum { + ENTITY, // 实体(默认) + ENTITY_WITH_RELATIONS, // 实体关联查询(如实体字段上加 @RelationOneToMany 等注解) + CUSTOM , // 自定义,默认为Map +} diff --git a/src/main/java/com/cool/core/request/CrudOption.java b/src/main/java/com/cool/core/request/CrudOption.java index 66add2f..136cb64 100644 --- a/src/main/java/com/cool/core/request/CrudOption.java +++ b/src/main/java/com/cool/core/request/CrudOption.java @@ -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 { private QueryColumn[] select; private JSONObject requestParams; + private QueryModeEnum queryModeEnum; + + private Transform transform; + + public interface Transform { + 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 fieldEq(QueryColumn... fields) { - this.fieldEq = fields; - return this; + queryModeEnum = QueryModeEnum.ENTITY; } public QueryWrapper getQueryWrapper(Class entityClass) { @@ -53,16 +65,58 @@ public class CrudOption { return this; } + /** + * 按前端传上来的字段值做eq + */ + public CrudOption fieldEq(QueryColumn... fields) { + this.fieldEq = fields; + return this; + } + + /** + * 按前端传上来的字段值做like + */ public CrudOption keyWordLikeFields(QueryColumn... fields) { this.keyWordLikeFields = fields; return this; } + /** + * 需要返回给前端的字段 + */ public CrudOption select(QueryColumn... selects) { this.select = selects; return this; } + /** + * 查询模式决定返回值 + * 目前有三种模式,按实体查询返回、关联查询返回(实体字段上加 @RelationOneToMany 等注解)、自定义返回结果 + */ + public CrudOption queryModeEnum(QueryModeEnum queryModeEnum) { + this.queryModeEnum = queryModeEnum; + if (ObjUtil.equal(queryModeEnum, QueryModeEnum.CUSTOM) + && ObjUtil.isEmpty(asType)) { + asType = Map.class; + } + return this; + } + + /** + * 自定义返回结果对象类型 + */ + public CrudOption asType(Class asType) { + this.asType = asType; + return this; + } + + /** + * 转换参数,组装数据 + */ + public CrudOption transform(Transform transform) { + this.transform = transform; + return this; + } /** * 构建查询条件 diff --git a/src/main/java/com/cool/modules/base/service/sys/impl/BaseSysPermsServiceImpl.java b/src/main/java/com/cool/modules/base/service/sys/impl/BaseSysPermsServiceImpl.java index 56cc594..bcc6194 100644 --- a/src/main/java/com/cool/modules/base/service/sys/impl/BaseSysPermsServiceImpl.java +++ b/src/main/java/com/cool/modules/base/service/sys/impl/BaseSysPermsServiceImpl.java @@ -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,18 +42,20 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService { final private BaseSysDepartmentMapper baseSysDepartmentMapper; + final private ExecutorService cachedThreadPool; + @Override public Long[] loginDepartmentIds() { String username = CoolSecurityUtil.getAdminUsername(); if (username.equals("admin")) { return baseSysDepartmentMapper.selectAll().stream().map(BaseSysDepartmentEntity::getId) - .toArray(Long[]::new); + .toArray(Long[]::new); } else { Long[] roleIds = getRoles(username); return baseSysRoleDepartmentMapper - .selectListByQuery( - QueryWrapper.create().in(BaseSysRoleDepartmentEntity::getRoleId, (Object) roleIds)) - .stream().map(BaseSysRoleDepartmentEntity::getDepartmentId).toArray(Long[]::new); + .selectListByQuery( + QueryWrapper.create().in(BaseSysRoleDepartmentEntity::getRoleId, (Object) roleIds)) + .stream().map(BaseSysRoleDepartmentEntity::getDepartmentId).toArray(Long[]::new); } } @@ -70,8 +73,8 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService { queryWrapper.in(BaseSysRoleDepartmentEntity::getRoleId, (Object) roleIds); } return baseSysRoleDepartmentMapper - .selectListByQuery(queryWrapper) - .stream().map(BaseSysRoleDepartmentEntity::getDepartmentId).toArray(Long[]::new); + .selectListByQuery(queryWrapper) + .stream().map(BaseSysRoleDepartmentEntity::getDepartmentId).toArray(Long[]::new); } @Override @@ -97,7 +100,7 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService { @Override public Long[] getRoles(String username) { return getRoles( - baseSysUserMapper.selectOneByQuery(QueryWrapper.create().eq(BaseSysUserEntity::getUsername, username))); + baseSysUserMapper.selectOneByQuery(QueryWrapper.create().eq(BaseSysUserEntity::getUsername, username))); } @Override @@ -105,7 +108,7 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService { Long[] roleIds = null; if (!userEntity.getUsername().equals("admin")) { List list = baseSysUserRoleMapper - .selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userEntity.getId())); + .selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getUserId, userEntity.getId())); roleIds = list.stream().map(BaseSysUserRoleEntity::getRoleId).toArray(Long[]::new); if (Arrays.asList(roleIds).contains(1L)) { roleIds = null; @@ -124,7 +127,7 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService { List menus = getMenus(roleIds); Set perms = new HashSet<>(); String[] permsData = menus.stream().map(BaseSysMenuEntity::getPerms) - .filter(itemPerms -> !StrUtil.isEmpty(itemPerms)).toArray(String[]::new); + .filter(itemPerms -> !StrUtil.isEmpty(itemPerms)).toArray(String[]::new); for (String permData : permsData) { perms.addAll(Arrays.asList(permData.split(","))); } @@ -155,7 +158,7 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService { @Override public List getMenus(String username) { BaseSysUserEntity sysUserEntity = baseSysUserMapper - .selectOneByQuery(QueryWrapper.create().eq(BaseSysUserEntity::getUsername, username)); + .selectOneByQuery(QueryWrapper.create().eq(BaseSysUserEntity::getUsername, username)); return getMenus(sysUserEntity.getId()); } @@ -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 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)); + .deleteByQuery(QueryWrapper.create().eq(BaseSysRoleDepartmentEntity::getRoleId, roleId)); + List batchRoleDepartmentList = new ArrayList<>(); for (Long departmentId : departmentIds) { BaseSysRoleDepartmentEntity roleDepartmentEntity = new BaseSysRoleDepartmentEntity(); roleDepartmentEntity.setRoleId(roleId); roleDepartmentEntity.setDepartmentId(departmentId); - baseSysRoleDepartmentMapper.insert(roleDepartmentEntity); + batchRoleDepartmentList.add(roleDepartmentEntity); } - // 刷新对应角色用户的权限 - List userRoles = baseSysUserRoleMapper + if (ObjectUtil.isNotEmpty(batchRoleDepartmentList)) { + baseSysRoleDepartmentMapper.insertBatch(batchRoleDepartmentList); + } + cachedThreadPool.submit(() -> { + // 刷新对应角色用户的权限 + List userRoles = baseSysUserRoleMapper .selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, roleId)); - for (BaseSysUserRoleEntity userRole : userRoles) { - refreshPerms(userRole.getUserId()); - } + for (BaseSysUserRoleEntity userRole : userRoles) { + refreshPerms(userRole.getUserId()); + } + }); } @Override @@ -227,11 +240,11 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService { public void refreshPermsByMenuId(Long menuId) { // 刷新超管权限、 找出这个菜单的所有用户、 刷新用户权限 BaseSysUserEntity admin = baseSysUserMapper - .selectOneByQuery(QueryWrapper.create().eq(BaseSysUserEntity::getUsername, "admin")); + .selectOneByQuery(QueryWrapper.create().eq(BaseSysUserEntity::getUsername, "admin")); refreshPerms(admin.getId()); List list = baseSysRoleMenuMapper.selectRowsByQuery(QueryWrapper.create().select(BASE_SYS_USER_ROLE_ENTITY.USER_ID) - .from(BASE_SYS_ROLE_MENU_ENTITY).leftJoin(BASE_SYS_USER_ROLE_ENTITY) - .on(BASE_SYS_ROLE_MENU_ENTITY.ROLE_ID.eq(BASE_SYS_USER_ROLE_ENTITY.ROLE_ID)).and(BASE_SYS_ROLE_MENU_ENTITY.MENU_ID.eq(menuId, ObjectUtil.isNotEmpty(menuId))).groupBy(BASE_SYS_USER_ROLE_ENTITY.USER_ID)); + .from(BASE_SYS_ROLE_MENU_ENTITY).leftJoin(BASE_SYS_USER_ROLE_ENTITY) + .on(BASE_SYS_ROLE_MENU_ENTITY.ROLE_ID.eq(BASE_SYS_USER_ROLE_ENTITY.ROLE_ID)).and(BASE_SYS_ROLE_MENU_ENTITY.MENU_ID.eq(menuId, ObjectUtil.isNotEmpty(menuId))).groupBy(BASE_SYS_USER_ROLE_ENTITY.USER_ID)); for (Row row : list) { refreshPerms(row.getLong("userId")); } @@ -241,7 +254,7 @@ public class BaseSysPermsServiceImpl implements BaseSysPermsService { public void refreshPermsByRoleId(Long roleId) { // 找出角色对应的所有用户 List list = baseSysUserRoleMapper - .selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, roleId)); + .selectListByQuery(QueryWrapper.create().eq(BaseSysUserRoleEntity::getRoleId, roleId)); list.forEach(e -> { refreshPerms(e.getUserId()); });