1.完成数据权限功能。

2.角色,用户,部门,项目全部支持数据权限
This commit is contained in:
Wang Chen Chen
2024-10-29 11:14:44 +08:00
parent a0c3f5ec34
commit eff969b2fb
33 changed files with 792 additions and 147 deletions

View File

@@ -173,13 +173,14 @@ export const chinaAreaDeepQuery = (areaCode: number) => {
}
/** 将权限树形结构扁平化为一维数组,用于权限查询 */
export const flatTreeToCascaderOption = (arr: any[], {value = "id", label = "label", children = "children"}) => {
export const flatTreeToCascaderOption = (arr: any[], { value = "id", label = "label", disabled = "disabled", children = "children" }) => {
const result: CascaderOption[] = []
const deep = (arr1: any[], arr2: CascaderOption[]) => {
arr1.forEach((item: any) => {
const temp: CascaderOption = {
value: item[value],
label: item[label]
label: item[label],
disabled: item[disabled]
}
arr2.push(temp)
if (item[children] && item[children].length > 0) {

View File

@@ -1,26 +1,47 @@
package com.xaaef.molly.common.consts;
/**
* <p>
*
* </p>
*
* @author Wang Chen Chen
* @version 1.0.1
* @date 2024/8/13 15:15
* @author WangChenChen
* @version 1.0.0
* @date 2024/10/28 下午6:37
*/
public class DataScopeConst {
/**
* 数据范围1全部数据权限 2自定数据权限 3仅本部门数据权限 4本部门及以下数据权限
* 全部数据权限
*/
public static final Integer All = 1;
public static final int DATA_SCOPE_ALL = 1;
public static final Integer CUSTOM = 2;
/**
* 自定数据权限
*/
public static final int DATA_SCOPE_CUSTOM = 2;
public static final Integer ONLY_ME = 3;
/**
* 部门数据权限
*/
public static final int DATA_SCOPE_DEPT = 3;
/**
* 部门及以下数据权限
*/
public static final int DATA_SCOPE_DEPT_AND_CHILD = 4;
/**
* 仅本人数据权限
*/
public static final int DATA_SCOPE_SELF = 5;
/**
* 数据权限过滤关键字
*/
public static final String DATA_SCOPE = "dataScope";
public static final Integer ME_AND_CHILD = 4;
}

View File

@@ -40,6 +40,6 @@ public class PmsRoleDTO implements java.io.Serializable {
/**
* 数据范围
*/
private Integer dataScope;
private int dataScope;
}

View File

@@ -9,7 +9,7 @@ import com.xaaef.molly.common.valid.ValidCreate;
import com.xaaef.molly.common.valid.ValidDelete;
import com.xaaef.molly.common.valid.ValidUpdate;
import com.xaaef.molly.internal.dto.PmsDeptDTO;
import com.xaaef.molly.tenant.base.BaseEntity;
import com.xaaef.molly.tenant.base.ParamBaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
@@ -36,7 +36,7 @@ import lombok.experimental.Accessors;
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class CmsProject extends BaseEntity {
public class CmsProject extends ParamBaseEntity {
/**
* 项目ID

View File

@@ -2,11 +2,14 @@ package com.xaaef.molly.corems.mapper;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xaaef.molly.corems.entity.CmsProject;
import com.xaaef.molly.corems.entity.TenantAndProject;
import com.xaaef.molly.tenant.ds.DataScope;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -42,4 +45,25 @@ public interface CmsProjectMapper extends BaseMapper<CmsProject> {
// 根据 租户的数据名称 查询 项目列表。如: molly_master 、molly_google
Set<TenantAndProject> selectListByTenantDbName(Collection<String> tenantDbNameList);
/**
* 根据条件分页查询数据
*/
@DataScope()
List<CmsProject> selectProjectList(@Param("p") CmsProject user);
/**
* 根据条件分页查询数据
*/
@DataScope()
IPage<CmsProject> selectProjectPage(IPage<?> page, @Param("p") CmsProject user);
/**
* 根据条件分页查询数据
*/
@DataScope()
IPage<CmsProject> selectSimpleProjectPage(IPage<?> page, @Param("p") CmsProject user);
}

View File

@@ -1,6 +1,5 @@
package com.xaaef.molly.corems.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -22,12 +21,12 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static com.xaaef.molly.auth.jwt.JwtSecurityUtils.*;
import static com.xaaef.molly.auth.jwt.JwtSecurityUtils.encryptPassword;
import static com.xaaef.molly.auth.jwt.JwtSecurityUtils.matchesPassword;
import static com.xaaef.molly.common.consts.ConfigDataConst.DEFAULT_PROJECT_PASSWORD;
import static com.xaaef.molly.common.consts.MbpConst.PROJECT_ID;
@@ -56,19 +55,15 @@ public class CmsProjectServiceImpl extends BaseServiceImpl<CmsProjectMapper, Cms
@Override
public IPage<CmsProject> pageKeywords(ProjectQueryPO params) {
var wrapper = super.getKeywordsQueryWrapper(params,
List.of(CmsProject::getProjectName, CmsProject::getLinkman));
var project = new CmsProject();
if (StrUtil.isNotBlank(params.getKeywords())) {
project.setProjectName(params.getKeywords());
}
if (params.getDeptId() != null && params.getDeptId() > 0L) {
if (CollectionUtil.contains(getLoginUser().getHaveDeptIds(), params.getDeptId())) {
wrapper.lambda().in(CmsProject::getDeptId, params.getDeptId());
} else {
wrapper.lambda().in(CmsProject::getDeptId, getLoginUser().getHaveDeptIds());
}
} else {
wrapper.lambda().in(CmsProject::getDeptId, getLoginUser().getHaveDeptIds());
project.setDeptId(params.getDeptId());
}
Page<CmsProject> pageRequest = Page.of(params.getPageIndex(), params.getPageSize());
Page<CmsProject> result = super.page(pageRequest, wrapper);
var result = baseMapper.selectProjectPage(pageRequest, project);
if (params.isIncludeCauu()) {
reflectionFill(result.getRecords());
}
@@ -143,25 +138,14 @@ public class CmsProjectServiceImpl extends BaseServiceImpl<CmsProjectMapper, Cms
@Override
public IPage<CmsProject> simplePageKeywords(SearchPO po) {
var wrapper = super.getKeywordsQueryWrapper(po,
List.of(CmsProject::getProjectName, CmsProject::getLinkman)
)
.lambda()
.select(
List.of(
CmsProject::getProjectId, CmsProject::getProjectName,
CmsProject::getLinkman, CmsProject::getAreaCode, CmsProject::getAddress
)
)
.eq(CmsProject::getStatus, StatusEnum.NORMAL.getCode())
.orderByAsc(CmsProject::getSort, CmsProject::getCreateTime);
// 非系统用户和管理员用户。根据所在部门,查询项目列表
if (!isMasterUser() && !isAdminUser()) {
wrapper.in(CmsProject::getDeptId, getLoginUser().getHaveDeptIds());
public IPage<CmsProject> simplePageKeywords(SearchPO params) {
var project = new CmsProject();
if (StrUtil.isNotBlank(params.getKeywords())) {
project.setProjectName(params.getKeywords());
}
Page<CmsProject> pageRequest = Page.of(po.getPageIndex(), po.getPageSize());
return super.page(pageRequest, wrapper);
project.setStatus(StatusEnum.NORMAL.getCode());
Page<CmsProject> pageRequest = Page.of(params.getPageIndex(), params.getPageSize());
return baseMapper.selectSimpleProjectPage(pageRequest, project);
}

View File

@@ -4,6 +4,25 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xaaef.molly.corems.mapper.CmsProjectMapper">
<resultMap id="BaseResultMap" type="CmsProject">
<id property="projectId" column="project_id"/>
<result property="projectName" column="project_name"/>
<result property="linkman" column="linkman"/>
<result property="contactNumber" column="contact_number"/>
<result property="areaCode" column="area_code"/>
<result property="address" column="address"/>
<result property="sort" column="sort"/>
<result property="deptId" column="dept_id"/>
<result property="password" column="password"/>
<result property="status" column="status"/>
<result property="createTime" column="create_time"/>
<result property="createUser" column="create_user"/>
<result property="lastUpdateTime" column="last_update_time"/>
<result property="lastUpdateUser" column="last_update_user"/>
</resultMap>
<select id="selectListTableNamesByNotIncludeColumn" resultType="java.lang.String">
SELECT *
FROM (SELECT DISTINCT TABLE_NAME
@@ -17,7 +36,10 @@
<select id="selectListTableNamesByIncludeColumn" resultType="java.lang.String">
SELECT DISTINCT TABLE_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = (SELECT DATABASE()) AND COLUMN_NAME = #{column}
SELECT DISTINCT TABLE_NAME
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = (SELECT DATABASE())
AND COLUMN_NAME = #{column}
</select>
@@ -41,4 +63,49 @@
</select>
<sql id="DataScopeWhere">
<where>
<if test="p.projectId != null and p.projectId != 0">
AND pro.project_id = #{p.projectId}
</if>
<if test="p.status != null">
AND pro.`status` = #{p.status}
</if>
<if test="p.projectName != null and p.projectName !=''">
AND CONCAT(pro.project_name, pro.linkman, pro.contactNumber, pro.address) LIKE
CONCAT('%',#{p.projectName},'%')
</if>
<if test="p.deptId != null and p.deptId != 0">
AND (pro.dept_id = #{p.deptId} OR pro.dept_id IN ( SELECT t.dept_id FROM pms_dept t WHERE
find_in_set(#{p.deptId}, ancestors) ))
</if>
<!-- 数据范围过滤 -->
${p.params.dataScope}
</where>
</sql>
<select id="selectProjectList" resultMap="BaseResultMap">
select pro.* from cms_project as pro
left join pms_dept as d on pro.dept_id = d.dept_id
<include refid="DataScopeWhere"/>
</select>
<select id="selectProjectPage" resultMap="BaseResultMap">
select pro.* from cms_project as pro
left join pms_dept as d on pro.dept_id = d.dept_id
<include refid="DataScopeWhere"/>
order by pro.sort,pro.create_time
</select>
<select id="selectSimpleProjectPage" resultMap="BaseResultMap">
select pro.project_id, pro.project_name, pro.linkman, pro.area_code, pro.address from cms_project as pro
left join pms_dept as d on pro.dept_id = d.dept_id
<include refid="DataScopeWhere"/>
order by pro.sort,pro.create_time
</select>
</mapper>

View File

@@ -56,9 +56,7 @@ public class PmsRoleController {
@Operation(summary = "分页", description = "分页 查询所有")
@GetMapping("/query")
public JsonResult<Pagination<PmsRole>> pageQuery(SearchPO params) {
var page = baseService.pageKeywords(
params, List.of(PmsRole::getRoleName, PmsRole::getDescription)
);
var page = baseService.pageKeywords(params);
return JsonResult.success(page.getTotal(), page.getRecords());
}

View File

@@ -7,7 +7,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.xaaef.molly.common.consts.RegexConst;
import com.xaaef.molly.common.valid.ValidCreate;
import com.xaaef.molly.common.valid.ValidUpdate;
import com.xaaef.molly.tenant.base.BaseEntity;
import com.xaaef.molly.tenant.base.ParamBaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@@ -34,7 +34,7 @@ import lombok.experimental.Accessors;
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class PmsDept extends BaseEntity {
public class PmsDept extends ParamBaseEntity {
/**
* 部门 ID

View File

@@ -6,7 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xaaef.molly.common.valid.ValidCreate;
import com.xaaef.molly.common.valid.ValidUpdate;
import com.xaaef.molly.tenant.base.BaseEntity;
import com.xaaef.molly.tenant.base.ParamBaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@@ -33,7 +33,7 @@ import java.util.Set;
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class PmsRole extends BaseEntity {
public class PmsRole extends ParamBaseEntity {
/**
* 角色 ID
@@ -65,7 +65,7 @@ public class PmsRole extends BaseEntity {
private String description;
/**
* 数据范围1全部数据权限 2自定数据权限 3仅本部门数据权限 4本部门及以下数据权限
* 数据范围1全部数据权限 2自定数据权限 3仅本部门数据权限 4本部门及以下数据权限 5仅自己的权限
*/
@Schema(description = "数据范围", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "数据范围,必须填写", groups = {ValidCreate.class})

View File

@@ -7,7 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import com.xaaef.molly.common.consts.RegexConst;
import com.xaaef.molly.common.valid.ValidCreate;
import com.xaaef.molly.common.valid.ValidUpdate;
import com.xaaef.molly.tenant.base.BaseEntity;
import com.xaaef.molly.tenant.base.ParamBaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import lombok.*;
@@ -37,7 +37,7 @@ import java.util.Set;
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class PmsUser extends BaseEntity {
public class PmsUser extends ParamBaseEntity {
/**
* 用户ID

View File

@@ -1,7 +1,9 @@
package com.xaaef.molly.perms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xaaef.molly.perms.entity.PmsDept;
import com.xaaef.molly.tenant.ds.DataScope;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@@ -87,4 +89,23 @@ public interface PmsDeptMapper extends BaseMapper<PmsDept> {
Set<Long> selectDeptIdByRuleIds(Set<Long> roleIds);
/**
* 根据条件分页查询数据
*/
@DataScope()
IPage<PmsDept> selectDeptPage(IPage<?> page, @Param("p") PmsDept role);
/**
* 根据条件列表查询数据
*/
@DataScope()
List<PmsDept> selectDeptList(@Param("p") PmsDept dept);
@DataScope()
Set<Long> selectDeptIdList(@Param("p") PmsDept dept);
}

View File

@@ -1,9 +1,11 @@
package com.xaaef.molly.perms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xaaef.molly.common.domain.LinkedTarget;
import com.xaaef.molly.perms.entity.PmsRole;
import com.xaaef.molly.perms.entity.PmsRoleProxy;
import com.xaaef.molly.tenant.ds.DataScope;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@@ -78,4 +80,20 @@ public interface PmsRoleMapper extends BaseMapper<PmsRole> {
@Param("deptIds") Set<Long> deptIds);
/**
* 根据条件列表查询数据
*/
@DataScope()
List<PmsRole> selectRoleList(@Param("p") PmsRole role);
/**
* 根据条件分页查询数据
*/
@DataScope()
IPage<PmsRole> selectRolePage(IPage<?> page, @Param("p") PmsRole role);
}

View File

@@ -1,7 +1,9 @@
package com.xaaef.molly.perms.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xaaef.molly.perms.entity.PmsUser;
import com.xaaef.molly.tenant.ds.DataScope;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
@@ -32,4 +34,20 @@ public interface PmsUserMapper extends BaseMapper<PmsUser> {
@Param("dbNameList") Set<String> dbNameList,
@Param("userIdList") Set<Long> userIdList);
/**
* 根据条件列表查询数据
*/
@DataScope()
List<PmsUser> selectUserList(@Param("p") PmsUser user);
/**
* 根据条件分页查询数据
*/
@DataScope()
IPage<PmsUser> selectUserPage(IPage<?> page, @Param("p") PmsUser user);
}

View File

@@ -24,7 +24,7 @@ public interface PmsDeptService extends BaseService<PmsDept> {
/**
* 分页查询
*/
IPage<PmsDept> pageKeywords(SearchParentPO po);
IPage<PmsDept> pageKeywords(SearchParentPO params);
/**

View File

@@ -20,6 +20,7 @@ import java.util.Set;
public interface PmsRoleService extends BaseService<PmsRole> {
IPage<PmsRole> pageKeywords(SearchPO params);

View File

@@ -51,31 +51,57 @@ public class PmsDeptServiceImpl extends BaseServiceImpl<PmsDeptMapper, PmsDept>
private final ApiCmsProjectService projectService;
@Override
public IPage<PmsDept> pageKeywords(SearchParentPO po) {
var wrapper = super.getKeywordsQueryWrapper(
po,
List.of(
PmsDept::getDeptName, PmsDept::getDescription,
PmsDept::getLeader, PmsDept::getLeaderMobile
)
);
if (po.getParentId() != null) {
wrapper.lambda().eq(PmsDept::getParentId, po.getParentId());
public IPage<PmsDept> pageKeywords(SearchParentPO params) {
var dept = new PmsDept();
if (StrUtil.isNotBlank(params.getKeywords())) {
dept.setDeptName(params.getKeywords());
}
Page<PmsDept> pageRequest = Page.of(po.getPageIndex(), po.getPageSize());
return super.page(pageRequest, wrapper);
if (params.getParentId() != null && params.getParentId() > 0) {
dept.setParentId(params.getParentId());
}
Page<PmsDept> pageRequest = Page.of(params.getPageIndex(), params.getPageSize());
var result = baseMapper.selectDeptPage(pageRequest, dept);
if (params.isIncludeCauu()) {
reflectionFill(result.getRecords());
}
return result;
}
@Override
public List<Tree<Long>> treeNode() {
var nodeList = this.list().stream().map(r -> {
var node = new TreeNode<>(r.getDeptId(), r.getParentId(), r.getDeptName(), r.getSort());
var targetMap = new HashMap<String, Object>();
BeanUtil.beanToMap(r, targetMap, CopyOptions.create().setIgnoreNullValue(true));
node.setExtra(targetMap);
return node;
}).collect(Collectors.toList());
final var deptList = baseMapper.selectDeptList(new PmsDept());
// 获取 部门的 所有祖籍节点
var ancestors = deptList.stream()
.filter(a -> StrUtil.isNotBlank(a.getAncestors()))
.map(a -> a.getAncestors().split(StrUtil.COMMA))
.flatMap(Stream::of)
.filter(StrUtil::isNotBlank)
.map(Long::parseLong)
.filter(a -> a > 0)
.collect(Collectors.toSet());
// 移除已经存在的节点
if (!ancestors.isEmpty()) {
var c1 = deptList.stream().map(PmsDept::getDeptId).collect(Collectors.toSet());
ancestors.removeAll(c1);
}
var disableMaps = new HashMap<Long, Boolean>();
if (!ancestors.isEmpty()) {
this.listByIds(ancestors)
.forEach(d -> {
disableMaps.put(d.getDeptId(), true);
deptList.add(d);
});
}
var nodeList = deptList.stream()
.map(r -> {
var node = new TreeNode<>(r.getDeptId(), r.getParentId(), r.getDeptName(), r.getSort());
var targetMap = new HashMap<String, Object>();
BeanUtil.beanToMap(r, targetMap, CopyOptions.create().setIgnoreNullValue(true));
targetMap.put("disabled", disableMaps.getOrDefault(r.getDeptId(), false));
node.setExtra(targetMap);
return node;
}).collect(Collectors.toList());
return TreeUtil.build(nodeList, 0L);
}

View File

@@ -4,20 +4,19 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xaaef.molly.common.consts.DataScopeConst;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xaaef.molly.common.domain.LinkedTarget;
import com.xaaef.molly.common.exception.BizException;
import com.xaaef.molly.common.po.SearchPO;
import com.xaaef.molly.common.util.TenantUtils;
import com.xaaef.molly.internal.api.ApiSysMenuService;
import com.xaaef.molly.internal.dto.SysMenuDTO;
import com.xaaef.molly.perms.entity.PmsDept;
import com.xaaef.molly.perms.entity.PmsRole;
import com.xaaef.molly.perms.entity.PmsRoleProxy;
import com.xaaef.molly.perms.mapper.PmsDeptMapper;
import com.xaaef.molly.perms.mapper.PmsRoleMapper;
import com.xaaef.molly.perms.service.PmsDeptService;
import com.xaaef.molly.perms.service.PmsRoleService;
import com.xaaef.molly.perms.vo.UpdateMenusVO;
import com.xaaef.molly.tenant.base.service.impl.BaseServiceImpl;
@@ -31,6 +30,8 @@ import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import static com.xaaef.molly.common.consts.DataScopeConst.DATA_SCOPE_CUSTOM;
/**
* <p>
@@ -49,40 +50,39 @@ public class PmsRoleServiceImpl extends BaseServiceImpl<PmsRoleMapper, PmsRole>
private final ApiSysMenuService menuService;
private final PmsDeptMapper deptMapper;
private final PmsDeptService deptService;
private final MultiTenantManager tenantManager;
@Override
public IPage<PmsRole> pageKeywords(SearchPO params) {
var result = super.pageKeywords(
params, List.of(PmsRole::getRoleName, PmsRole::getDescription)
);
Page<PmsRole> pageRequest = Page.of(params.getPageIndex(), params.getPageSize());
var sysRole = new PmsRole();
if (StrUtil.isNotBlank(params.getKeywords())) {
sysRole.setDescription(params.getKeywords());
}
var result = baseMapper.selectRolePage(pageRequest, sysRole);
includeDept(result.getRecords());
if (params.isIncludeCauu()) {
reflectionFill(result.getRecords());
}
return result;
}
@Override
public List<PmsRole> list() {
return baseMapper.selectRoleList(new PmsRole());
}
@Override
public UpdateMenusVO listHaveDepts(Long roleId) {
var result = new UpdateMenusVO()
.setAll(new ArrayList<>())
.setHave(new HashSet<>());
var w1 = new LambdaQueryWrapper<PmsDept>()
.select(List.of(PmsDept::getDeptId, PmsDept::getDeptName,
PmsDept::getParentId, PmsDept::getSort));
final var deptList = deptMapper.selectList(w1);
if (!deptList.isEmpty()) {
// 获取全部的菜单
var all = deptList.stream()
.map(r -> new TreeNode<>(
r.getDeptId(), r.getParentId(),
r.getDeptName(), r.getSort())
)
.collect(Collectors.toList());
result.setAll(TreeUtil.build(all, 0L));
}
result.setAll(deptService.treeNode());
if (roleId > 0) {
final var haveList = baseMapper.selectDeptIdByRoleIds(Set.of(roleId));
if (!haveList.isEmpty()) {
@@ -98,7 +98,7 @@ public class PmsRoleServiceImpl extends BaseServiceImpl<PmsRoleMapper, PmsRole>
if (CollectionUtil.isNotEmpty(list)) {
var roleIds = list
.stream()
.filter(r -> Objects.equals(r.getDataScope(), DataScopeConst.CUSTOM))
.filter(r -> Objects.equals(r.getDataScope(), DATA_SCOPE_CUSTOM))
.map(PmsRole::getRoleId)
.collect(Collectors.toSet());
if (!roleIds.isEmpty()) {
@@ -206,7 +206,7 @@ public class PmsRoleServiceImpl extends BaseServiceImpl<PmsRoleMapper, PmsRole>
@Transactional(rollbackFor = Exception.class)
@Override
public boolean save(PmsRole entity) {
if (entity.getDataScope() == 2) {
if (Objects.equals(entity.getDataScope(), DATA_SCOPE_CUSTOM)) {
if (CollectionUtil.isEmpty(entity.getDeptIds())) {
throw new RuntimeException("自定义数据权限,最少需要选择一个部门");
}
@@ -221,7 +221,7 @@ public class PmsRoleServiceImpl extends BaseServiceImpl<PmsRoleMapper, PmsRole>
@Transactional(rollbackFor = Exception.class)
@Override
public boolean updateById(PmsRole entity) {
if (entity.getDataScope() == 2) {
if (Objects.equals(entity.getDataScope(), DATA_SCOPE_CUSTOM)) {
if (CollectionUtil.isEmpty(entity.getDeptIds())) {
throw new RuntimeException("自定义数据权限,最少需要选择一个部门");
}

View File

@@ -2,12 +2,13 @@ package com.xaaef.molly.perms.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xaaef.molly.auth.jwt.JwtLoginUser;
import com.xaaef.molly.auth.jwt.JwtSecurityUtils;
@@ -47,6 +48,7 @@ import java.util.stream.Collectors;
import static com.xaaef.molly.auth.jwt.JwtSecurityUtils.*;
import static com.xaaef.molly.common.consts.ConfigDataConst.DEFAULT_USER_PASSWORD;
import static com.xaaef.molly.common.consts.MbpConst.CREATE_TIME;
import static com.xaaef.molly.common.enums.AdminFlag.NO;
import static com.xaaef.molly.common.enums.MenuTypeEnum.BUTTON;
import static com.xaaef.molly.common.enums.MenuTypeEnum.MENU;
@@ -87,19 +89,16 @@ public class PmsUserServiceImpl extends BaseServiceImpl<PmsUserMapper, PmsUser>
@Override
public IPage<PmsUser> pageKeywords(UserQueryPO params) {
var wrapper = super.getKeywordsQueryWrapper(params,
List.of(PmsUser::getUsername, PmsUser::getNickname));
if (params.getDeptId() != null && params.getDeptId() > 0L) {
if (CollectionUtil.contains(getLoginUser().getHaveDeptIds(), params.getDeptId())) {
wrapper.lambda().in(PmsUser::getDeptId, params.getDeptId());
} else {
wrapper.lambda().in(PmsUser::getDeptId, getLoginUser().getHaveDeptIds());
}
} else {
wrapper.lambda().in(PmsUser::getDeptId, getLoginUser().getHaveDeptIds());
var userParams = new PmsUser();
if (NumberUtil.isValidNumber(params.getDeptId())) {
userParams.setDeptId(params.getDeptId());
}
if (StringUtils.isNotBlank(params.getKeywords())) {
userParams.setNickname(params.getKeywords());
}
Page<PmsUser> pageRequest = Page.of(params.getPageIndex(), params.getPageSize());
Page<PmsUser> result = super.page(pageRequest, wrapper);
pageRequest.addOrder(OrderItem.desc(CREATE_TIME));
IPage<PmsUser> result = baseMapper.selectUserPage(pageRequest, userParams);
if (params.isIncludeCauu()) {
reflectionFill(result.getRecords());
}

View File

@@ -51,25 +51,30 @@
<select id="selectChildDeptByUserId" resultMap="BaseResultMap">
SELECT * FROM pms_dept
SELECT *
FROM pms_dept
WHERE dept_id = (SELECT u1.dept_id FROM pms_user AS u1 WHERE u1.user_id = #{userId})
UNION
SELECT * FROM pms_dept
SELECT *
FROM pms_dept
WHERE find_in_set((SELECT u1.dept_id FROM pms_user AS u1 WHERE u1.user_id = #{userId}), ancestors)
</select>
<select id="selectChildDeptIdByUserId" resultType="java.lang.Long">
SELECT dept_id FROM pms_dept
SELECT dept_id
FROM pms_dept
WHERE dept_id = (SELECT u1.dept_id FROM pms_user AS u1 WHERE u1.user_id = #{userId})
UNION
SELECT dept_id FROM pms_dept
SELECT dept_id
FROM pms_dept
WHERE find_in_set((SELECT u1.dept_id FROM pms_user AS u1 WHERE u1.user_id = #{userId}), ancestors)
</select>
<select id="selectDeptByUserId" resultMap="BaseResultMap">
SELECT * FROM pms_dept
SELECT *
FROM pms_dept
WHERE dept_id = (SELECT u1.dept_id FROM pms_user AS u1 WHERE u1.user_id = #{userId})
</select>
@@ -77,10 +82,10 @@
<select id="selectDeptByRuleIds" resultMap="BaseResultMap">
SELECT * FROM pms_dept
WHERE dept_id IN (
SELECT dept_id FROM pms_role_dept WHERE role_id IN
<foreach item="item" index="index" collection="roleIds" open="(" separator="," close=")">
#{item}
</foreach>
SELECT dept_id FROM pms_role_dept WHERE role_id IN
<foreach item="item" index="index" collection="roleIds" open="(" separator="," close=")">
#{item}
</foreach>
)
</select>
@@ -93,4 +98,40 @@
</select>
<sql id="DataScopeWhere">
<where>
<if test="p.deptId != null and p.deptId != 0">
AND d.dept_id = #{p.deptId}
</if>
<if test="p.parentId != null and p.parentId != 0">
AND d.parent_id = #{p.parentId}
</if>
<if test="p.deptName != null and p.deptName != ''">
AND CONCAT(d.dept_name,d.leader,d.description) LIKE CONCAT('%',#{p.deptName},'%')
</if>
<!-- 数据范围过滤 -->
${p.params.dataScope}
</where>
</sql>
<select id="selectDeptPage" parameterType="PmsDept" resultMap="BaseResultMap">
select d.* from pms_dept as d
<include refid="DataScopeWhere"/>
order by d.parent_id, d.sort
</select>
<select id="selectDeptList" parameterType="PmsDept" resultMap="BaseResultMap">
select d.* from pms_dept as d
<include refid="DataScopeWhere"/>
order by d.parent_id, d.sort
</select>
<select id="selectDeptIdList" parameterType="PmsDept" resultType="java.lang.Long">
select d.dept_id from pms_dept as d
<include refid="DataScopeWhere"/>
</select>
</mapper>

View File

@@ -16,9 +16,9 @@
<result property="lastUpdateUser" column="last_update_user"/>
</resultMap>
<sql id="Base_Column_List">
role_id,role_name,
role_id
,role_name,
sort,`description`,create_time,
create_user,last_update_time,last_update_user
</sql>
@@ -56,7 +56,7 @@
<select id="selectListByUserId" resultMap="SysRoleProxyResultMap">
SELECT r1.role_id, r1.role_name, r1.description
FROM pms_role AS r1
RIGHT JOIN pms_user_role AS r2 ON r2.role_id = r1.role_id
RIGHT JOIN pms_user_role AS r2 ON r2.role_id = r1.role_id
WHERE r2.user_id = #{userId}
</select>
@@ -85,5 +85,49 @@
</insert>
<sql id="SelectRoleVo">
select distinct r.role_id,
r.role_name,
r.sort,
r.description,
r.data_scope,
r.create_time,
r.create_user,
r.last_update_time,
r.last_update_user
from pms_role r
left join pms_user_role ur on ur.role_id = r.role_id
left join pms_user u on u.user_id = ur.user_id
left join pms_dept d on u.dept_id = d.dept_id
</sql>
<sql id="DataScopeWhere">
<where>
<if test="p.roleId != null and p.roleId != 0">
AND r.role_id = #{p.roleId}
</if>
<if test="p.description != null and p.description != ''">
AND CONCAT(r.`role_name`,r.description) LIKE CONCAT('%',#{p.description},'%')
</if>
<!-- 数据范围过滤 -->
${p.params.dataScope}
</where>
</sql>
<select id="selectRoleList" resultMap="BaseResultMap">
<include refid="SelectRoleVo"/>
<include refid="DataScopeWhere"/>
order by r.sort,r.create_time
</select>
<select id="selectRolePage" resultMap="BaseResultMap">
<include refid="SelectRoleVo"/>
<include refid="DataScopeWhere"/>
order by r.sort,r.create_time
</select>
</mapper>

View File

@@ -3,7 +3,7 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xaaef.molly.perms.mapper.PmsUserMapper">
<resultMap id="baseResultMap" type="PmsUser">
<resultMap id="BaseResultMap" type="PmsUser">
<id property="userId" column="user_id"/>
<result property="avatar" column="avatar"/>
<result property="username" column="username"/>
@@ -30,7 +30,7 @@
</insert>
<select id="selectSimpleListByUserIds" resultMap="baseResultMap">
<select id="selectSimpleListByUserIds" resultMap="BaseResultMap">
<foreach collection='dbNameList' item='item' index='index1' separator='UNION'>
SELECT user_id,avatar,nickname FROM ${item}.pms_user WHERE user_id IN
<foreach collection='userIdList' item='userId' index='index2' open='(' separator=',' close=')'>
@@ -40,4 +40,35 @@
</select>
<sql id="DataScopeWhere">
<where>
<if test="p.userId != null and p.userId != 0">
AND u.user_id = #{p.userId}
</if>
<if test="p.nickname != null and p.nickname !=''">
AND CONCAT(u.`username`,u.nickname) LIKE CONCAT('%',#{p.nickname},'%')
</if>
<if test="p.deptId != null and p.deptId != 0">
AND (u.dept_id = #{p.deptId} OR u.dept_id IN ( SELECT t.dept_id FROM pms_dept t WHERE find_in_set(#{p.deptId}, ancestors) ))
</if>
<!-- 数据范围过滤 -->
${p.params.dataScope}
</where>
</sql>
<select id="selectUserList" resultMap="BaseResultMap">
select u.* from pms_user as u
left join pms_dept as d on u.dept_id = d.dept_id
<include refid="DataScopeWhere"/>
</select>
<select id="selectUserPage" resultMap="BaseResultMap">
select u.* from pms_user as u
left join pms_dept as d on u.dept_id = d.dept_id
<include refid="DataScopeWhere"/>
</select>
</mapper>

View File

@@ -38,7 +38,7 @@ VALUES (10001, 0, '集团', '张集团', '15055555555', 1, '集团', '0', '2022-
-- ----------------------------
INSERT INTO `pms_role` (`role_id`, `role_name`, `sort`, `data_scope`, `description`, `create_time`, `create_user`,
`last_update_time`, `last_update_user`)
VALUES (10001, '管理员', 10, 4, '管理员', '2022-06-10 23:11:09', 19980817, '2022-06-10 23:11:09', 19980817),
VALUES (10001, '管理员', 10, 1, '管理员', '2022-06-10 23:11:09', 19980817, '2022-06-10 23:11:09', 19980817),
(10002, '测试员', 20, 4, '测试员', '2023-11-09 10:11:49', 19980817, '2023-11-09 10:11:49', 19980817),
(10003, '运营员', 30, 4, '运营员', '2023-11-09 10:12:01', 19980817, '2023-11-09 10:12:01', 19980817);

View File

@@ -67,7 +67,8 @@ VALUES
(10042, 0, '全部数据权限', '1', 'sys_data_scope', 0, 19980817, '2024-08-13 10:19:18', 19980817, '2024-08-13 10:20:34'),
(10043, 0, '自定数据权限', '2', 'sys_data_scope', 0, 19980817, '2024-08-13 10:19:39', 19980817, '2024-08-13 10:20:40'),
(10044, 0, '仅本部门数据权限', '3', 'sys_data_scope', 0, 19980817, '2024-08-13 10:20:22', 19980817, '2024-08-13 10:20:22'),
(10045, 0, '本部门及以下数据权限', '4', 'sys_data_scope', 1, 19980817, '2024-08-13 10:20:29', 19980817, '2024-08-13 10:20:43');
(10045, 0, '本部门及以下数据权限', '4', 'sys_data_scope', 1, 19980817, '2024-08-13 10:20:29', 19980817, '2024-08-13 10:20:43'),
(10046, 0, '仅本人数据权限', '5', 'sys_data_scope', 0, 19980817, '2024-08-13 10:20:29', 19980817, '2024-08-13 10:20:43');
SET FOREIGN_KEY_CHECKS = 1;

View File

@@ -21,6 +21,19 @@ import io.swagger.v3.oas.annotations.media.Schema;
import liquibase.integration.spring.MultiTenantSpringLiquibase;
import lombok.*;
import lombok.experimental.Accessors;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.*;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.util.SelectUtils;
import org.assertj.core.util.Sets;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.FileSystemResourceLoader;
@@ -34,7 +47,9 @@ import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.xaaef.molly.common.consts.LoginConst.*;
@@ -271,4 +286,142 @@ public class NoSpringTests {
}
@Test
public void test19() throws Exception {
// 单表全量
Table table = new Table("test");
Select select = SelectUtils.buildSelectFromTable(table);
System.err.println(select); // SELECT * FROM test
// 指定列查询
Select buildSelectFromTableAndExpressions = SelectUtils.buildSelectFromTableAndExpressions(new Table("test"), new Column("col1"), new Column("col2"));
System.err.println(buildSelectFromTableAndExpressions); // SELECT col1, col2 FROM test
// WHERE =
EqualsTo equalsTo = new EqualsTo(); // 等于表达式
equalsTo.setLeftExpression(new Column(table, "user_id")); // 设置表达式左边值
equalsTo.setRightExpression(new StringValue("123456"));// 设置表达式右边值
PlainSelect plainSelect = (PlainSelect) select.getSelectBody(); // 转换为更细化的Select对象
plainSelect.setWhere(equalsTo);
System.err.println(plainSelect);// SELECT * FROM test WHERE test.user_id = '123456'
// WHERE != <>
NotEqualsTo notEqualsTo = new NotEqualsTo();
notEqualsTo.setLeftExpression(new Column(table, "user_id")); // 设置表达式左边值
notEqualsTo.setRightExpression(new StringValue("123456"));// 设置表达式右边值
PlainSelect plainSelectNot = (PlainSelect) select.getSelectBody();
plainSelectNot.setWhere(notEqualsTo);
System.err.println(plainSelectNot);// SELECT * FROM test WHERE test.user_id <> '123456'
// 其他运算符, 参考上面代码添加表达式即可
GreaterThan gt = new GreaterThan(); // ">"
GreaterThanEquals geq = new GreaterThanEquals(); // ">="
MinorThan mt = new MinorThan(); // "<"
MinorThanEquals leq = new MinorThanEquals();// "<="
IsNullExpression isNull = new IsNullExpression(); // "is null"
isNull.setNot(true);// "is not null"
LikeExpression nlike = new LikeExpression();
nlike.setNot(true); // "not like"
Between bt = new Between();
bt.setNot(true);// "not between"
// WHERE LIKE
LikeExpression likeExpression = new LikeExpression(); // 创建Like表达式对象
likeExpression.setLeftExpression(new Column("username")); // 表达式左边
likeExpression.setRightExpression(new StringValue("张%")); // 右边表达式
PlainSelect plainSelectLike = (PlainSelect) select.getSelectBody();
plainSelectLike.setWhere(likeExpression);
System.err.println(plainSelectLike); // SELECT * FROM test WHERE username LIKE '张%'
// WHERE IN
Set<String> deptIds = Sets.newLinkedHashSet(); // 创建IN范围的元素集合
deptIds.add("0001");
deptIds.add("0002");
var itemsList = new ExpressionList(deptIds.stream().map(StringValue::new).collect(Collectors.toList())); // 把集合转变为JSQLParser需要的元素列表
InExpression inExpression = new InExpression(new Column("dept_id "), itemsList); // 创建IN表达式对象传入列名及IN范围列表
PlainSelect plainSelectIn = (PlainSelect) select.getSelectBody();
plainSelectIn.setWhere(inExpression);
System.err.println(plainSelectIn); // SELECT * FROM test WHERE dept_id IN ('0001', '0002')
// WHERE BETWEEN AND
Between between = new Between();
between.setBetweenExpressionStart(new LongValue(18)); // 设置起点值
between.setBetweenExpressionEnd(new LongValue(30)); // 设置终点值
between.setLeftExpression(new Column("age")); // 设置左边的表达式,一般为列
PlainSelect plainSelectBetween = (PlainSelect) select.getSelectBody();
plainSelectBetween.setWhere(between);
System.err.println(plainSelectBetween); // SELECT * FROM test WHERE age BETWEEN 18 AND 30
// WHERE AND 多个条件结合,都需要成立
AndExpression andExpression = new AndExpression(); // AND 表达式
andExpression.setLeftExpression(equalsTo); // AND 左边表达式
andExpression.setRightExpression(between); // AND 右边表达式
PlainSelect plainSelectAnd = (PlainSelect) select.getSelectBody();
plainSelectAnd.setWhere(andExpression);
System.err.println(plainSelectAnd); // SELECT * FROM test WHERE test.user_id = '123456' AND age BETWEEN 18 AND 30
// WHERE OR 多个条件满足一个条件成立返回
OrExpression orExpression = new OrExpression();// OR 表达式
orExpression.setLeftExpression(equalsTo); // OR 左边表达式
orExpression.setRightExpression(between); // OR 右边表达式
PlainSelect plainSelectOr = (PlainSelect) select.getSelectBody();
plainSelectOr.setWhere(orExpression);
System.err.println(plainSelectOr); // SELECT * FROM test WHERE test.user_id = '123456' OR age BETWEEN 18 AND 30
// ORDER BY 排序
OrderByElement orderByElement = new OrderByElement(); // 创建排序对象
orderByElement.isAsc(); // 设置升序排列 从小到大
orderByElement.setExpression(new Column("col01")); // 设置排序字段
PlainSelect plainSelectOrderBy = (PlainSelect) select.getSelectBody();
plainSelectOrderBy.addOrderByElements(orderByElement);
System.err.println(plainSelectOrderBy); // SELECT * FROM test WHERE test.user_id = '123456' OR age BETWEEN 18 AND 30 ORDER BY col01
}
@Test
public void test20() throws Exception {
// 单表全量
Table table = new Table("test");
Select select = SelectUtils.buildSelectFromTable(table);
System.err.println(select); // SELECT * FROM test
EqualsTo equalsTo = new EqualsTo(); // 等于表达式
equalsTo.setLeftExpression(new Column(table, "user_id")); // 设置表达式左边值
equalsTo.setRightExpression(new StringValue("123456"));// 设置表达式右边值
final var in = CCJSqlParserUtil.parseExpression("u.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in (1,2) )");
PlainSelect plainSelectIn = (PlainSelect) select.getSelectBody();
plainSelectIn.setWhere(
new AndExpression(equalsTo, new AndExpression(equalsTo, new AndExpression(equalsTo, in)))
);
System.err.println(plainSelectIn); // SELECT * FROM test WHERE dept_id IN ('0001', '0002')
}
@Test
public void test21() throws Exception {
Select childSelect = SelectUtils.buildSelectFromTableAndExpressions(
new Table("sys_role_dept"),
new Column("dept_id")
);
Set<String> deptIds = Set.of("10001", "10002", "10003");
var itemsList = new ExpressionList<>(deptIds.stream().map(StringValue::new).collect(Collectors.toList()));
InExpression inExpression = new InExpression(new Column("dept_id "), itemsList);
childSelect.getPlainSelect().setWhere(inExpression);
System.err.println(childSelect);
Select select = SelectUtils.buildSelectFromTable(
new Table("sys_role")
);
EqualsTo equalsTo = new EqualsTo(); // 等于表达式
equalsTo.setLeftExpression(new Column("user_id")); // 设置表达式左边值
equalsTo.setRightExpression(childSelect);// 设置表达式右边值
select.getPlainSelect().setWhere(equalsTo);
System.err.println(select.getPlainSelect());// SELECT * FROM test WHERE test.user_id = '123456'
}
}

View File

@@ -12,7 +12,6 @@ import com.xaaef.molly.auth.service.JwtTokenService;
import com.xaaef.molly.auth.service.LineCaptchaService;
import com.xaaef.molly.auth.service.RsaAsymmetricCryptoService;
import com.xaaef.molly.auth.service.UserLoginService;
import com.xaaef.molly.common.consts.DataScopeConst;
import com.xaaef.molly.common.domain.CustomRequestInfo;
import com.xaaef.molly.common.enums.AdminFlag;
import com.xaaef.molly.common.enums.StatusEnum;
@@ -38,6 +37,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static com.xaaef.molly.common.consts.DataScopeConst.*;
/**
* <p>
@@ -248,7 +248,7 @@ public class UserLoginServiceImpl implements UserLoginService {
return Set.of();
}
// 角色列表中是否包含 1.全部数据权限
var isAll = target.getRoles().stream().anyMatch(a -> Objects.equals(a.getDataScope(), DataScopeConst.All));
var isAll = target.getRoles().stream().anyMatch(a -> Objects.equals(a.getDataScope(), DATA_SCOPE_ALL));
if (isAll) {
return deptService.listDeptIdByAll();
}
@@ -256,7 +256,7 @@ public class UserLoginServiceImpl implements UserLoginService {
var depsIds = new HashSet<Long>();
// 角色列表中是否包含 2.自定数据权限
var roleIds = target.getRoles().stream()
.filter(a -> Objects.equals(a.getDataScope(), DataScopeConst.CUSTOM))
.filter(a -> Objects.equals(a.getDataScope(), DATA_SCOPE_CUSTOM))
.map(PmsRoleDTO::getRoleId).collect(Collectors.toSet());
if (!roleIds.isEmpty()) {
var v1 = deptService.listDeptIdByRuleId(roleIds);
@@ -264,13 +264,13 @@ public class UserLoginServiceImpl implements UserLoginService {
}
// 角色列表中是否包含 3.仅本部门数据权限
var isOnlyMe = target.getRoles().stream().anyMatch(a -> Objects.equals(a.getDataScope(), DataScopeConst.ONLY_ME));
var isOnlyMe = target.getRoles().stream().anyMatch(a -> Objects.equals(a.getDataScope(), DATA_SCOPE_DEPT));
if (isOnlyMe) {
depsIds.add(target.getDeptId());
}
// 角色列表中是否包含 4本部门及以下数据权限
var isMeAndChild = target.getRoles().stream().anyMatch(a -> Objects.equals(a.getDataScope(), DataScopeConst.ME_AND_CHILD));
var isMeAndChild = target.getRoles().stream().anyMatch(a -> Objects.equals(a.getDataScope(), DATA_SCOPE_DEPT_AND_CHILD));
if (isMeAndChild) {
var v1 = deptService.listChildIdByDeptId(target.getDeptId());
depsIds.addAll(v1);

View File

@@ -16,6 +16,11 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>

View File

@@ -0,0 +1,44 @@
package com.xaaef.molly.tenant.base;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* 项目基础类
* </p>
*
* @author WangChenChen
* @version 1.1
* @date 2022/12/9 13:39
*/
@Getter
@Setter
public class ParamBaseEntity extends BaseEntity implements java.io.Serializable {
/**
* 参数
*/
@JsonIgnore
@TableField(exist = false)
private Map<String, Object> params;
@JsonIgnore
public Map<String, Object> getParamsValue() {
if (params == null) {
params = new HashMap<>();
}
return params;
}
public void setParamsValue(Map<String, Object> params) {
this.params = params;
}
}

View File

@@ -0,0 +1,24 @@
package com.xaaef.molly.tenant.ds;
import java.lang.annotation.*;
/**
* 数据权限过滤注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope {
/**
* 部门的别名
*/
String deptAlias() default "d";
/**
* 用户表的别名
*/
String userAlias() default "u";
}

View File

@@ -0,0 +1,123 @@
package com.xaaef.molly.tenant.ds;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.xaaef.molly.auth.jwt.JwtLoginUser;
import com.xaaef.molly.auth.jwt.JwtSecurityUtils;
import com.xaaef.molly.tenant.base.ParamBaseEntity;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import static com.xaaef.molly.common.consts.DataScopeConst.*;
/**
* 数据过滤处理
*/
@Aspect
@Component
public class DataScopeAspect {
@Before("@annotation(controllerDataScope)")
public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable {
clearDataScope(point);
handleDataScope(point, controllerDataScope);
}
protected void handleDataScope(final JoinPoint joinPoint, DataScope ds) {
if (!JwtSecurityUtils.isAuthenticated()) {
return;
}
// 平台用户 和 租户管理员,禁用数据权限
if (JwtSecurityUtils.isAdminUser() || JwtSecurityUtils.isMasterUser()) {
return;
}
// 获取当前的用户
var currentUser = JwtSecurityUtils.getLoginUser();
dataScopeFilter(joinPoint, currentUser, ds.deptAlias(), ds.userAlias());
}
/**
* 数据范围过滤
*
* @param joinPoint 切点
* @param user 用户
* @param deptAlias 部门别名
* @param userAlias 用户别名
*/
public static void dataScopeFilter(JoinPoint joinPoint, JwtLoginUser user, String deptAlias, String userAlias) {
StringBuilder sqlString = new StringBuilder();
var conditions = new ArrayList<Integer>();
var scopeCustomIds = new ArrayList<String>();
user.getRoles().forEach(role -> {
if (Objects.equals(DATA_SCOPE_CUSTOM, role.getDataScope())) {
scopeCustomIds.add(Convert.toStr(role.getRoleId()));
}
});
for (var role : user.getRoles()) {
var dataScope = role.getDataScope();
if (conditions.contains(dataScope)) {
continue;
}
if (Objects.equals(DATA_SCOPE_ALL, dataScope)) {
sqlString = new StringBuilder();
conditions.add(dataScope);
break;
} else if (Objects.equals(DATA_SCOPE_CUSTOM, dataScope)) {
if (scopeCustomIds.size() > 1) {
// 多个自定数据权限使用in查询避免多次拼接。
sqlString.append(StrUtil.format(" OR {}.dept_id IN ( SELECT dept_id FROM pms_role_dept WHERE role_id in ({}) ) ", deptAlias, String.join(",", scopeCustomIds)));
} else {
sqlString.append(StrUtil.format(" OR {}.dept_id IN ( SELECT dept_id FROM pms_role_dept WHERE role_id = {} ) ", deptAlias, role.getRoleId()));
}
} else if (Objects.equals(DATA_SCOPE_DEPT, dataScope)) {
sqlString.append(StrUtil.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
} else if (Objects.equals(DATA_SCOPE_DEPT_AND_CHILD, dataScope)) {
sqlString.append(StrUtil.format(" OR {}.dept_id IN ( SELECT dept_id FROM pms_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )", deptAlias, user.getDeptId(), user.getDeptId()));
} else if (Objects.equals(DATA_SCOPE_SELF, dataScope)) {
if (StrUtil.isNotBlank(userAlias)) {
sqlString.append(StrUtil.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
} else {
// 数据权限为仅本人且没有userAlias别名不查询任何数据
sqlString.append(StrUtil.format(" OR {}.dept_id = 0 ", deptAlias));
}
}
conditions.add(dataScope);
}
// 角色都不包含传递过来的权限字符这个时候sqlString也会为空所以要限制一下,不查询任何数据
if (CollectionUtil.isEmpty(conditions)) {
sqlString.append(StrUtil.format(" OR {}.dept_id = 0 ", deptAlias));
}
if (StrUtil.isNotBlank(sqlString.toString())) {
var params = Arrays.stream(joinPoint.getArgs()).filter(a -> a instanceof ParamBaseEntity).findFirst();
if (params.isPresent()) {
var baseEntity = (ParamBaseEntity) params.get();
baseEntity.getParamsValue().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
}
}
}
/**
* 拼接权限sql前先清空params.dataScope参数防止注入
*/
private void clearDataScope(final JoinPoint joinPoint) {
var params = Arrays.stream(joinPoint.getArgs()).filter(a -> a instanceof ParamBaseEntity).findFirst();
if (params.isPresent()) {
var baseEntity = (ParamBaseEntity) params.get();
baseEntity.getParamsValue().put(DATA_SCOPE, "");
}
}
}

View File

@@ -10,6 +10,7 @@ import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.Statements;
import net.sf.jsqlparser.util.TablesNamesFinder;
import org.apache.ibatis.executor.statement.StatementHandler;
@@ -92,7 +93,7 @@ public class SchemaInterceptor implements InnerInterceptor {
}
private final static TablesNamesFinder TABLES_NAMES_FINDER = new TablesNamesFinder();
private final static TablesNamesFinder<Statement> TABLES_NAMES_FINDER = new TablesNamesFinder<>();
/**
@@ -106,9 +107,8 @@ public class SchemaInterceptor implements InnerInterceptor {
log.error("getTableListName: \n{}", e.getMessage());
return Set.of();
}
return statements.getStatements()
.stream()
.map(TABLES_NAMES_FINDER::getTableList)
return statements.stream()
.map(TABLES_NAMES_FINDER::getTables)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
}

View File

@@ -38,7 +38,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- graalvm native-maven-plugin -->
<native-maven.version>0.9.28</native-maven.version>
<native-maven.version>0.10.3</native-maven.version>
<!-- 优化的雪花算法雪花漂移它生成的ID更短、速度更快 -->
<idgenerator.version>1.0.6</idgenerator.version>
<!-- x-file-storage文件上传 文档地址 https://x-file-storage.xuyanwu.cn -->
@@ -54,13 +54,13 @@
<!-- Excel文件操作 -->
<apache-poi.version>5.3.0</apache-poi.version>
<!-- 小而美的工具库 -->
<hutool.version>5.8.28</hutool.version>
<hutool.version>5.8.32</hutool.version>
<!-- 简单、方便的OpenAPI接口文档 -->
<knife4j.version>4.5.0</knife4j.version>
<!-- MyBatis 的增强工具,基友搭配,效率翻倍 -->
<mybatis-plus.version>3.5.7</mybatis-plus.version>
<mybatis-plus.version>3.5.8</mybatis-plus.version>
<!-- JavaEE 颠覆者 -->
<spring-boot.version>3.2.8</spring-boot.version>
<spring-boot.version>3.2.11</spring-boot.version>
</properties>

View File

@@ -1,8 +1,8 @@
import dayjs from "dayjs"
import {removeConfigLayout} from "@/utils/cache/local-storage"
import { removeConfigLayout } from "@/utils/cache/local-storage"
import chinaAreaJson from "@/assets/ChinaArea.json"
import {ISimpleProject} from "@/types/base"
import {CascaderOption} from "element-plus"
import { ISimpleProject } from "@/types/base"
import { CascaderOption } from "element-plus"
//#region 格式化日期时间
export const DEFAULT_DATE_TIME_PATTERN = "YYYY-MM-DD HH:mm:ss"
@@ -173,13 +173,14 @@ export const chinaAreaDeepQuery = (areaCode: number) => {
}
/** 将权限树形结构扁平化为一维数组,用于权限查询 */
export const flatTreeToCascaderOption = (arr: any[], { value = "id", label = "label", children = "children" }) => {
export const flatTreeToCascaderOption = (arr: any[], { value = "id", label = "label", disabled = "disabled", children = "children" }) => {
const result: CascaderOption[] = []
const deep = (arr1: any[], arr2: CascaderOption[]) => {
arr1.forEach((item: any) => {
const temp: CascaderOption = {
value: item[value],
label: item[label]
label: item[label],
disabled: item[disabled]
}
arr2.push(temp)
if (item[children] && item[children].length > 0) {