微服务版后端初始化

This commit is contained in:
yaoyn
2025-02-08 17:51:37 +08:00
parent 54af6be188
commit da009a7cc4
1897 changed files with 429541 additions and 81 deletions

View File

@ -0,0 +1,23 @@
package com.xjrsoft.organization;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
/**
* @Author: tzx
* @Date: 2023/10/8 9:35
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.xjrsoft")
@MapperScan(value = "com.xjrsoft.**.mapper")
@ComponentScan(value = "com.xjrsoft")
public class OrganizationApplication {
public static void main(String[] args) {
SpringApplication.run(OrganizationApplication.class, args);
}
}

View File

@ -0,0 +1,66 @@
package com.xjrsoft.organization.client;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.service.IDepartmentService;
import com.xjrsoft.tenant.util.TenantUtil;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author: tzx
* @Date: 2023/10/11 16:22
*/
@Hidden
@RestController
@AllArgsConstructor
public class DepartmentClient implements IDepartmentClient {
private final IDepartmentService departmentService;
private final RedisUtil redisUtil;
/**
* 根据id获取部门
* @param depId
* @return
*/
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getDepartmentByIdFeign")
public Department getDepartmentByIdFeign(Long depId) {
TenantUtil.ignore(true);
Department department = departmentService.getById(depId);
TenantUtil.clear();
return department;
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getDepartmentListByIdsFeign")
public List<Department> getDepartmentListByIdsFeign(List<Long> depIds) {
TenantUtil.ignore(true);
List<Department> departmentList = departmentService.listByIds(depIds);
TenantUtil.clear();
return departmentList;
}
@Override
@PostMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/addDepartmentFeign")
public boolean addDepartmentFeign( @RequestBody Department department) {
return departmentService.save(department);
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/departmentCacheFeign")
public void departmentCacheFeign() {
departmentService.departmentCache();
}
}

View File

@ -0,0 +1,24 @@
package com.xjrsoft.organization.client;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.organization.service.IOauthService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.request.AuthRequest;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author yjw
* @createDate 2024-07-17
*/
@Slf4j
@RequiredArgsConstructor
public class OauthClient implements IOauthClient{
private final IOauthService oauthService;
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getAuthRequestFeign")
public AuthRequest getAuthRequest(String source) {
return oauthService.getAuthRequest(source);
}
}

View File

@ -0,0 +1,60 @@
package com.xjrsoft.organization.client;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.entity.Post;
import com.xjrsoft.organization.service.IPostService;
import com.xjrsoft.tenant.util.TenantUtil;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author: tzx
* @Date: 2023/10/12 16:23
*/
@Hidden
@RestController
@AllArgsConstructor
public class PostClient implements IPostClient {
private final IPostService postService;
private final RedisUtil redisUtil;
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getPostByIdFeign")
public Post getPostByIdFeign(Long postId) {
TenantUtil.ignore(true);
Post post = postService.getById(postId);
TenantUtil.clear();
return post;
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getPostListByIdsFeign")
public List<Post> getPostListByIdsFeign(List<Long> postIds) {
TenantUtil.ignore(true);
List<Post> postList = postService.listByIds(postIds);
TenantUtil.clear();
return postList;
}
@Override
@PostMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/addPostFeign")
public boolean addPostFeign(@RequestBody Post post) {
return postService.save(post);
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/postCacheFeign")
public void postCacheFeign() {
postService.postCache();
};
}

View File

@ -0,0 +1,72 @@
package com.xjrsoft.organization.client;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.uitls.VoToColumnUtil;
import com.xjrsoft.organization.entity.Role;
import com.xjrsoft.organization.service.IRoleService;
import com.xjrsoft.organization.vo.UserRoleVo;
import com.xjrsoft.system.vo.AuthObjectVo;
import com.xjrsoft.tenant.util.TenantUtil;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @Author: tzx
* @Date: 2023/10/10 10:13
*/
@Hidden
@RestController
@AllArgsConstructor
public class RoleClient implements IRoleClient {
private final IRoleService roleService;
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getRoleListByRelationIdsFeign")
public List<Role> getRoleListByRelationIdsFeign(List<Long> relationIds) {
return roleService.list(Wrappers.lambdaQuery(Role.class)
.select(Role.class, x -> VoToColumnUtil.fieldsToColumns(UserRoleVo.class).contains(x.getColumn()))
.in(relationIds.size() > 0, Role::getId, relationIds));
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getRoleByIdsFeign")
public List<Role> getRoleByIdsFeign(List<Long> roleIds) {
return roleService.list(Wrappers.<Role>query().lambda()
.select(Role.class, x -> VoToColumnUtil.fieldsToColumns(AuthObjectVo.class).contains(x.getProperty()))
.in(Role::getId, roleIds));
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getTenantRoleFeign")
public Role getTenantRoleFeign() {
TenantUtil.ignore(Boolean.TRUE);
Role one = roleService.getOne(Wrappers.lambdaQuery(Role.class)
.select(Role::getId).lt(Role::getId, 1000L).orderByDesc(Role::getId), false);
TenantUtil.clear();
return one;
}
@Override
@PostMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/addRoleFeign")
public boolean addRoleFeign(@RequestBody Role role) {
return roleService.save(role);
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getTenantRoleLtFeign")
public Role getTenantRoleLtFeign(Long roleId) {
return roleService.getOne(Wrappers.lambdaQuery(Role.class)
.select(Role::getId).lt(Role::getId, roleId).orderByDesc(Role::getId), false);
}
}

View File

@ -0,0 +1,232 @@
package com.xjrsoft.organization.client;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.uitls.VoToColumnUtil;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.entity.*;
import com.xjrsoft.organization.model.NewTenantDefaultInfoModel;
import com.xjrsoft.organization.service.*;
import com.xjrsoft.organization.vo.UserRoleVo;
import com.xjrsoft.system.vo.AuthObjectVo;
import com.xjrsoft.tenant.config.TenantConfig;
import com.xjrsoft.tenant.util.TenantUtil;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
/**
* @Author: tzx
* @Date: 2023/10/11 14:48
*/
@Hidden
@RestController
@AllArgsConstructor
public class UserClient implements IUserClient {
private final IUserService userService;
private final IRoleService roleService;
private final IUserRoleRelationService userRoleRelationService;
private final IDepartmentService departmentService;
private final IUserDeptRelationService userDeptRelationService;
private final IPostService postService;
private final IUserPostRelationService userPostRelationService;
private final RedisUtil redisUtil;
private final TenantConfig tenantConfig;
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/getUserByIdsFeign")
public List<User> getUserByIdsFeign(List<Long> userIds) {
return userService.list(Wrappers.<User>query().lambda()
.select(User.class, x -> VoToColumnUtil.fieldsToColumns(AuthObjectVo.class).contains(x.getProperty()))
.in(User::getId, userIds));
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/getUserByUserNameFeign")
public User getUserByUserNameFeign(String userName) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUserName, userName);
return userService.getOne(queryWrapper);
}
@Override
public User getTenantUserByUserNameNoTenantFeign(String userName, Long tenantId) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUserName, userName);
if (tenantConfig.getEnabled()) {
queryWrapper.eq(User::getTenantId, tenantId);
}
TenantUtil.ignore(true);
User one = userService.getOne(queryWrapper);
TenantUtil.clear();
return one;
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/userCacheFeign")
public void userCacheFeign() {
List<User> list = userService.list();
redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);
}
@Override
@PostMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/addUserFeign")
public boolean addUserFeign(@RequestBody User user) {
return userService.save(user);
}
@Override
@PostMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/addTenantDefInfoFeign")
public boolean addTenantDefInfoFeign(Long tenantId) {
String tenantDefaultInfo = FileUtil.readString(ResourceUtil.getResource("./new_tenant_default_admin_info.json"), StandardCharsets.UTF_8);
NewTenantDefaultInfoModel defaultInfo =
BeanUtil.mapToBean(JSONUtil.parseObj(tenantDefaultInfo), NewTenantDefaultInfoModel.class, true, CopyOptions.create());
User user = defaultInfo.getUser();
Role role = defaultInfo.getRole();
if (user == null || role == null) {
throw new RuntimeException("请完善租户默认管理员用户信息配置!");
}
TenantUtil.ignore(Boolean.TRUE);
user.setTenantId(tenantId);
user.setPassword(SaSecureUtil.md5BySalt(user.getPassword(), GlobalConstant.SECRET_KEY));
userService.save(user);
//优化方案 使用一个feign 调用 解决所有问题
//可以优化多个服务调用的时间
//目前此处因为是租户管理 不会有性能方面影响 所以 暂时分多个feign调用
Role one = roleService.getOne(Wrappers.lambdaQuery(Role.class)
.select(Role::getId).lt(Role::getId, 1000L).orderByDesc(Role::getId), false);
if (one != null) {
role.setId(one.getId() + 1L);
} else {
role.setId(1L);
}
role.setTenantId(tenantId);
roleService.save(role);
UserRoleRelation userRoleRelation = new UserRoleRelation();
userRoleRelation.setUserId(user.getId());
userRoleRelation.setRoleId(role.getId());
userRoleRelation.setTenantId(tenantId);
userRoleRelationService.save(userRoleRelation);
Department department = defaultInfo.getDepartment();
if (department != null) {
department.setTenantId(tenantId);
departmentService.save(department);
UserDeptRelation userDeptRelation = new UserDeptRelation();
userDeptRelation.setDeptId(department.getId());
userDeptRelation.setUserId(user.getId());
userDeptRelation.setTenantId(tenantId);
userDeptRelationService.save(userDeptRelation);
Post post = defaultInfo.getPost();
if (post != null) {
post.setDeptId(department.getId());
post.setTenantId(tenantId);
postService.save(post);
UserPostRelation userPostRelation = new UserPostRelation();
userPostRelation.setPostId(post.getId());
userPostRelation.setUserId(user.getId());
userPostRelation.setTenantId(tenantId);
userPostRelationService.save(userPostRelation);
}
}
// 更新缓存
CompletableFuture.runAsync(() -> {
TenantUtil.ignore(true);
List<User> userList = userService.list();
redisUtil.set(GlobalConstant.USER_CACHE_KEY, userList);
List<Department> departmentList = departmentService.list();
redisUtil.set(GlobalConstant.DEP_CACHE_KEY, departmentList);
List<Role> roleList = roleService.list();
redisUtil.set(GlobalConstant.ROLE_CACHE_KEY, roleList);
List<Post> postList = postService.list();
redisUtil.set(GlobalConstant.POST_CACHE_KEY, postList);
List<UserRoleRelation> list = userRoleRelationService.list();
redisUtil.set(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY,list);
List<UserDeptRelation> deptRelationList = userDeptRelationService.list();
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, deptRelationList);
List<UserPostRelation> postRelationList = userPostRelationService.list();
redisUtil.set(GlobalConstant.USER_POST_RELATION_CACHE_KEY, postRelationList);
TenantUtil.clear();
});
TenantUtil.clear();
return true;
}
@Override
@PostMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/updateUserInfoFeign")
public boolean updateUserInfoFeign(@RequestBody User user) {
return userService.updateById(user);
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/getDepartmentsOfUserIdFeign")
public List<Department> queryDepartmentsOfUserIdFeign(Long id) {
return userService.queryDepartmentsOfUser(id);
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/queryRolesOfUserFeign")
public List<UserRoleVo> queryRolesOfUserFeign(Long id) {
return userService.queryRolesOfUser(id);
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/getUserByMobileFeign")
public User getUserByMobileFeign(String mobile) {
return userService.getUserByMobile(mobile);
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/getUserByCodeFeign")
public User getUserByCodeFeign(String code) {
return userService.getUserByCode(code);
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/getUserByIdsFeignSet")
public List<User> getUserByIdsFeignSet(Set<String> userIds) {
return userService.list(Wrappers.<User>query().lambda()
.select(User.class, x -> VoToColumnUtil.fieldsToColumns(AuthObjectVo.class).contains(x.getProperty()))
.in(User::getId, userIds));
}
}

View File

@ -0,0 +1,44 @@
package com.xjrsoft.organization.client;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.organization.entity.UserDeptRelation;
import com.xjrsoft.organization.service.IUserDeptRelationService;
import com.xjrsoft.tenant.util.TenantUtil;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @Author: tzx
* @Date: 2023/10/10 10:36
*/
@Hidden
@RestController
@AllArgsConstructor
public class UserDeptRelationClient implements IUserDeptRelationClient {
private final IUserDeptRelationService userDeptRelationService;
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getUserDeptRelationListFeign")
public List<UserDeptRelation> getUserDeptRelationListFeign(Long userId) {
TenantUtil.ignore(true);
List<UserDeptRelation> userDeptRelationList = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class)
.eq(UserDeptRelation::getUserId, userId));
TenantUtil.clear();
return userDeptRelationList;
}
@Override
@PostMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/addUserDeptRelationFeign")
public boolean addUserDeptRelationFeign(@RequestBody UserDeptRelation userDeptRelation) {
return userDeptRelationService.save(userDeptRelation);
}
}

View File

@ -0,0 +1,43 @@
package com.xjrsoft.organization.client;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.organization.entity.UserPostRelation;
import com.xjrsoft.organization.service.IUserPostRelationService;
import com.xjrsoft.tenant.util.TenantUtil;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @Author: tzx
* @Date: 2023/10/12 16:19
*/
@Hidden
@RestController
@AllArgsConstructor
public class UserPostRelationClient implements IUserPostRelationClient {
private final IUserPostRelationService userPostRelationService;
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/getUserPostRelationListFeign")
public List<UserPostRelation> getUserPostRelationListFeign(Long userId) {
TenantUtil.ignore(true);
List<UserPostRelation> userPostRelations = userPostRelationService.list(Wrappers.lambdaQuery(UserPostRelation.class)
.eq(UserPostRelation::getUserId, userId));
TenantUtil.clear();
return userPostRelations;
}
@Override
@PostMapping(GlobalConstant.CLIENT_API_PRE + GlobalConstant.MODULE_ORGANIZATION_NAME + "/addUserPostRelationFeign")
public boolean addUserPostRelationFeign(@RequestBody UserPostRelation userPostRelation) {
return userPostRelationService.save(userPostRelation);
}
}

View File

@ -0,0 +1,61 @@
package com.xjrsoft.organization.client;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.organization.entity.UserRoleRelation;
import com.xjrsoft.organization.service.IUserRoleRelationService;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @Author: tzx
* @Date: 2023/10/10 10:27
*/
@Hidden
@RestController
@AllArgsConstructor
public class UserRoleRelationClient implements IUserRoleRelationClient {
private final IUserRoleRelationService userRoleRelationService;
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getUserRoleRelationListByUserIdFeign")
public List<UserRoleRelation> getUserRoleRelationListByUserIdFeign(Long userId) {
return userRoleRelationService.list(Wrappers.lambdaQuery(UserRoleRelation.class)
.eq(UserRoleRelation::getUserId, userId));
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/getUserRoleRelationListByRoleIdFeigh")
public List<UserRoleRelation> getUserRoleRelationListByRoleIdFeigh(Long roleId) {
return userRoleRelationService.list(Wrappers.lambdaQuery(UserRoleRelation.class)
.eq(UserRoleRelation::getRoleId, roleId).select(UserRoleRelation::getUserId));
}
@Override
@GetMapping(GlobalConstant.CLIENT_API_PRE+ GlobalConstant.MODULE_ORGANIZATION_NAME + "/addUserRoleRelationFeign")
public boolean addUserRoleRelationFeign(@RequestBody UserRoleRelation userRoleRelation) {
return userRoleRelationService.save(userRoleRelation);
}
@Override
public List<UserRoleRelation> list(UserRoleRelation userRoleRelation) {
MPJLambdaWrapper<UserRoleRelation> queryWrapper = new MPJLambdaWrapper<>();
queryWrapper.eq(ObjectUtils.isNotEmpty(userRoleRelation.getRoleId()), UserRoleRelation::getRoleId, userRoleRelation.getRoleId());
return userRoleRelationService.list(queryWrapper);
}
}

View File

@ -0,0 +1,399 @@
package com.xjrsoft.organization.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
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.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.core.annotation.XjrLog;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.domain.page.PageOutput;
import com.xjrsoft.common.core.domain.result.R;
import com.xjrsoft.common.core.enums.YesOrNoEnum;
import com.xjrsoft.common.core.uitls.TreeUtil;
import com.xjrsoft.common.core.uitls.VoToColumnUtil;
import com.xjrsoft.common.mybatis.utils.ConventPage;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.dto.*;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.entity.User;
import com.xjrsoft.organization.entity.UserDeptRelation;
import com.xjrsoft.organization.service.IDepartmentService;
import com.xjrsoft.organization.service.IUserDeptRelationService;
import com.xjrsoft.organization.service.IUserService;
import com.xjrsoft.organization.vo.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* <p>
* 机构 前端控制器
* </p>
*
* @author tzx
* @since 2022-03-02
*/
@RestController
@RequestMapping(GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/department")
@Tag(name = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/department", description = "机构")
@AllArgsConstructor
public class DepartmentController {
private final IDepartmentService departmentService;
private final IUserService userService;
private final IUserDeptRelationService userDeptRelationService;
private final RedisUtil redisUtil;
@GetMapping(value = "/list")
@Operation(summary = "机构列表(不分页)")
@XjrLog(value = "获取不分页机构列表")
public R list() {
List<Department> list = departmentService.list(Wrappers.lambdaQuery(Department.class)
.orderByAsc(Department::getSortCode)
.select(Department.class, x -> VoToColumnUtil.fieldsToColumns(DepartmentListVo.class).contains(x.getProperty())));
List<DepartmentListVo> departmentListVos = BeanUtil.copyToList(list, DepartmentListVo.class);
return R.ok(departmentListVos);
}
@GetMapping(value = "/page")
@Operation(summary = "机构列表(分页)")
@XjrLog(value = "获取分页机构列表")
public R page(DepartmentPageDto dto) {
LambdaQueryWrapper<Department> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StrUtil.isNotBlank(dto.getKeyword()), Department::getName, dto.getKeyword())
.like(StrUtil.isNotBlank(dto.getKeyword()), Department::getCode, dto.getKeyword())
.like(StrUtil.isNotBlank(dto.getName()), Department::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getCode()), Department::getCode, dto.getCode())
.like(ObjectUtil.isNotEmpty(dto.getEnabledMark()), Department::getEnabledMark, dto.getEnabledMark())
.orderByAsc(Department::getSortCode)
.select(Department.class, x -> VoToColumnUtil.fieldsToColumns(DepartmentPageVo.class).contains(x.getProperty()));
IPage<Department> page = departmentService.page(ConventPage.getPage(dto), queryWrapper);
PageOutput<DepartmentPageVo> pageOutput = ConventPage.getPageOutput(page, DepartmentPageVo.class);
return R.ok(pageOutput);
}
@GetMapping(value = "/enabled-tree")
@Operation(summary = "机构树")
@XjrLog(value = "部门展示 所有数据")
public R tree(DepartmentTreeDto dto) {
List<Department> list = departmentService.list(Wrappers.<Department>lambdaQuery()
.like(StrUtil.isNotBlank(dto.getName()), Department::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getCode()), Department::getCode, dto.getCode())
.like(ObjectUtil.isNotEmpty(dto.getEnabledMark()), Department::getEnabledMark, dto.getEnabledMark())
.orderByAsc(Department::getSortCode)
.select(Department.class, x -> VoToColumnUtil.fieldsToColumns(DepartmentTreeVo.class).contains(x.getProperty())));
List<DepartmentTreeVo> voList = BeanUtil.copyToList(list, DepartmentTreeVo.class);
List<Department>rootDepartment=departmentService.getRootDepartment();
List<DepartmentTreeVo> treeVoList = TreeUtil.build(voList,false,rootDepartment!=null?rootDepartment.stream().map(Department::getId).collect(Collectors.toList()) : null);
return R.ok(treeVoList);
}
@GetMapping(value = "/tree")
@Operation(summary = "部门展示 (忽略 未启用的数据)")
@XjrLog(value = "部门展示 (忽略 未启用的数据)")
public R treeEnabled(DepartmentTreeDto dto) {
List<Department> list = departmentService.list(Wrappers.<Department>lambdaQuery()
.like(StrUtil.isNotBlank(dto.getName()), Department::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getCode()), Department::getCode, dto.getCode())
.like(ObjectUtil.isNotEmpty(dto.getEnabledMark()), Department::getEnabledMark, dto.getEnabledMark())
.orderByAsc(Department::getSortCode)
.select(Department.class, x -> VoToColumnUtil.fieldsToColumns(DepartmentTreeVo.class).contains(x.getProperty())));
List<DepartmentTreeVo> voList = BeanUtil.copyToList(list, DepartmentTreeVo.class);
//所有需要过滤掉下级节点的deptIds
List<Long> deptIds = new ArrayList<>();
for (DepartmentTreeVo departmentTreeVo : voList) {
if (departmentTreeVo.getEnabledMark() == YesOrNoEnum.NO.getCode()) {
//如果有下级,下级进行过滤,不显示到前端去
deptIds.add(departmentTreeVo.getId());
departmentTreeVo.setDisabled(true);
} else {
departmentTreeVo.setDisabled(false);
}
}
//所有需要过滤的ids的集合
List<Long> allChildIds = departmentService.getAllChildIds(deptIds, voList);
//不是组织管理模块请求过滤父级,如果是组织管理isOrg不为空,不用过滤
if (ObjectUtil.isEmpty(dto.getIsOrg())) {
//将父级节点也过滤掉
allChildIds.addAll(deptIds);
}
List<DepartmentTreeVo> vo = voList.stream().filter(u -> !allChildIds.contains(u.getId())).collect(Collectors.toList());
List<Department>rootDepartment=departmentService.getRootDepartment();
List<DepartmentTreeVo> treeVoList = TreeUtil.build(vo,false,rootDepartment!=null?rootDepartment.stream().map(Department::getId).collect(Collectors.toList()) : null);
for (DepartmentTreeVo departmentTreeVo : treeVoList) {
if (departmentTreeVo.getParentId() == 0) {
departmentTreeVo.setParentId(null);
}
}
return R.ok(treeVoList);
}
@GetMapping(value = "/trees")
@Operation(summary = "部门展示 (忽略 未启用的数据)")
@XjrLog(value = "部门展示 (忽略 未启用的数据)")
public R treeEnableds(DepartmentTreeDto dto) {
List<String> deptPIds = null;
if (dto.isParentNode() && StrUtil.isNotBlank(dto.getId())){
deptPIds = departmentService.findDeptPIds(dto.getId());
}
List<String> idsList = null;
if(StrUtil.isNotBlank(dto.getIds()))
{
idsList = Arrays.asList(dto.getIds().split(","));
}
List<Long>rootDepartmentIds=null;
//如果没有传参指定部门,则获取根部门
if(StrUtil.isBlank(dto.getId())&&StrUtil.isBlank(dto.getIds())){
List<Department>rootDepartment=departmentService.getRootDepartment();
if(rootDepartment!=null){
rootDepartmentIds=rootDepartment.stream().map(Department::getId).collect(Collectors.toList());
}
}
List<Department> list = departmentService.list(Wrappers.<Department>lambdaQuery()
.like(StrUtil.isNotBlank(dto.getName()), Department::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getCode()), Department::getCode, dto.getCode())
.like(ObjectUtil.isNotEmpty(dto.getEnabledMark()), Department::getEnabledMark, dto.getEnabledMark())
//非isParentNode指定查询父路径时根据传参id查询本级和下一级部门
.eq(StrUtil.isNotBlank(dto.getId()) && !dto.isParentNode(), Department::getId, dto.getId()).or()
.eq(StrUtil.isNotBlank(dto.getId()) && !dto.isParentNode(), Department::getParentId, dto.getId())
//isParentNode指定查询父路径时根据传参id查询父路径上所有部门的下一级部门
.in(dto.isParentNode() && StrUtil.isNotBlank(dto.getId()), Department::getParentId, deptPIds)
//传参ids查询多个指定部门
.in(StrUtil.isNotBlank(dto.getIds()),Department::getId, idsList)
//查询指定根部门
.in(CollectionUtil.isNotEmpty(rootDepartmentIds),Department::getId,rootDepartmentIds)
//查询默认根部门
.eq(StrUtil.isBlank(dto.getId())&&StrUtil.isBlank(dto.getIds())&&CollectionUtil.isEmpty(rootDepartmentIds), Department::getParentId, Constants.ZERO)
.orderByAsc(Department::getSortCode)
.select(Department.class, x -> VoToColumnUtil.fieldsToColumns(DepartmentTreeVo.class).contains(x.getProperty())));
if (StrUtil.isBlank(dto.getId()) && !CollectionUtils.isEmpty(list)){
List<Long> ids = list.stream().map(s -> s.getId()).collect(Collectors.toList());
List<Department> childrenList = departmentService.list(Wrappers.<Department>lambdaQuery()
.in(Department::getParentId, ids)
.orderByAsc(Department::getSortCode));
list.addAll(childrenList);
}
departmentService.queryPathFromRoot(list);
List<DepartmentTreeVo> voList = BeanUtil.copyToList(list, DepartmentTreeVo.class);
//所有需要过滤掉下级节点的deptIds
List<Long> deptIds = new ArrayList<>();
for (DepartmentTreeVo departmentTreeVo : voList) {
if (departmentTreeVo.getEnabledMark() == YesOrNoEnum.NO.getCode()) {
//如果有下级,下级进行过滤,不显示到前端去
deptIds.add(departmentTreeVo.getId());
departmentTreeVo.setDisabled(true);
} else {
departmentTreeVo.setDisabled(false);
}
}
//所有需要过滤的ids的集合
List<Long> allChildIds = departmentService.getAllChildIds(deptIds, voList);
//不是组织管理模块请求过滤父级,如果是组织管理isOrg不为空,不用过滤
if (ObjectUtil.isEmpty(dto.getIsOrg())) {
//将父级节点也过滤掉
allChildIds.addAll(deptIds);
}
List<DepartmentTreeVo> vo = voList.stream().filter(u -> !allChildIds.contains(u.getId())).collect(Collectors.toList());
List<DepartmentTreeVo> treeVoList;
if (dto.isParentNode()){
treeVoList = TreeUtil.build(vo);
}else {
treeVoList = TreeUtil.buildTwoTree(vo);
}
for (DepartmentTreeVo departmentTreeVo : treeVoList) {
if (departmentTreeVo.getParentId() == 0) {
departmentTreeVo.setParentId(null);
}
}
return R.ok(treeVoList);
}
@GetMapping(value = "/getDepartments")
@Operation(summary = "获取公司下面的一级部门")
@XjrLog(value = "一级部门数据")
public R getDepartmentsByParentId(@RequestParam Long id) {
List<Department> childrenList = new ArrayList<>();
if (id != null){
childrenList = departmentService.getChildrenDepartmentInfo(id);
}
return R.ok(childrenList);
}
@GetMapping(value = "/info")
@Operation(summary = "根据id查询机构信息")
@XjrLog(value = "id查询获取机构信息")
public R info(@RequestParam Long id) {
Department dept = departmentService.getById(id);
if (dept == null) {
R.error("找不到此机构!");
}
DepartmentVo departmentVo = BeanUtil.toBean(dept, DepartmentVo.class);
return R.ok(departmentVo);
}
@PostMapping
@Operation(summary = "新增机构")
@XjrLog(value = "新增机构")
public R add(@Valid @RequestBody AddDepartmentDto dto) {
long count = departmentService.count(Wrappers.<Department>query().lambda().eq(Department::getName, dto.getName())
.eq(Department::getParentId, ObjectUtil.isEmpty(dto.getParentId())?0L:dto.getParentId()));
if (count > 0) {
return R.error("同一父机构下已经存在相同名称的机构!");
}
count = departmentService.count(Wrappers.<Department>query().lambda().eq(Department::getCode, dto.getCode()));
if (count > 0) {
return R.error("机构编码已经存在!");
}
Department department = BeanUtil.toBean(dto, Department.class);
if (ObjectUtil.isEmpty(dto.getParentId())) {
department.setParentId(0L);
}
departmentService.save(department);
//设置层级
if (ObjectUtil.isNotEmpty(dto.getParentId())){
List<Department> list = redisUtil.get(GlobalConstant.DEP_CACHE_KEY,new TypeReference<List<Department>>() {
});
//获取父级的层级
String hierarchy = list.stream().filter(x->x.getId().equals(dto.getParentId())).findFirst().orElse(new Department()).getHierarchy();
//在父级的基础上添加层级
department.setHierarchy(hierarchy + StringPool.DASH + department.getId());
}else {
department.setHierarchy(department.getId().toString());
}
departmentService.updateById(department);
CompletableFuture.runAsync(departmentService::departmentCache);
return R.ok(true);
}
@PutMapping
@Operation(summary = "修改机构")
@XjrLog(value = "修改机构")
public R update(@Valid @RequestBody UpdateDepartmentDto dto) {
long count = departmentService.count(Wrappers.<Department>query().lambda()
.eq(Department::getName, dto.getName())
.eq(Department::getParentId, ObjectUtil.isEmpty(dto.getParentId())?0L:dto.getParentId())
.ne(Department::getId, dto.getId()));
if (count > 0) {
return R.error("同一父机构下已经存在相同名称的机构!");
}
count = departmentService.count(Wrappers.<Department>query().lambda()
.eq(Department::getCode, dto.getCode())
.ne(Department::getId, dto.getId()));
if (count > 0) {
return R.error("机构编码已经存在!");
}
Department department = BeanUtil.toBean(dto, Department.class);
if (department.getParentId() == null) {
department.setParentId(0L);
}
departmentService.updateById(department);
CompletableFuture.runAsync(departmentService::departmentCache);
return R.ok(true);
}
@DeleteMapping
@Operation(summary = "删除")
@XjrLog(value = "删除机构")
public R delete(@RequestBody List<Long> ids) {
//删除岗位时,需要判断,此机构下是不是存在人员,存在人员就不能删除
List<UserDeptRelation> userDeptRelationList = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
});
//拿ids进行过滤如果存在就不能删除
List<UserDeptRelation> users = userDeptRelationList.stream().filter(u -> ids.contains(u.getDeptId())).collect(Collectors.toList());
if (users.size()>0){
return R.error("此机构下存在用户!");
}
departmentService.removeBatchByIds(ids);
CompletableFuture.runAsync(departmentService::departmentCache);
return R.ok(true);
}
@PostMapping("add-dept-user")
@Operation(summary = "添加人员(组织)")
@Transactional(rollbackFor = Exception.class)
public R addDeptUser(@Valid @RequestBody AddDepartmentUserDto dto) {
//先删除再新增
userDeptRelationService.remove(Wrappers.<UserDeptRelation>query().lambda().eq(UserDeptRelation::getDeptId,dto.getId()));
List<UserDeptRelation> userDeptRelationList = new ArrayList<>();
if (CollectionUtil.isNotEmpty(dto.getUserIds())){
for (Long userId : dto.getUserIds()) {
//将用户所选部门保存到关联表中
UserDeptRelation userDeptRelation = new UserDeptRelation();
userDeptRelation.setUserId(userId);
userDeptRelation.setDeptId(dto.getId());
userDeptRelationList.add(userDeptRelation);
}
}
userDeptRelationService.saveBatch(userDeptRelationList);
//更新缓存
CompletableFuture.runAsync(() -> {
List<UserDeptRelation> deptRelationList = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class));
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, deptRelationList);
});
return R.ok(true);
}
@GetMapping(value = "/dept-user-info")
@Operation(summary = "根据组织id查询组织下的人员")
public R DeptUserInfo(@RequestParam Long id) {
List<Long> userIdList = userDeptRelationService.list(Wrappers.<UserDeptRelation>query().lambda().eq(UserDeptRelation::getDeptId, id)).stream().map(UserDeptRelation::getUserId).collect(Collectors.toList());
if (CollectionUtils.isEmpty(userIdList)) {
return R.ok(new ArrayList<>());
}
List<User> users = userService.list(Wrappers.<User>query().lambda().in(User::getId, userIdList).select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserRoleVo.class).contains(x.getProperty())));
List<UserRoleVo> userRoleVos = BeanUtil.copyToList(users, UserRoleVo.class);
return R.ok(userRoleVos);
}
}

View File

@ -0,0 +1,125 @@
package com.xjrsoft.organization.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.core.annotation.XjrLog;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.domain.page.PageOutput;
import com.xjrsoft.common.core.domain.result.R;
import com.xjrsoft.common.core.enums.EnabledMark;
import com.xjrsoft.common.core.uitls.ListUtils;
import com.xjrsoft.common.core.uitls.TreeUtil;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.dto.DingDeptSettingDto;
import com.xjrsoft.organization.dto.UserPageDto;
import com.xjrsoft.organization.dto.WeChatDepartPageDto;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.entity.UserDeptRelation;
import com.xjrsoft.organization.service.DingtalkService;
import com.xjrsoft.organization.service.IDepartmentService;
import com.xjrsoft.organization.service.IUserDeptRelationService;
import com.xjrsoft.organization.service.IUserService;
import com.xjrsoft.organization.vo.DepartmentTreeVo;
import com.xjrsoft.organization.vo.UserPageVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@RestController
@RequestMapping(value = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/ding-talk")
@Tag(name = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/ding-talk", description = "钉钉信息")
@AllArgsConstructor
public class DingtalkController {
private final IUserService userService;
private final IUserDeptRelationService userDeptRelationService;
private final IDepartmentService departmentService;
private DingtalkService dingtalkService;
private RedisUtil redisUtil;
@PutMapping("/sync-user/to-dingtalk")
@Operation(summary = "微信信息更新")
public R syncUsersToDingTalk(@RequestParam Long departmentId) {
dingtalkService.syncUsersToDingTalk(departmentId);
/*CompletableFuture.runAsync(() -> {
//???没有修改系统数据有必要刷缓存?
userService.userCache();
departmentService.departmentCache();
});*/
return R.ok();
}
@PutMapping("/sync-user/to-system")
@Operation(summary = "微信信息更新")
public R syncUsersToSystem(@RequestParam Long departmentId) {
dingtalkService.syncUsersToSystem(departmentId);
CompletableFuture.runAsync(() -> {
userService.userCache();
List<UserDeptRelation> userDeptRelationList = userDeptRelationService.list();
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, userDeptRelationList);
});
return R.ok();
}
@PutMapping("/sync-departments")
@Operation(summary = "微信信息更新")
public R syncDepartments(@RequestParam Long departmentId) {
dingtalkService.syncDepartments(departmentId);
CompletableFuture.runAsync(() -> {
departmentService.departmentCache();
List<UserDeptRelation> userDeptRelationList = userDeptRelationService.list();
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, userDeptRelationList);
});
return R.ok();
}
@GetMapping(value = "/page")
@Operation(summary = "获取员工分页信息")
@XjrLog(value = "获取员工分页信息")
public R page(UserPageDto dto){
PageOutput<UserPageVo> page = userService.page(dto);
if (dto.getDepartmentId() != null) {
Department department = departmentService.getById(dto.getDepartmentId());
for (UserPageVo userPageVo : page.getList()) {
userPageVo.setDepartmentName(department.getName());
}
}
return R.ok(page);
}
@GetMapping(value = "/departments")
@Operation(summary = "获取部门分页信息")
@XjrLog(value = "获取部门分页信息")
public R page(WeChatDepartPageDto dto){
List<Department> departmentList = departmentService.list(Wrappers.lambdaQuery(Department.class)
.eq(Department::getEnabledMark, EnabledMark.ENABLED.getCode())
.and(StrUtil.isNotEmpty(dto.getKeyword()),
wrapper -> wrapper.like(Department::getName, dto.getKeyword())
.or().like(Department::getCode, dto.getKeyword())));
List<DepartmentTreeVo> departmentTreeVoList = TreeUtil.build(BeanUtil.copyToList(departmentList, DepartmentTreeVo.class));
return R.ok(ListUtils.Pager(dto.getSize(), dto.getLimit(), departmentTreeVoList));
}
@PutMapping(value = "/department")
@Operation(summary = "设置钉钉公司秘钥配置")
public R setDingTalkInfo(@RequestBody DingDeptSettingDto dto) {
Department department = BeanUtil.toBean(dto, Department.class);
return R.ok(departmentService.updateById(department));
}
}

View File

@ -0,0 +1,233 @@
package com.xjrsoft.organization.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
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.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.core.annotation.XjrLog;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.domain.page.PageOutput;
import com.xjrsoft.common.core.domain.result.R;
import com.xjrsoft.common.core.uitls.TreeUtil;
import com.xjrsoft.common.core.uitls.VoToColumnUtil;
import com.xjrsoft.common.mybatis.utils.ConventPage;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.dto.*;
import com.xjrsoft.organization.entity.Post;
import com.xjrsoft.organization.entity.User;
import com.xjrsoft.organization.entity.UserPostRelation;
import com.xjrsoft.organization.service.*;
import com.xjrsoft.organization.vo.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* <p>
* 岗位 前端控制器
* </p>
*
* @author tzx
* @since 2022-03-02
*/
@RestController
@RequestMapping(GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/post")
@Tag(name = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/post", description = "岗位")
@AllArgsConstructor
public class PostController {
private final IPostService postService;
private final IUserService userService;
private final IDepartmentService departmentService;
private final RedisUtil redisUtil;
private final IUserPostRelationService userPostRelationService;
private final IUserDeptRelationService userDeptRelationService;
@GetMapping(value = "/list")
@Operation(summary = "岗位列表(不分页)")
public R list(String keyword) {
List<Post> list = postService.list(Wrappers.lambdaQuery(Post.class)
.like(StrUtil.isNotBlank(keyword), Post::getName, keyword)
.or()
.like(StrUtil.isNotBlank(keyword), Post::getCode, keyword)
.select(Post.class, x -> VoToColumnUtil.fieldsToColumns(PostListVo.class).contains(x.getProperty()))
.orderByAsc(Post::getSortCode));
List<PostListVo> postListVos = BeanUtil.copyToList(list, PostListVo.class);
return R.ok(postListVos);
}
@GetMapping(value = "/page")
@Operation(summary = "岗位列表(分页)")
public R page(@Valid PostPageDto dto) {
LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StrUtil.isNotBlank(dto.getKeyword()), Post::getName, dto.getKeyword())
// .eq(Post::getEnabledMark, YesOrNoEnum.YES.getCode())
.eq(ObjectUtil.isNotEmpty(dto.getDepartmentId()),Post::getDeptId,dto.getDepartmentId())
.like(StrUtil.isNotBlank(dto.getKeyword()), Post::getCode, dto.getKeyword())
.like(StrUtil.isNotBlank(dto.getName()), Post::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getCode()), Post::getCode, dto.getCode())
.like(ObjectUtil.isNotEmpty(dto.getEnabledMark()), Post::getEnabledMark, dto.getEnabledMark())
.select(Post.class, x -> VoToColumnUtil.fieldsToColumns(PostPageVo.class).contains(x.getProperty()))
.orderByAsc(Post::getSortCode);
IPage<Post> page = postService.page(ConventPage.getPage(dto), queryWrapper);
PageOutput<PostPageVo> pageOutput = ConventPage.getPageOutput(page, PostPageVo.class);
return R.ok(pageOutput);
}
@GetMapping(value = "/info")
@Operation(summary = "根据id查询机构信息")
public R info(@RequestParam Long id) {
Post post = postService.getById(id);
if (post == null) {
R.error("找不到此岗位!");
}
return R.ok(BeanUtil.toBean(post, PostVo.class));
}
@GetMapping(value = "/info/multi")
@Operation(summary = "批量查询岗位信息")
public R multiInfo(@RequestParam String ids) {
LambdaQueryWrapper<Post> queryWrapper = Wrappers.lambdaQuery(Post.class).in(Post::getId, Arrays.stream(ids.split(StringPool.COMMA)).toArray());
List<Post> postList = postService.list(queryWrapper);
if (postList == null) {
R.error("找不到此岗位!");
}
return R.ok(BeanUtil.copyToList(postList, PostVo.class));
}
@PostMapping
@Operation(summary = "新增岗位")
public R add(@Valid @RequestBody AddPostDto dto) {
long count = postService.count(Wrappers.<Post>query().lambda().eq(Post::getCode, dto.getCode()));
if (count > 0) {
return R.error("岗位编码已经存在!");
}
Post post = BeanUtil.toBean(dto, Post.class);
postService.save(post);
CompletableFuture.runAsync(postService::postCache);
return R.ok(true);
}
@PutMapping
@Operation(summary = "修改岗位")
public R update(@Valid @RequestBody UpdatePostDto dto) {
long count = postService.count(Wrappers.<Post>query().lambda()
.eq(Post::getCode, dto.getCode())
.ne(Post::getId, dto.getId()));
if (count > 0) {
return R.error("岗位编码已经存在!");
}
Post post = BeanUtil.toBean(dto, Post.class);
postService.updateById(post);
CompletableFuture.runAsync(postService::postCache);
return R.ok(true);
}
@DeleteMapping
@Operation(summary = "删除")
@XjrLog(value = "删除岗位")
public R delete(@Valid @RequestBody List<Long> ids) {
//删除岗位时,需要判断,此岗位下是不是存在人员,存在人员就不能删除
//查询到所有的用户数据
List<UserPostRelation> userPostRelationList = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
});
//拿ids进行过滤如果存在就不能删除
List<UserPostRelation> users = userPostRelationList.stream().filter(u -> ids.contains(u.getPostId())).collect(Collectors.toList());
if (users.size()>0){
return R.error("此岗位下存在用户!");
}
postService.removeBatchByIds(ids);
CompletableFuture.runAsync(postService::postCache);
return R.ok(true);
}
@GetMapping(value = "/tree")
@Operation(summary = "岗位机构树")
@XjrLog(value = "岗位展示")
public R tree(PostTreeDto dto) {
//如果deptId有子集组织也需要把子集组织的用户一起显示出来
// List<Long> deptChild = new ArrayList<>();
// if(ObjectUtil.isNotEmpty(dto.getDeptId())){
// List<Long> deptIds = new ArrayList<>();
// deptIds.add(dto.getDeptId());
// List<Department> list = departmentService.list();
// //先将list集合里面禁用的进行过滤
// List<Department> unEnabledMarkList = OrganizationUtil.getUnEnabledMarkList(list);
// //获取该部门下所有的子节点
// deptChild = OrganizationUtil.getDeptChild(deptIds, unEnabledMarkList);
// deptChild.addAll(deptIds);
// }
LambdaQueryWrapper<Post> queryWrapper = Wrappers.<Post>query().lambda()
.eq(ObjectUtil.isNotEmpty(dto.getDeptId()), Post::getDeptId, dto.getDeptId())
.like(StrUtil.isNotBlank(dto.getName()), Post::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getCode()), Post::getCode, dto.getCode())
.like(ObjectUtil.isNotEmpty(dto.getEnabledMark()), Post::getEnabledMark, dto.getEnabledMark())
.select(Post.class, x -> VoToColumnUtil.fieldsToColumns(PostTreeVo.class).contains(x.getProperty()))
.last(StrUtil.isNotBlank(dto.getField()), GlobalConstant.ORDER_BY + StringPool.SPACE + dto.getField() + StringPool.SPACE + ConventPage.getOrder(dto.getOrder()))
.orderByAsc(StrUtil.isBlank(dto.getField()), Post::getSortCode);
List<Post> list = postService.list(queryWrapper);
List<PostTreeVo> voList = BeanUtil.copyToList(list, PostTreeVo.class);
List<PostTreeVo> treeVoList = TreeUtil.build(voList);
for (PostTreeVo postTreeVo : treeVoList) {
if (postTreeVo.getParentId()==0){
postTreeVo.setParentId(null);
}
}
return R.ok(treeVoList);
}
@GetMapping(value = "/get-post-user")
@Operation(summary = "根据岗位id查询所拥有的用户")
public R getUserByPostId(@RequestParam Long id) {
List<UserPostRelation> list = userPostRelationService.list(Wrappers.<UserPostRelation>query().lambda().eq(UserPostRelation::getPostId, id));
if (CollectionUtils.isEmpty(list)) {
return R.ok(new ArrayList<>());
}
List<Long> userIds = list.stream().map(UserPostRelation::getUserId).collect(Collectors.toList());
List<User> users = userService.list(Wrappers.<User>query().lambda().in(User::getId, userIds).select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPostVo.class).contains(x.getProperty())));
List<UserPostVo> userPostVos = BeanUtil.copyToList(users, UserPostVo.class);
return R.ok(userPostVos);
}
@PutMapping(value = "/update-user-post-batch")
@Operation(summary = "添加岗位下的人员")
public R updatePostIdByUserId(@RequestBody UpdateUserPostDto dto){
//添加岗位下的人员以及人员的组织
return R.ok(userPostRelationService.addPostUser(dto));
}
@PostMapping("/switch-post")
@Operation(summary = "切换岗位")
public R switchPost(@Valid @RequestBody SwitchPostDto dto){
return R.ok(postService.switchPost(dto));
}
}

View File

@ -0,0 +1,275 @@
package com.xjrsoft.organization.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
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.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.app.client.IAppAuthorizeClient;
import com.xjrsoft.app.dto.SetAppRoleAuthDto;
import com.xjrsoft.common.core.annotation.XjrLog;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.domain.page.PageOutput;
import com.xjrsoft.common.core.domain.result.R;
import com.xjrsoft.common.core.enums.YesOrNoEnum;
import com.xjrsoft.common.core.uitls.VoToColumnUtil;
import com.xjrsoft.common.mybatis.utils.ConventPage;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.dto.*;
import com.xjrsoft.organization.entity.Role;
import com.xjrsoft.organization.entity.User;
import com.xjrsoft.organization.entity.UserDeptRelation;
import com.xjrsoft.organization.entity.UserRoleRelation;
import com.xjrsoft.organization.service.IRoleService;
import com.xjrsoft.organization.service.IUserRoleRelationService;
import com.xjrsoft.organization.service.IUserService;
import com.xjrsoft.organization.vo.RoleListVo;
import com.xjrsoft.organization.vo.RolePageVo;
import com.xjrsoft.organization.vo.RoleVo;
import com.xjrsoft.organization.vo.UserRoleVo;
import com.xjrsoft.system.client.IAuthorizeClient;
import com.xjrsoft.system.dto.SetRoleAuthDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* <p>
* 角色 前端控制器
* </p>
*
* @author tzx
* @since 2022-03-02
*/
@RestController
@RequestMapping(GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/role")
@Tag(name = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/role", description = "角色")
@AllArgsConstructor
public class RoleController {
private final IRoleService roleService;
private final IAuthorizeClient authorizeClient;
private final IAppAuthorizeClient appAuthorizeClient;
private final IUserRoleRelationService userRoleRelationService;
private final IUserService userService;
private final RedisUtil redisUtil;
@GetMapping(value = "/list")
@Operation(summary = "角色列表(不分页)")
public R list(RoleListDto dto) {
List<Role> list = roleService.list(Wrappers.lambdaQuery(Role.class)
.likeRight(StrUtil.isNotBlank(dto.getKeyword()), Role::getName, dto.getKeyword())
.eq(Role::getEnabledMark, YesOrNoEnum.YES.getCode())
.select(Role.class, x -> VoToColumnUtil.fieldsToColumns(RoleListVo.class).contains(x.getProperty())));
List<RoleListVo> roleListVos = BeanUtil.copyToList(list, RoleListVo.class);
List<UserRoleRelation> userRoleRelations = redisUtil.get(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, new TypeReference<List<UserRoleRelation>>() {
});
//统计人数
for (RoleListVo roleListVo : roleListVos) {
roleListVo.setCount(userRoleRelations.stream().filter(x -> ObjectUtil.equals(x.getRoleId(), roleListVo.getId())).map(UserRoleRelation::getUserId).distinct().count());
}
return R.ok(roleListVos);
}
@GetMapping(value = "/page")
@Operation(summary = "角色列表(分页)")
public R page(@Valid RolePageDto dto) {
LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StrUtil.isNotBlank(dto.getKeyword()), Role::getName, dto.getKeyword())
.like(StrUtil.isNotBlank(dto.getKeyword()), Role::getCode, dto.getKeyword())
.like(StrUtil.isNotBlank(dto.getName()), Role::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getCode()), Role::getCode, dto.getCode())
.like(ObjectUtil.isNotEmpty(dto.getEnabledMark()), Role::getEnabledMark, dto.getEnabledMark())
.select(Role.class, x -> VoToColumnUtil.fieldsToColumns(RolePageVo.class).contains(x.getProperty()));
IPage<Role> page = roleService.page(ConventPage.getPage(dto), queryWrapper);
PageOutput<RolePageVo> pageOutput = ConventPage.getPageOutput(page, RolePageVo.class);
return R.ok(pageOutput);
}
@GetMapping(value = "/info")
@Operation(summary = "根据id查询角色信息")
public R info(@RequestParam Long id) {
Role role = roleService.getById(id);
if (role == null) {
R.error("找不到此用户!");
}
return R.ok(BeanUtil.toBean(role, RoleVo.class));
}
@GetMapping(value = "/info/multi")
@Operation(summary = "批量查询角色信息")
public R multiInfo(@RequestParam String ids) {
LambdaQueryWrapper<Role> queryWrapper = Wrappers.lambdaQuery(Role.class).in(Role::getId, Arrays.stream(ids.split(StringPool.COMMA)).toArray());
List<Role> roleList = roleService.list(queryWrapper);
if (roleList == null) {
R.error("找不到此角色!");
}
return R.ok(BeanUtil.copyToList(roleList, RoleVo.class));
}
@PostMapping
@Operation(summary = "新增角色")
public R add(@Valid @RequestBody AddRoleDto dto) {
long count = roleService.count(Wrappers.<Role>query().lambda().eq(Role::getName, dto.getName()).or().eq(Role::getCode, dto.getCode()));
if (count > 0) {
return R.error("角色名称或编码已存在!");
}
Role role = BeanUtil.toBean(dto, Role.class);
roleService.save(role);
CompletableFuture.runAsync(() -> {
List<Role> list = roleService.list();
redisUtil.set(GlobalConstant.ROLE_CACHE_KEY, list);
});
return R.ok(true);
}
@PutMapping
@Operation(summary = "修改角色")
public R update(@Valid @RequestBody UpdateRoleDto dto) {
if (dto.getId().equals(GlobalConstant.SUPER_ADMIN_ROLE_ID)) {
return R.error("超级管理员角色不能修改!");
}
long count = roleService.count(Wrappers.<Role>query().lambda()
.eq(Role::getName, dto.getName())
.ne(Role::getId, dto.getId())
.or()
.eq(Role::getCode, dto.getCode())
.ne(Role::getId, dto.getId()));
if (count > 0) {
return R.error("角色名称或编码已存在!");
}
Role role = BeanUtil.toBean(dto, Role.class);
roleService.updateById(role);
CompletableFuture.runAsync(() -> {
List<Role> list = roleService.list();
redisUtil.set(GlobalConstant.ROLE_CACHE_KEY, list);
});
return R.ok(true);
}
@GetMapping("/user")
@Operation(summary = "获取角色用户列表")
public R userList(@RequestParam Long id) {
List<UserRoleRelation> list = userRoleRelationService.list(Wrappers.<UserRoleRelation>query().lambda().eq(UserRoleRelation::getRoleId, id));
if (CollectionUtils.isEmpty(list)) {
return R.ok(new ArrayList<>());
}
List<Long> userIds = list.stream().map(UserRoleRelation::getUserId).collect(Collectors.toList());
List<User> users = userService.list(Wrappers.<User>query().lambda().in(User::getId, userIds).select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserRoleVo.class).contains(x.getProperty())));
List<UserRoleVo> userRoleVos = BeanUtil.copyToList(users, UserRoleVo.class);
return R.ok(userRoleVos);
}
@PostMapping("/user")
@Operation(summary = "添加角色下的人员")
public R addRoleUser(@RequestBody AddRoleUserDto roleUserDto) {
Long roleId = roleUserDto.getId();
if (roleUserDto.getType() == YesOrNoEnum.NO.getCode()){
List<Long> userIds = roleUserDto.getUserIds();
userRoleRelationService.addRoleUser(roleId, userIds);
}else {
//把该组织下所以的人员全部添加到角色下面
List<Long> deptIds = roleUserDto.getDepartmentIds();
List<UserDeptRelation> userDeptRelations= redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
});
List<UserDeptRelation> list = userDeptRelations.stream().filter(x-> CollectionUtil.isNotEmpty(deptIds) && deptIds.contains(x.getDeptId())).collect(Collectors.toList());
//去重操作,防止一个用户在多个组织下
List<Long> userIds = list.stream().map(UserDeptRelation::getUserId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
userRoleRelationService.addRoleUser(roleId, userIds);
}
CompletableFuture.runAsync(() -> {
List<UserRoleRelation> list = userRoleRelationService.list();
redisUtil.set(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, list);
});
return R.ok(true);
}
@PostMapping("/auth")
@Operation(summary = "设置角色菜单权限")
public R auth(@Valid @RequestBody SetRoleAuthDto dto) {
if (dto.getId().equals(GlobalConstant.SUPER_ADMIN_ROLE_ID)) {
return R.error("超级管理员角色不能设置权限!");
}
return R.ok(authorizeClient.setRoleAuthFeign(dto));
}
@GetMapping("/auth")
@Operation(summary = "获取角色菜单权限")
public R authList(@RequestParam Long id) {
return R.ok(authorizeClient.getRoleAuthFeign(id));
}
@PostMapping("/app-auth")
@Operation(summary = "设置角色app菜单权限")
public R appAuth(@Valid @RequestBody SetAppRoleAuthDto dto) {
if (dto.getId().equals(GlobalConstant.SUPER_ADMIN_ROLE_ID)) {
return R.error("超级管理员角色不能设置权限!");
}
return R.ok(appAuthorizeClient.setAppRoleAuthFeign(dto));
}
@GetMapping("/app-auth")
@Operation(summary = "获取角色app菜单权限")
public R appAuthList(@RequestParam Long id) {
return R.ok(appAuthorizeClient.getAppRoleAuthFeign(id));
}
@PutMapping("/status")
@Operation(summary = "修改角色状态")
public R updateEnabled(@Valid @RequestBody UpdateRoleStatusDto dto) {
if (dto.getId().equals(GlobalConstant.SUPER_ADMIN_ROLE_ID)) {
return R.error("超级管理员角色不能修改!");
}
//根据id修改角色enabledMark
return R.ok(roleService.update(Wrappers.<Role>update().lambda().set(Role::getEnabledMark, dto.getEnabledMark()).eq(Role::getId, dto.getId())));
}
@DeleteMapping
@Operation(summary = "删除角色")
@XjrLog(value = "删除角色")
public R delete(@RequestBody List<Long> ids) {
if (ids.contains(1L)) {
return R.error("超级管理员角色不能删除!");
}
roleService.removeBatchByIds(ids);
CompletableFuture.runAsync(() -> {
List<Role> list = roleService.list();
redisUtil.set(GlobalConstant.ROLE_CACHE_KEY, list);
});
return R.ok(true);
}
}

View File

@ -0,0 +1,344 @@
package com.xjrsoft.organization.controller;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.session.TokenSign;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.toolkit.MPJWrappers;
import com.xjrsoft.common.core.config.CommonPropertiesConfig;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.constant.StringPool;
import com.xjrsoft.common.core.domain.result.R;
import com.xjrsoft.common.core.enums.EnabledMark;
import com.xjrsoft.common.core.exception.MyException;
import com.xjrsoft.common.core.uitls.ListUtils;
import com.xjrsoft.common.core.uitls.VoToColumnUtil;
import com.xjrsoft.common.mybatis.utils.LocalDateTimeUtil;
import com.xjrsoft.common.oss.factory.OssFactory;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.dto.*;
import com.xjrsoft.organization.entity.*;
import com.xjrsoft.organization.service.IUserService;
import com.xjrsoft.organization.vo.*;
import com.xjrsoft.tenant.util.SecureUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* <p>
* 用户 前端控制器
* </p>
*
* @author tzx
* @since 2022-03-02
*/
@RestController
@RequestMapping(GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/user")
@Tag(name = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/user", description = "用户")
@AllArgsConstructor
public class UserController {
private final IUserService userService;
private final CommonPropertiesConfig propertiesConfig;
private final RedisUtil redisUtil;
@GetMapping(value = "/list")
@Operation(summary = "用户列表(不分页)")
public R list(String keyword) {
List<User> list = userService.list(Wrappers.lambdaQuery(User.class)
.like(StrUtil.isNotBlank(keyword), User::getUserName, keyword)
.like(StrUtil.isNotBlank(keyword), User::getCode, keyword)
.like(StrUtil.isNotBlank(keyword), User::getName, keyword)
.like(StrUtil.isNotBlank(keyword), User::getMobile, keyword)
.select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserListVo.class).contains(x.getProperty())).orderByAsc(User::getSortCode));
List<UserListVo> userListVos = BeanUtil.copyToList(list, UserListVo.class);
return R.ok(userListVos);
}
@GetMapping(value = "/page")
@Operation(summary = "用户列表(分页)")
public R page(UserPageDto dto) {
return R.ok(userService.page(dto));
}
@GetMapping(value = "/info")
@Operation(summary = "根据id查询用户信息")
public R info(@RequestParam Long id) {
UserVo info = userService.getInfo(id);
return R.ok(info);
}
@GetMapping(value = "/departmentInfo")
@Operation(summary = "根据用户id查询用户的部门和公司信息")
public R departmentInfo(@RequestParam Long id) {
DepartmentCompanyVo info = userService.getDepartmentInfo(id);
return R.ok(info);
}
@PostMapping
@Operation(summary = "新增用户")
public R add(@Valid @RequestBody AddUserDto dto) {
// if (!OrganizationUtil.validatePassword(dto.getPassword())) {
// return R.error("密码必须包含大写字母、小写字母、数字和特殊字符长度8~16位");
// }
return R.ok(userService.add(dto));
}
@PutMapping
@Operation(summary = "修改用户 不能修改用户名")
public R update(@Valid @RequestBody UpdateUserDto dto) {
return R.ok(userService.update(dto));
}
@GetMapping(value = "/current/info")
@Operation(summary = "当前登录用户信息")
public R info() {
SaSession tokenSession = StpUtil.getTokenSession();
User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
UserInfoVo currentInfo = userService.getCurrentInfo(user);
currentInfo.setTenantId(SecureUtil.getCurrentTenantId());
currentInfo.setTenantCode(SecureUtil.getCurrentTenantCode());
currentInfo.setTenantName(SecureUtil.getCurrentTenantName());
return R.ok(currentInfo);
}
@PutMapping("/update/info")
@Operation(summary = "登陆人修改自己得用户信息")
public R updateInfo(@RequestBody @Valid UpdateInfoDto dto) {
User updateUserInfo = BeanUtil.toBean(dto, User.class);
updateUserInfo.setId(StpUtil.getLoginIdAsLong());
CompletableFuture.runAsync(userService::userCache);
return R.ok(userService.updateById(updateUserInfo));
}
@PutMapping("/update/password")
@Operation(summary = "当前登录用户修改本人密码")
public R updatePassword(@RequestBody @Valid UpdatePasswordDto dto) {
// if (!OrganizationUtil.validatePassword(dto.getNewPassword())) {
// return R.error("密码必须包含大写字母、小写字母、数字和特殊字符长度8~16位");
// }
User user = userService.getById(StpUtil.getLoginIdAsLong());
if (!StrUtil.equals(SaSecureUtil.md5BySalt(dto.getOldPassword(), GlobalConstant.SECRET_KEY), user.getPassword())) {
return R.error("当前密码填写错误!");
}
if (!StrUtil.equals(dto.getNewPassword(), dto.getConfirmPassword())) {
return R.error("2次密码输入不一致");
}
User updateUser = new User();
updateUser.setId(StpUtil.getLoginIdAsLong());
updateUser.setPassword(SaSecureUtil.md5BySalt(dto.getNewPassword(), GlobalConstant.SECRET_KEY));
return R.ok(userService.updateById(updateUser));
}
@PostMapping("/update/avatar")
@Operation(summary = "当前登录用户修改头像")
public R uploadAvatar(@RequestParam("file") MultipartFile file) throws Exception {
if (file.isEmpty()) {
throw new MyException("上传文件不能为空");
}
//上传文件
String suffix = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf(StringPool.DOT));
String url = Objects.requireNonNull(OssFactory.build()).uploadSuffix(file.getBytes(), suffix);
User updateUser = new User();
updateUser.setId(StpUtil.getLoginIdAsLong());
updateUser.setAvatar(url);
userService.updateById(updateUser);
SaSession tokenSession = StpUtil.getTokenSession();
User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
user.setAvatar(url);
tokenSession.set(GlobalConstant.LOGIN_USER_INFO_KEY, user);
return R.ok(url);
}
@DeleteMapping
@Operation(summary = "删除用户(可批量)")
public R delete(@RequestBody List<Long> ids) {
if (ids.contains(GlobalConstant.SUPER_ADMIN_USER_ID)) {
R.error("管理员账户不能删除!");
}
if (ids.contains(StpUtil.getLoginIdAsLong())) {
R.error("当前登录账户不能删除!");
}
//删除时需要同时删除用户部门关联表和用户角色关联表和用户岗位关系表数据。
return R.ok(userService.deleteBatch(ids));
}
@GetMapping("/info/multi")
@Operation(summary = "批量获取用户信息")
public R usersInfo(@RequestParam String ids) {
return R.ok(userService.getUsersInfo(ids));
}
@GetMapping("/enabled")
@Operation(summary = "启用/禁用用户")
public R enabled(@RequestParam Long id) {
User user = userService.getOne(Wrappers.<User>query().lambda().select(User::getEnabledMark).eq(User::getId, id), false);
if (user != null) {
User updateUser = new User();
updateUser.setId(id);
updateUser.setEnabledMark(user.getEnabledMark() == EnabledMark.ENABLED.getCode() ? EnabledMark.DISABLED.getCode() : EnabledMark.ENABLED.getCode());
if (user.getEnabledMark() == EnabledMark.DISABLED.getCode()){
//将对应的密码错误次数给删除掉
redisUtil.delete(GlobalConstant.LOGIN_ERROR_NUMBER + id);
}
return R.ok(userService.updateById(updateUser));
}
CompletableFuture.runAsync(userService::userCache);
return R.error("该用户不存在!");
}
@PutMapping("/reset-password")
@Operation(summary = "重置密码")
public R resetPassword(@RequestBody ResetPasswordDto dto) {
User user = new User();
user.setId(dto.getId());
// user.setPassword(DigestUtil.md5Hex(propertiesConfig.getDefaultPassword()));
user.setPassword(SaSecureUtil.md5BySalt(propertiesConfig.getDefaultPassword(), GlobalConstant.SECRET_KEY));
CompletableFuture.runAsync(userService::userCache);
return R.ok(userService.updateById(user));
}
@GetMapping("/online-users/page")
@Operation(summary = "获取在线人员")
public R onlineUsersPage(OnlineUsersPageDto dto) {
List<String> sessionIdList = StpUtil.searchSessionId(StringPool.EMPTY, 0, Integer.MAX_VALUE);
List<OnlineUsersPageVo> loginUserList = new ArrayList<>(sessionIdList.size());
LocalDateTime currentTime = LocalDateTime.now();
for (String sessionId : sessionIdList) {
SaSession session = StpUtil.getSessionBySessionId(sessionId);
List<TokenSign> tokenSignList = session.getTokenSignList();
// // 根据设备过滤多个登录token找出最近登录的
// Optional<TokenSign> tokenSignOpt = tokenSignList.stream().filter(ts -> StrUtil.isEmpty(dto.getDevice()) || StrUtil.equalsIgnoreCase(dto.getDevice(), ts.getDevice()))
// .max(((o1, o2) -> {
// SaSession tokenSession1 = StpUtil.getTokenSessionByToken(o1.getValue());
// SaSession tokenSession2 = StpUtil.getTokenSessionByToken(o2.getValue());
// return Long.compare(tokenSession1.getCreateTime(), tokenSession2.getCreateTime());
// }));
for (TokenSign tokenSign : tokenSignList) {
// TokenSign tokenSign = tokenSignOpt.get();
SaSession tokenSession = StpUtil.getTokenSessionByToken(tokenSign.getValue());
User user = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
// 根据设备以及模糊查询条件过滤
if ( (StrUtil.isNotEmpty(dto.getDevice()) && !StrUtil.equalsIgnoreCase(dto.getDevice(), tokenSign.getDevice()))
|| (StrUtil.isNotEmpty(dto.getKeyword())
&& !StrUtil.containsAnyIgnoreCase(user.getName(), dto.getKeyword())
&& !StrUtil.containsAnyIgnoreCase(user.getUserName(), dto.getKeyword()))) {
continue;
}
OnlineUsersPageVo onlineUsersPageVo = new OnlineUsersPageVo();
onlineUsersPageVo.setId(user.getId());
onlineUsersPageVo.setName(user.getName());
onlineUsersPageVo.setUserName(user.getUserName());
// 在线时长计算
LocalDateTime loginTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(tokenSession.getCreateTime()), ZoneId.systemDefault());
onlineUsersPageVo.setLoginTime(loginTime);
Duration duration = Duration.between(loginTime, currentTime);
onlineUsersPageVo.setOnlineTime(LocalDateTimeUtil.tranDurationToShow(duration));
// 部门名称组装
List<Department> departments = tokenSession.get(GlobalConstant.LOGIN_USER_DEPT_LIST_KEY, new ArrayList<Department>(0));
if (CollectionUtils.isNotEmpty(departments)) {
onlineUsersPageVo.setDepartmentNames(departments.stream().map(Department::getName).collect(Collectors.joining(StringPool.COMMA)));
}
loginUserList.add(onlineUsersPageVo);
}
}
List<OnlineUsersPageVo> sortedList = loginUserList.stream().sorted(((o1, o2) -> o2.getLoginTime().compareTo(o1.getLoginTime()))).collect(Collectors.toList());
return R.ok(ListUtils.Pager(dto.getSize(), dto.getLimit(), sortedList));
}
@PostMapping("/offline-users")
@Operation(summary = "强制下线在线人员")
public R onlineUsersPage(@RequestBody OfflineUsersDto dto) {
for (Long userId : dto.getUserIds()) {
StpUtil.logout(userId, dto.getDevice());
}
return R.ok();
}
@GetMapping("/get-user-organization-info")
@Operation(summary = "获取当前人员的组织架构信息")
public R getUserOrganizationInfo() {
//从缓存中获取当前登陆人的所有组织架构信息
List<Long> roleIdList = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_ROLE_ID_KEY, new ArrayList<>());
List<Post> postList = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_POST_LIST_KEY, new ArrayList<>());
List<Department> departmentList = StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_DEPT_LIST_KEY, new ArrayList<>());
UserOrganizationInfoVo userOrganizationInfoVo = new UserOrganizationInfoVo();
if (roleIdList.size() > 0){
//获取所有的角色信息
List<Role> allRoleList = redisUtil.get(GlobalConstant.ROLE_CACHE_KEY, new TypeReference<List<Role>>() {
});
//获取当前登录人的角色名称集合
List<String> roleNameList = allRoleList.stream().filter(x->roleIdList.contains(x.getId())).map(Role::getName).collect(Collectors.toList());
userOrganizationInfoVo.setRoleNameList(roleNameList);
}
if (postList.size() > 0){
//获取当前登陆人的岗位名称集合
List<String> postNameList = postList.stream().map(Post::getName).collect(Collectors.toList());
userOrganizationInfoVo.setPostNameList(postNameList);
}
userOrganizationInfoVo.setDepartmentNameList(departmentList.size()>0?
departmentList.stream().map(Department::getHierarchy).collect(Collectors.toList()) : Arrays.asList(new String[]{"没有所属部门"}));
return R.ok(userOrganizationInfoVo);
}
@GetMapping("/search")
@Operation(summary = "搜索用户、工号、部门")
public R search(@RequestParam("name") String name) {
List<UserDeptVo> maps = userService.selectJoinList(UserDeptVo.class, MPJWrappers.<User>lambdaJoin()
.distinct()
.like(User::getUserName, name).or()
.like(User::getName, name)
.select(User::getId)
.select(User::getUserName)
.select(User::getName)
.selectAs(Department::getName, UserDeptVo::getDeptName)
.leftJoin(UserDeptRelation.class, UserDeptRelation::getUserId, User::getId)
.leftJoin(Department.class, Department::getId, UserDeptRelation::getDeptId));
return R.ok(maps);
}
}

View File

@ -0,0 +1,11 @@
package com.xjrsoft.organization.controller;
import com.xjrsoft.common.core.constant.GlobalConstant;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/user-post-relation")
public class UserPostRelationController {
}

View File

@ -0,0 +1,19 @@
package com.xjrsoft.organization.controller;
import com.xjrsoft.common.core.constant.GlobalConstant;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 用户关联角色表 前端控制器
* </p>
*
* @author tzx
* @since 2022-03-02
*/
@RestController
@RequestMapping(GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/user-role-relation")
public class UserRoleRelationController {
}

View File

@ -0,0 +1,103 @@
package com.xjrsoft.organization.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.domain.page.PageOutput;
import com.xjrsoft.common.core.domain.result.R;
import com.xjrsoft.common.core.enums.EnabledMark;
import com.xjrsoft.common.core.uitls.ListUtils;
import com.xjrsoft.common.core.uitls.TreeUtil;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.dto.UserPageDto;
import com.xjrsoft.organization.dto.WeChatDepartPageDto;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.entity.UserDeptRelation;
import com.xjrsoft.organization.service.IDepartmentService;
import com.xjrsoft.organization.service.IUserDeptRelationService;
import com.xjrsoft.organization.service.IUserService;
import com.xjrsoft.organization.service.WeChatService;
import com.xjrsoft.organization.vo.DepartmentTreeVo;
import com.xjrsoft.organization.vo.UserPageVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@RestController
@RequestMapping(value = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/wechat")
@Tag(name = GlobalConstant.ORGANIZATION_MODULE_PREFIX + "/wechat", description = "微信")
@AllArgsConstructor
public class WechatController {
private final WeChatService weChatService;
private final IUserService userService;
private final IUserDeptRelationService userDeptRelationService;
private final IDepartmentService departmentService;
private final RedisUtil redisUtil;
@PutMapping("/sync-user")
@Operation(summary = "微信信息更新")
public R syncUsers(@RequestParam Long departmentId) {
weChatService.syncUsers(departmentId);
CompletableFuture.runAsync(() -> {
userService.userCache();
List<UserDeptRelation> userDeptRelationList = userDeptRelationService.list();
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, userDeptRelationList);
});
return R.ok();
}
@PutMapping("/sync-departments")
@Operation(summary = "微信信息更新")
public R syncDepartments() {
weChatService.syncDepartments();
CompletableFuture.runAsync(() -> {
departmentService.departmentCache();
List<UserDeptRelation> userDeptRelationList = userDeptRelationService.list();
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, userDeptRelationList);
});
return R.ok();
}
@GetMapping(value = "/page")
@Operation(summary = "获取员工分页信息")
public R page(UserPageDto dto){
PageOutput<UserPageVo> page = userService.page(dto);
if (dto.getDepartmentId() != null) {
Department department = departmentService.getById(dto.getDepartmentId());
for (UserPageVo userPageVo : page.getList()) {
userPageVo.setDepartmentName(department.getName());
}
}
return R.ok(page);
}
@GetMapping(value = "/departments")
@Operation(summary = "获取部门分页信息")
public R page(WeChatDepartPageDto dto) {
List<Department> departmentList = departmentService.list(Wrappers.lambdaQuery(Department.class)
.eq(Department::getEnabledMark, EnabledMark.ENABLED.getCode())
.and(StrUtil.isNotEmpty(dto.getKeyword()),
wrapper -> wrapper.like(Department::getName, dto.getKeyword())
.or().like(Department::getCode, dto.getKeyword())));
List<DepartmentTreeVo> departmentTreeVoList = TreeUtil.build(BeanUtil.copyToList(departmentList, DepartmentTreeVo.class));
return R.ok(ListUtils.Pager(dto.getSize(), dto.getLimit(), departmentTreeVoList));
}
}

View File

@ -0,0 +1,110 @@
package com.xjrsoft.organization.runner;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.entity.*;
import com.xjrsoft.organization.service.*;
import com.xjrsoft.tenant.util.TenantUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* 组织架构缓存
* @Author: tzx
* @Date: 2022/12/6 14:50
*/
@Component
@AllArgsConstructor
@Slf4j
public class OrganizationCacheRunner implements CommandLineRunner {
private RedisUtil redisUtil;
private IUserService userService;
private IDepartmentService departmentService;
private IRoleService roleService;
private IPostService postService;
private IUserRoleRelationService userRoleRelationService;
private IUserDeptRelationService userDeptRelationService;
private IUserPostRelationService userPostRelationService;
@Override
public void run(String... args) {
TenantUtil.ignore(Boolean.TRUE);
loadUserCache();
loadDeptCache();
loadRoleCache();
loadPostCache();
loadUserRoleRelationCache();
loadUserDepartmentRelationCache();
loadUserPostRelationCache();
TenantUtil.clear();
}
@Async
void loadUserCache(){
log.info("ITC-FRAMEWORK: 加载所有用户表缓存开始");
List<User> list = userService.list();
redisUtil.set(GlobalConstant.USER_CACHE_KEY,list);
redisUtil.set(GlobalConstant.USER_NAME_CACHE_KEY,list.stream().collect(Collectors.toMap(User::getId,User::getName)));
log.info("ITC-FRAMEWORK: 加载所有用户表缓存结束");
}
@Async
void loadDeptCache(){
log.info("ITC-FRAMEWORK: 加载所有机构表缓存开始");
List<Department> list = departmentService.list();
redisUtil.set(GlobalConstant.DEP_CACHE_KEY,list);
redisUtil.set(GlobalConstant.DEP_NAME_CACHE_KEY,list.stream().collect(Collectors.toMap(Department::getId,Department::getName)));
log.info("ITC-FRAMEWORK: 加载所有机构表缓存结束");
}
@Async
void loadRoleCache(){
log.info("ITC-FRAMEWORK: 加载所有角色表缓存开始");
List<Role> list = roleService.list();
redisUtil.set(GlobalConstant.ROLE_CACHE_KEY,list);
log.info("ITC-FRAMEWORK: 加载所有角色表缓存结束");
}
@Async
void loadPostCache(){
log.info("ITC-FRAMEWORK: 加载所有岗位表缓存开始");
List<Post> list = postService.list();
redisUtil.set(GlobalConstant.POST_CACHE_KEY,list);
redisUtil.set(GlobalConstant.POST_NAME_CACHE_KEY,list.stream().collect(Collectors.toMap(Post::getId,Post::getName)));
log.info("ITC-FRAMEWORK: 加载所有岗位表缓存结束");
}
@Async
void loadUserRoleRelationCache(){
log.info("ITC-FRAMEWORK: 加载所有用户角色关联表缓存开始");
List<UserRoleRelation> list = userRoleRelationService.list();
redisUtil.set(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY,list);
log.info("ITC-FRAMEWORK: 加载所有用户角色关联表缓存结束");
}
void loadUserDepartmentRelationCache(){
log.info("ITC-FRAMEWORK: 加载所有用户部门关联表缓存开始");
List<UserDeptRelation> deptRelationList = userDeptRelationService.list();
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, deptRelationList);
log.info("ITC-FRAMEWORK: 加载所有用户部门关联表缓存结束");
}
void loadUserPostRelationCache(){
log.info("ITC-FRAMEWORK: 加载所有用户岗位关联表缓存开始");
List<UserPostRelation> postRelationList = userPostRelationService.list();
redisUtil.set(GlobalConstant.USER_POST_RELATION_CACHE_KEY, postRelationList);
log.info("ITC-FRAMEWORK: 加载所有用户岗位关联表缓存结束");
}
}

View File

@ -0,0 +1,10 @@
package com.xjrsoft.organization.service;
public interface DingtalkService {
boolean syncUsersToDingTalk(Long departmentId);
boolean syncUsersToSystem(Long departmentId);
boolean syncDepartments(Long departmentId);
}

View File

@ -0,0 +1,46 @@
package com.xjrsoft.organization.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xjrsoft.common.core.domain.page.PageInput;
import com.xjrsoft.organization.dto.WeChatDepartPageDto;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.vo.DepartmentTreeVo;
import java.util.List;
/**
* <p>
* 机构 服务类
* </p>
*
* @author tzx
* @since 2022-03-02
*/
public interface IDepartmentService extends IService<Department> {
Object page(PageInput pageInput);
List<Long> getAllChildIds(List<Long> deptIds,List<DepartmentTreeVo> voList);
/**
* 查询指定节点的所有父节点
* @param id
* @return
*/
List<String> findDeptPIds(String id);
List<Department> getChildrenDepartmentInfo(Long id);
void departmentCache();
List<Department>getRootDepartment();
/**
* 查询指定部门从站点根节点开始的部门名称路径,填充到部门的层级字段
* @param list
* @param separator 分隔符,默认/
* @param isQueryIdPath 是否查询id路径默认查询名称路径
* @return
*/
List<Department>queryPathFromRoot(List<Department>list,String separator,Boolean isQueryIdPath);
List<Department>queryPathFromRoot(List<Department>list,String separator);
List<Department>queryPathFromRoot(List<Department>list);
}

View File

@ -0,0 +1,17 @@
package com.xjrsoft.organization.service;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.request.AuthRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: tzx
* @Date: 2023/8/8 10:39
*/
public interface IOauthService {
void oAuthLogin(String source, AuthCallback callback, HttpServletRequest request, HttpServletResponse response);
AuthRequest getAuthRequest(String source);
}

View File

@ -0,0 +1,20 @@
package com.xjrsoft.organization.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xjrsoft.organization.dto.SwitchPostDto;
import com.xjrsoft.organization.entity.Post;
import com.xjrsoft.organization.vo.SwitchPostVo;
/**
* <p>
* 岗位 服务类
* </p>
*
* @author tzx
* @since 2022-03-02
*/
public interface IPostService extends IService<Post> {
SwitchPostVo switchPost(SwitchPostDto dto);
void postCache();
}

View File

@ -0,0 +1,16 @@
package com.xjrsoft.organization.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xjrsoft.organization.entity.Role;
/**
* <p>
* 角色 服务类
* </p>
*
* @author tzx
* @since 2022-03-02
*/
public interface IRoleService extends IService<Role> {
}

View File

@ -0,0 +1,9 @@
package com.xjrsoft.organization.service;
import java.util.Map;
public interface ISyncOrgAndUserService {
Map<String ,String> sync(Integer syncType) throws Exception;
Map<String ,String> sync(Integer syncType,String startRootCode) throws Exception;
}

View File

@ -0,0 +1,16 @@
package com.xjrsoft.organization.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xjrsoft.organization.entity.UserChargeDept;
/**
* <p>
* 用户负责部门表 服务类
* </p>
*
* @author hnyyzy
* @since 2023-12-20
*/
public interface IUserChargeDeptService extends IService<UserChargeDept> {
}

View File

@ -0,0 +1,7 @@
package com.xjrsoft.organization.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xjrsoft.organization.entity.UserDeptRelation;
public interface IUserDeptRelationService extends IService<UserDeptRelation> {
}

View File

@ -0,0 +1,9 @@
package com.xjrsoft.organization.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xjrsoft.organization.dto.UpdateUserPostDto;
import com.xjrsoft.organization.entity.UserPostRelation;
public interface IUserPostRelationService extends IService<UserPostRelation> {
boolean addPostUser(UpdateUserPostDto dto);
}

View File

@ -0,0 +1,19 @@
package com.xjrsoft.organization.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xjrsoft.organization.entity.UserRoleRelation;
import java.util.List;
/**
* <p>
* 用户关联角色表 服务类
* </p>
*
* @author tzx
* @since 2022-03-02
*/
public interface IUserRoleRelationService extends IService<UserRoleRelation> {
boolean addRoleUser(Long roleId, List<Long> userIds);
}

View File

@ -0,0 +1,70 @@
package com.xjrsoft.organization.service;
import com.github.yulichang.base.MPJBaseService;
import com.xjrsoft.common.core.domain.page.PageOutput;
import com.xjrsoft.organization.dto.AddUserDto;
import com.xjrsoft.organization.dto.UpdateUserDto;
import com.xjrsoft.organization.dto.UserPageDto;
import com.xjrsoft.organization.dto.WeChatPageDto;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.entity.User;
import com.xjrsoft.organization.vo.*;
import java.util.List;
/**
* <p>
* 用户 服务类
* </p>
*
* @author tzx
* @since 2022-03-02
*/
public interface IUserService extends MPJBaseService<User> {
boolean add(AddUserDto dto);
boolean update(UpdateUserDto dto);
boolean deleteBatch(List<Long> ids);
/**
* 批量获取用户信息
*
* @param ids
* @return 用户信息
*/
List<UserInfoVo> getUsersInfo(String ids);
/**
* 获取微信分页
* @param dto
* @return
*/
PageOutput<WeChatPageVO> getPage(WeChatPageDto dto);
/**
* 获取用户分页
* @param dto
* @return
*/
PageOutput<UserPageVo> page(UserPageDto dto);
UserVo getInfo(Long id);
DepartmentCompanyVo getDepartmentInfo(Long id);
UserVo getInfoByUserName(String userName);
UserInfoVo getCurrentInfo(User user);
List<Department> queryDepartmentsOfUser(Long id);
List<UserRoleVo> queryRolesOfUser(Long id);
void userCache();
User getUserByMobile(String mobile);
User getUserByCode(String code);
}

View File

@ -0,0 +1,11 @@
package com.xjrsoft.organization.service;
public interface WeChatService {
boolean syncUsers(Long departmentId);
boolean syncDepartments();
}

View File

@ -0,0 +1,156 @@
package com.xjrsoft.organization.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.domain.page.PageInput;
import com.xjrsoft.common.core.uitls.ListUtils;
import com.xjrsoft.common.core.uitls.TreeUtil;
import com.xjrsoft.common.core.uitls.VoToColumnUtil;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.mapper.DepartmentMapper;
import com.xjrsoft.organization.service.IDepartmentService;
import com.xjrsoft.organization.vo.DepartmentTreeVo;
import com.xjrsoft.system.client.ISystemConfigClient;
import com.xjrsoft.system.entity.XjrSystemConfig;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* <p>
* 机构 服务实现类
* </p>
*
* @author tzx
* @since 2022-03-02
*/
@Service
@AllArgsConstructor
@Slf4j
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements IDepartmentService {
private final DepartmentMapper departmentMapper;
private final RedisUtil redisUtil;
private final ISystemConfigClient systemConfigClient;
@Override
public Object page(PageInput pageInput) {
LambdaQueryWrapper<Department> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StrUtil.isNotBlank(pageInput.getKeyword()),Department::getName, pageInput.getKeyword())
.select(Department.class,x -> VoToColumnUtil.fieldsToColumns(DepartmentTreeVo.class).contains(x.getProperty()));
List<Department> departmentList = departmentMapper.selectList(queryWrapper);
List<DepartmentTreeVo> build = TreeUtil.build(BeanUtil.copyToList(departmentList, DepartmentTreeVo.class));
return ListUtils.Pager(pageInput.getSize(), pageInput.getLimit(), build);
}
/**
* 获取所有的子集id
* @param deptIds
* @param voList
* @return
*/
@Override
public List<Long> getAllChildIds(List<Long> deptIds, List<DepartmentTreeVo> voList) {
List<Long> ids = new ArrayList<>();
for (Long deptId : deptIds) {
if (voList.stream().anyMatch(x -> x.getParentId().equals(deptId))){
List<DepartmentTreeVo> child = voList.stream().filter(x -> x.getParentId().equals(deptId)).collect(Collectors.toList());
List<Long> allChildId = child.stream().map(DepartmentTreeVo::getId).collect(Collectors.toList());
List<Long> allChildId1= getAllChildIds(allChildId, voList);
ids.addAll(allChildId);
ids.addAll(allChildId1);
}
}
return ids;
}
/**
* 获取一级子集部门数据
* @param id
* @return
*/
@Override
public List<Department> getChildrenDepartmentInfo(Long id){
List<Department> list = departmentMapper.selectList(Wrappers.lambdaQuery(Department.class).eq(Department::getParentId,id).eq(Department::getDepartmentType,0))
.stream().collect(Collectors.toList());
return list;
}
@Override
public List<String> findDeptPIds(String id) {
//return departmentMapper.findDeptPIds(id);
Map<String,Object> params=new HashMap<>();
params.put("queryType","parent");
params.put("startIds",new String[]{id});
return departmentMapper.findParentIds(params);
}
@Override
public List<Department> queryPathFromRoot(List<Department> list,String separator,Boolean isQueryIdPath) {
if(ObjectUtil.isNotEmpty(list)){
Map<String,Object> params=new HashMap<>();
params.put("queryType","parent");
params.put("startIds",list.stream().map(Department::getId).toArray(Long[]::new));
List<Department>rootDepartment=getRootDepartment();
if(rootDepartment!=null){
params.put("stopParentIds",rootDepartment.stream().map(Department::getId).toArray(Long[]::new));
}
params.put("isQueryIdPath",isQueryIdPath?"Y":"N");
params.put("pathSeparator",separator);
Map<Long,Map>deptPathMap=departmentMapper.queryDeptPath(params);
if(deptPathMap!=null){
for(Department department:list){
if(deptPathMap.get(department.getId())!=null){
department.setHierarchy(String.valueOf(deptPathMap.get(department.getId()).get("path")));
}
}
}
}
return list;
}
@Override
public List<Department> queryPathFromRoot(List<Department> list, String separator) {
return queryPathFromRoot(list,separator,false);
}
@Override
public List<Department> queryPathFromRoot(List<Department> list) {
return queryPathFromRoot(list,null,false);
}
@Override
public void departmentCache() {
log.info("刷新部门表缓存开始");
List<Department> list = list();
redisUtil.set(GlobalConstant.DEP_CACHE_KEY,list);
redisUtil.set(GlobalConstant.DEP_NAME_CACHE_KEY,list.stream().collect(Collectors.toMap(Department::getId,Department::getName)));
log.info("刷新部门表缓存结束");
}
@Override
public List<Department> getRootDepartment() {
//从系统变量查根部门
XjrSystemConfig config = systemConfigClient.queryByCode(GlobalConstant.siteRootDepartmentKey);
if(config!=null&& StringUtils.isNotBlank(config.getValue())){
return lambdaQuery().in(Department::getCode,config.getValue().split(",")).list();
}
return null;
}
}

View File

@ -0,0 +1,238 @@
package com.xjrsoft.organization.service.impl;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiV2UserCreateRequest;
import com.dingtalk.api.request.OapiV2UserUpdateRequest;
import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
import com.dingtalk.api.response.OapiV2UserCreateResponse;
import com.dingtalk.api.response.OapiV2UserListResponse;
import com.dingtalk.api.response.OapiV2UserUpdateResponse;
import com.github.yulichang.toolkit.MPJWrappers;
import com.taobao.api.ApiException;
import com.xjrsoft.common.core.config.CommonPropertiesConfig;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.uitls.VoToColumnUtil;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.entity.User;
import com.xjrsoft.organization.entity.UserDeptRelation;
import com.xjrsoft.organization.service.DingtalkService;
import com.xjrsoft.organization.service.IDepartmentService;
import com.xjrsoft.organization.service.IUserDeptRelationService;
import com.xjrsoft.organization.service.IUserService;
import com.xjrsoft.organization.utils.WeChatUtil;
import com.xjrsoft.organization.vo.UserPageVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Service
@AllArgsConstructor
public class DingtalkServiceImpl implements DingtalkService {
private final IUserService userService;
private final IUserDeptRelationService userDeptRelationService;
private final IDepartmentService departmentService;
private final WeChatUtil weChatUtil;
private final CommonPropertiesConfig propertiesConfig;
@Override
public boolean syncUsersToDingTalk(Long departmentId) {
Department department = departmentService.getById(departmentId);
Department settingDept = findSettingDept(department);
if (department.getDingtalkDeptId() == null) {
throw new RuntimeException("请先同步部门!");
}
List<User> userList = userService.selectJoinList(User.class,
MPJWrappers.<User>lambdaJoin()
.distinct()
.eq( UserDeptRelation::getDeptId, departmentId)
.select(User::getId)
.select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
.leftJoin(UserDeptRelation.class, UserDeptRelation::getUserId, User::getId));
// 开始同步
String accessToken = weChatUtil.getDingTalkToken(settingDept.getDingAppKey(), settingDept.getDingAppSecret());
for (User user : userList) {
if (StrUtil.isEmpty(user.getDingtalkUserId())) {
createUserToDingTalk(department.getDingtalkDeptId(), user, accessToken);
} else {
updateUserToDingTalk(user, accessToken);
}
}
return true;
}
@Override
public boolean syncUsersToSystem(Long departmentId) {
Department department = departmentService.getById(departmentId);
Department settingDept = findSettingDept(department);
if (department.getDingtalkDeptId() == null) {
throw new RuntimeException("请先同步部门!");
}
List<OapiV2UserListResponse.ListUserResponse> dingTalkUserList = weChatUtil.getDingTalkUsersOfDepartment(department.getDingtalkDeptId(), settingDept.getDingAppKey(), settingDept.getDingAppSecret());
if (CollectionUtils.isNotEmpty(dingTalkUserList)) {
List<String> dingTalkUserIds = dingTalkUserList.stream().map(OapiV2UserListResponse.ListUserResponse::getUserid).collect(Collectors.toList());
List<User> userList = userService.list(Wrappers.lambdaQuery(User.class).in(User::getDingtalkUserId, dingTalkUserIds));
List<User> updateUserList = new ArrayList<>(dingTalkUserList.size());
List<UserDeptRelation> userDeptRelationList = new ArrayList<>(dingTalkUserList.size());
List<Long> updateUserIdList = new ArrayList<>(dingTalkUserList.size());
for (OapiV2UserListResponse.ListUserResponse dingTalkUserDto : dingTalkUserList) {
User updateUser = new User();
Long userId = null;
boolean exist = false;
for (User user : userList) {
if (StrUtil.equals(dingTalkUserDto.getUserid(), user.getDingtalkUserId())) {
userId = user.getId();
exist = true;
break;
}
}
if (!exist) {
userId = IdUtil.getSnowflakeNextId();
// 默认密码
updateUser.setPassword(SaSecureUtil.md5BySalt(propertiesConfig.getDefaultPassword(), GlobalConstant.SECRET_KEY));
}
// 构建同步的user信息
updateUser.setId(userId);
updateUser.setUserName(dingTalkUserDto.getMobile());
updateUser.setName(dingTalkUserDto.getName());
updateUser.setMobile(dingTalkUserDto.getMobile());
updateUser.setEmail(dingTalkUserDto.getEmail());
updateUser.setDingtalkUserId(dingTalkUserDto.getUserid());
// updateUser.setGender(Integer.valueOf(dingTalkUserDto.getGender()));
updateUserList.add(updateUser);
// 构建用户部门关系
UserDeptRelation userDeptRelation = new UserDeptRelation();
userDeptRelation.setUserId(userId);
userDeptRelation.setDeptId(departmentId);
userDeptRelationList.add(userDeptRelation);
updateUserIdList.add(userId);
}
userService.saveOrUpdateBatch(updateUserList);
// 删除旧的部门用户关联关系
userDeptRelationService.remove(Wrappers.lambdaQuery(UserDeptRelation.class)
.eq(UserDeptRelation::getDeptId, departmentId)
.in(UserDeptRelation::getUserId, updateUserIdList));
userDeptRelationService.saveBatch(userDeptRelationList);
return true;
} else {
throw new RuntimeException("钉钉没有人员!");
}
}
@Override
public boolean syncDepartments(Long departmentId) {
Department department = departmentService.getById(departmentId);
if (department == null || StrUtil.isEmpty(department.getDingAppKey()) || StrUtil.isEmpty(department.getDingAppSecret())) {
throw new RuntimeException("请配置部门的钉钉配置");
}
List<OapiV2DepartmentListsubResponse.DeptBaseResponse> dingTalkDeptList = weChatUtil.getDingTalkDepartmentList(department.getDingAppKey(), department.getDingAppSecret());
if (CollectionUtils.isNotEmpty(dingTalkDeptList)) {
List<Long> dingTalkDeptIdList = dingTalkDeptList.stream().map(OapiV2DepartmentListsubResponse.DeptBaseResponse::getDeptId).collect(Collectors.toList());
List<Department> departmentList = departmentService.list(Wrappers.lambdaQuery(Department.class)
.select(Department::getId, Department::getDingtalkDeptId)
.in(Department::getDingtalkDeptId, dingTalkDeptIdList));
// id映射key企业微信部门idvalue系统部门id
Map<Long, Long> idMap = new HashMap<>(dingTalkDeptIdList.size());
List<Department> updateDepartmentList = new ArrayList<>(dingTalkDeptList.size());
for (OapiV2DepartmentListsubResponse.DeptBaseResponse dingTalkDepartDto : dingTalkDeptList) {
boolean exist = false;
Long deptId = null;
Department updateDepartment = new Department();
for (Department sysDept : departmentList) {
if (dingTalkDepartDto.getDeptId().equals(sysDept.getDingtalkDeptId())) {
deptId = sysDept.getId();
exist = true;
break;
}
}
if (!exist) {
deptId = IdUtil.getSnowflakeNextId();
}
updateDepartment.setName(dingTalkDepartDto.getName());
// updateDepartment.setCode(dingTalkDepartDto.getName_en());
updateDepartment.setId(deptId);
updateDepartment.setDingtalkDeptId(dingTalkDepartDto.getDeptId());
updateDepartment.setParentId(dingTalkDepartDto.getParentId());
updateDepartmentList.add(updateDepartment);
idMap.put(dingTalkDepartDto.getDeptId(), deptId);
}
// 处理上级部门
for (Department updateDepartment : updateDepartmentList) {
Long parentId = idMap.get(updateDepartment.getParentId());
updateDepartment.setParentId(parentId == null ? departmentId : parentId);
}
return departmentService.saveOrUpdateBatch(updateDepartmentList);
}
return true;
}
public boolean updateUserToDingTalk(User user, String accessToken) {
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/update");
OapiV2UserUpdateRequest req = new OapiV2UserUpdateRequest();
req.setUserid(user.getDingtalkUserId());
req.setName(user.getName());
req.setHideMobile(false);
req.setTitle(user.getNickName());
req.setEmail(user.getEmail());
req.setRemark(user.getRemark());
req.setDeptIdList("2,3,4");
req.setMobile(user.getMobile());
req.setLanguage("zh_CN");
OapiV2UserUpdateResponse rsp = null;
try {
rsp = client.execute(req, accessToken);
} catch (ApiException e) {
log.error("同步钉钉用户出错!用户名:" + user.getNickName(), e);
return false;
}
return rsp.getErrcode() == 0L;
}
public boolean createUserToDingTalk(Long dingDeptId, User user, String accessToken) {
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/create");
OapiV2UserCreateRequest req = new OapiV2UserCreateRequest();
req.setUserid(user.getUserName());
req.setName(user.getName());
req.setMobile(user.getMobile());
req.setTitle(user.getNickName());
req.setEmail(user.getEmail());
req.setRemark(user.getRemark());
req.setDeptIdList(dingDeptId.toString());
OapiV2UserCreateResponse rsp = null;
try {
rsp = client.execute(req, accessToken);
} catch (ApiException e) {
log.error("同步钉钉用户出错!用户名:" + user.getNickName(), e);
return false;
}
return rsp.getErrcode() == 0L;
}
private Department findSettingDept(Department department) {
if (department == null) {
throw new RuntimeException("请配置部门的钉钉配置");
} else if (StrUtil.isEmpty(department.getDingAppKey()) || StrUtil.isEmpty(department.getDingAppSecret())) {
Department parent = departmentService.getById(department.getParentId());
department = findSettingDept(parent);
}
return department;
}
}

View File

@ -0,0 +1,566 @@
package com.xjrsoft.organization.service.impl;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiUserGetbyunionidRequest;
import com.dingtalk.api.request.OapiV2UserGetRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiUserGetbyunionidResponse;
import com.dingtalk.api.response.OapiV2UserGetResponse;
import com.xjrsoft.common.core.config.DingtalkConfig;
import com.xjrsoft.common.core.config.LicenseConfig;
import com.xjrsoft.common.core.config.WechatEnterpriseConfig;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.enums.EnabledMark;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.entity.*;
import com.xjrsoft.organization.service.*;
import com.xjrsoft.system.model.DingTalkModel;
import com.xjrsoft.system.model.DingTalkUserInfoModel;
import com.xjrsoft.system.model.WechatEnterpriseModel;
import com.xjrsoft.system.model.WechatEnterpriseUserInfoModel;
import com.xkcoding.http.config.HttpConfig;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.enums.scope.*;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.request.*;
import me.zhyd.oauth.utils.AuthScopeUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Author: tzx
* @Date: 2023/8/8 10:40
*/
@Service
@AllArgsConstructor
public class OauthServiceImpl implements IOauthService {
private final IUserService userService;
private final IUserDeptRelationService userDeptRelationService;
private final IUserPostRelationService userPostRelationService;
private final IPostService postService;
private final IDepartmentService departmentService;
private final RedisUtil redisUtil;
private final LicenseConfig licenseConfig;
private final DingtalkConfig dingtalkConfig;
private final WechatEnterpriseConfig wechatEnterpriseConfig;
@Override
@SneakyThrows
public void oAuthLogin(String source, AuthCallback callback, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
String prevPage = httpServletRequest.getHeader("Referer");
if (licenseConfig.getEnabled()) {
//查出所有在线用户
List<String> onlineUser = StpUtil.searchSessionId("", 0, Integer.MAX_VALUE);
//如果已经登录人数超过授权人数 不允许登录
if (onlineUser.size() >= licenseConfig.getLoginMax()) {
httpServletResponse.sendRedirect("http://localhost:3100/#/login?error=登录人数超过授权人数,无法登录,请联系管理员!");
}
}
AuthRequest authRequest = getAuthRequest(source);
AuthResponse response = authRequest.login(callback);
User loginUser = new User();
if(response.getCode() == 2000){
if(source.equals("dingtalk")){
DingTalkModel dingTalkModel = Convert.convert(DingTalkModel.class,response.getData());
DingTalkUserInfoModel dingTalkUserInfoModel = dingTalkModel.getRawUserInfo();
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(dingtalkConfig.getAppKey());
request.setAppsecret(dingtalkConfig.getAppSecret());
request.setHttpMethod(HttpMethod.GET.name());
OapiGettokenResponse res = client.execute(request);
DingTalkClient uniClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/getbyunionid");
OapiUserGetbyunionidRequest uniRequset = new OapiUserGetbyunionidRequest();
uniRequset.setUnionid(dingTalkUserInfoModel.getUnionid());
OapiUserGetbyunionidResponse uniResp = uniClient.execute(uniRequset, res.getAccessToken());
DingTalkClient userInfoClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
OapiV2UserGetRequest userInfoReq = new OapiV2UserGetRequest();
userInfoReq.setUserid(uniResp.getResult().getUserid());
userInfoReq.setLanguage("zh_CN");
OapiV2UserGetResponse userInfoResp = userInfoClient.execute(userInfoReq, res.getAccessToken());
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getMobile,userInfoResp.getResult().getMobile());
loginUser = userService.getOne(queryWrapper);
//如果扫码登录 没有此账号 默认新增
if (loginUser == null) {
httpServletResponse.sendRedirect("http://localhost:3100/#/login?error=没有找到所关联的账户");
return;
}
}
else{
WechatEnterpriseModel wechatEnterpriseModel = Convert.convert(WechatEnterpriseModel.class,response.getData());
WechatEnterpriseUserInfoModel rawUserInfo = wechatEnterpriseModel.getRawUserInfo();
// String tokenResult = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + wechatEnterpriseConfig.getAppKey() + "&corpsecret=" + wechatEnterpriseConfig.getAppSecret());
//
// WechatEnterpriseTokenResult wechatEnterpriseTokenResult = JSONUtil.toBean(tokenResult, WechatEnterpriseTokenResult.class);
//
// if(wechatEnterpriseTokenResult.getErrcode() > 0){
// httpServletResponse.sendRedirect("http://localhost:3100/#/login?error=" + wechatEnterpriseTokenResult.getErrmsg());
// return;
// }
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getMobile,rawUserInfo.getMobile());
loginUser = userService.getOne(queryWrapper);
//如果扫码登录 没有此账号 默认新增
if (loginUser == null) {
httpServletResponse.sendRedirect("http://localhost:3100/#/login?error=没有找到所关联的账户");
return;
// loginUser = new User();
// initUser(source,response.getData(),loginUser);
//
// loginUser = new User();
// loginUser.setName(rawUserInfo.getName());
// loginUser.setUserName(rawUserInfo.getMobile());
// loginUser.setEmail(rawUserInfo.getEmail());
// loginUser.setAvatar(rawUserInfo.getAvatar());
// loginUser.setMobile(rawUserInfo.getMobile());
// loginUser.setNickName(wechatEnterpriseModel.getNickname());
// loginUser.setGender(rawUserInfo.getGender());
// loginUser.setEnabledMark(rawUserInfo.getEnable());
// userService.save(loginUser);
}
}
}
else {
httpServletResponse.sendRedirect("http://localhost:3100/#/login?error=" + response.getMsg());
}
if (loginUser.getEnabledMark() == EnabledMark.DISABLED.getCode()) {
httpServletResponse.sendRedirect("http://localhost:3100/#/login?error=账户未启用");
return;
}
//此登录接口登录web端
StpUtil.login(loginUser.getId(), "PC");
SaSession tokenSession = StpUtil.getTokenSession();
List<UserDeptRelation> userDeptRelations = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class)
.eq(UserDeptRelation::getUserId, StpUtil.getLoginIdAsLong()));
List<UserPostRelation> userPostRelations = userPostRelationService.list(Wrappers.lambdaQuery(UserPostRelation.class)
.eq(UserPostRelation::getUserId, StpUtil.getLoginIdAsLong()));
//获取登陆人所选择的身份缓存
String postId = redisUtil.get(GlobalConstant.LOGIN_IDENTITY_CACHE_PREFIX + loginUser.getId());
Post post = new Post();
if (StrUtil.isNotBlank(postId)) {
post = postService.getById(postId);
}
if (userPostRelations.size() > 0) {
List<Long> postIds = userPostRelations.stream().map(UserPostRelation::getPostId).collect(Collectors.toList());
List<Post> postList = postService.listByIds(postIds);
if (StrUtil.isBlank(postId) && CollectionUtils.isNotEmpty(postList)) {
post = postList.get(0);
}
tokenSession.set(GlobalConstant.LOGIN_USER_POST_INFO_KEY, post);
tokenSession.set(GlobalConstant.LOGIN_USER_POST_LIST_KEY, postList);
loginUser.setPostId(post.getId());
//将登陆人所选择的身份缓存起来
//切换身份的时候 会一起修改
redisUtil.set(GlobalConstant.LOGIN_IDENTITY_CACHE_PREFIX + loginUser.getId(), post.getId());
}
if (userDeptRelations.size() > 0) {
// 存当前用户所有部门到缓存
List<Long> departmentIds = userDeptRelations.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());
List<Department> departmentList = departmentService.listByIds(departmentIds);
tokenSession.set(GlobalConstant.LOGIN_USER_DEPT_LIST_KEY, departmentList);
//如果此人有岗位 使用岗位的deptId 找到当前组织机构
if (ObjectUtil.isNotNull(post.getId())) {
Department department = departmentService.getById(post.getDeptId());
tokenSession.set(GlobalConstant.LOGIN_USER_DEPT_INFO_KEY, department);
loginUser.setDepartmentId(department.getId());
} else {
Department department = departmentList.get(0);
tokenSession.set(GlobalConstant.LOGIN_USER_DEPT_INFO_KEY, department);
loginUser.setDepartmentId(department.getId());
}
}
//根据登录信息 将post 和 department 信息存入用户信息中
tokenSession.set(GlobalConstant.LOGIN_USER_INFO_KEY, loginUser);
httpServletResponse.sendRedirect("http://localhost:3100/#/login?token=" + StpUtil.getTokenValue());
}
/**
* 根据具体的授权来源,获取授权请求工具类
*
* @param source
* @return
*/
public AuthRequest getAuthRequest(String source) {
AuthRequest authRequest = null;
switch (source.toLowerCase()) {
case "dingtalk":
authRequest = new AuthDingTalkRequest(AuthConfig.builder()
.clientId(dingtalkConfig.getAppKey())
.clientSecret(dingtalkConfig.getAppSecret())
.redirectUri(dingtalkConfig.getRedirectUri())
.agentId(dingtalkConfig.getAgentid())
.build());
break;
case "baidu":
authRequest = new AuthBaiduRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/baidu")
.scopes(Arrays.asList(
AuthBaiduScope.BASIC.getScope(),
AuthBaiduScope.SUPER_MSG.getScope(),
AuthBaiduScope.NETDISK.getScope()
))
// .clientId("")
// .clientSecret("")
// .redirectUri("http://localhost:9001/oauth/baidu/callback")
.build());
break;
case "weibo":
authRequest = new AuthWeiboRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://dblog-web.zhyd.me/oauth/callback/weibo")
.scopes(Arrays.asList(
AuthWeiboScope.EMAIL.getScope(),
AuthWeiboScope.FRIENDSHIPS_GROUPS_READ.getScope(),
AuthWeiboScope.STATUSES_TO_ME_READ.getScope()
))
.build());
break;
case "coding":
authRequest = new AuthCodingRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://dblog-web.zhyd.me/oauth/callback/coding")
.domainPrefix("")
.scopes(Arrays.asList(
AuthCodingScope.USER.getScope(),
AuthCodingScope.USER_EMAIL.getScope(),
AuthCodingScope.USER_PHONE.getScope()
))
.build());
break;
case "oschina":
authRequest = new AuthOschinaRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/oschina")
.build());
break;
case "alipay":
// 支付宝在创建回调地址时不允许使用localhost或者127.0.0.1所以这儿的回调地址使用的局域网内的ip
authRequest = new AuthAlipayRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.alipayPublicKey("")
.redirectUri("https://www.zhyd.me/oauth/callback/alipay")
.build());
break;
case "qq":
authRequest = new AuthQqRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/qq")
.build());
break;
case "wechat_open":
authRequest = new AuthWeChatOpenRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://www.zhyd.me/oauth/callback/wechat")
.build());
break;
case "csdn":
authRequest = new AuthCsdnRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://dblog-web.zhyd.me/oauth/callback/csdn")
.build());
break;
case "taobao":
authRequest = new AuthTaobaoRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://dblog-web.zhyd.me/oauth/callback/taobao")
.build());
break;
case "google":
authRequest = new AuthGoogleRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/google")
.scopes(AuthScopeUtils.getScopes(AuthGoogleScope.USER_EMAIL, AuthGoogleScope.USER_PROFILE, AuthGoogleScope.USER_OPENID))
// 针对国外平台配置代理
.httpConfig(HttpConfig.builder()
.timeout(15000)
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 10080)))
.build())
.build());
break;
case "facebook":
authRequest = new AuthFacebookRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("https://justauth.cn/oauth/callback/facebook")
.scopes(AuthScopeUtils.getScopes(AuthFacebookScope.values()))
// 针对国外平台配置代理
.httpConfig(HttpConfig.builder()
.timeout(15000)
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 10080)))
.build())
.build());
break;
case "douyin":
authRequest = new AuthDouyinRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://dblog-web.zhyd.me/oauth/callback/douyin")
.build());
break;
case "linkedin":
authRequest = new AuthLinkedinRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/linkedin")
.scopes(null)
.build());
break;
case "microsoft":
authRequest = new AuthMicrosoftRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/microsoft")
.scopes(Arrays.asList(
AuthMicrosoftScope.USER_READ.getScope(),
AuthMicrosoftScope.USER_READWRITE.getScope(),
AuthMicrosoftScope.USER_READBASIC_ALL.getScope(),
AuthMicrosoftScope.USER_READ_ALL.getScope(),
AuthMicrosoftScope.USER_READWRITE_ALL.getScope(),
AuthMicrosoftScope.USER_INVITE_ALL.getScope(),
AuthMicrosoftScope.USER_EXPORT_ALL.getScope(),
AuthMicrosoftScope.USER_MANAGEIDENTITIES_ALL.getScope(),
AuthMicrosoftScope.FILES_READ.getScope()
))
.build());
break;
case "mi":
authRequest = new AuthMiRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://dblog-web.zhyd.me/oauth/callback/mi")
.build());
break;
case "toutiao":
authRequest = new AuthToutiaoRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://dblog-web.zhyd.me/oauth/callback/toutiao")
.build());
break;
case "teambition":
authRequest = new AuthTeambitionRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://127.0.0.1:8443/oauth/callback/teambition")
.build());
break;
case "pinterest":
authRequest = new AuthPinterestRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("https://eadmin.innodev.com.cn/oauth/callback/pinterest")
// 针对国外平台配置代理
.httpConfig(HttpConfig.builder()
.timeout(15000)
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 10080)))
.build())
.build());
break;
case "renren":
authRequest = new AuthRenrenRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://127.0.0.1:8443/oauth/callback/teambition")
.build());
break;
case "stack_overflow":
authRequest = new AuthStackOverflowRequest(AuthConfig.builder()
.clientId("")
.clientSecret("((")
.redirectUri("http://localhost:8443/oauth/callback/stack_overflow")
.stackOverflowKey("")
.build());
break;
case "huawei":
authRequest = new AuthHuaweiRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://127.0.0.1:8443/oauth/callback/huawei")
.scopes(Arrays.asList(
AuthHuaweiScope.BASE_PROFILE.getScope(),
AuthHuaweiScope.MOBILE_NUMBER.getScope(),
AuthHuaweiScope.ACCOUNTLIST.getScope(),
AuthHuaweiScope.SCOPE_DRIVE_FILE.getScope(),
AuthHuaweiScope.SCOPE_DRIVE_APPDATA.getScope()
))
.build());
break;
case "wechat_enterprise":
authRequest = new AuthWeChatEnterpriseQrcodeRequest(AuthConfig.builder()
.clientId(wechatEnterpriseConfig.getAppKey())
.clientSecret(wechatEnterpriseConfig.getAppSecret())
.redirectUri(wechatEnterpriseConfig.getRedirectUri())
.agentId(wechatEnterpriseConfig.getAgentid())
.build());
break;
case "kujiale":
authRequest = new AuthKujialeRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://dblog-web.zhyd.me/oauth/callback/kujiale")
.build());
break;
case "gitlab":
authRequest = new AuthGitlabRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/gitlab")
.scopes(AuthScopeUtils.getScopes(AuthGitlabScope.values()))
.build());
break;
case "meituan":
authRequest = new AuthMeituanRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/meituan")
.build());
break;
case "eleme":
authRequest = new AuthElemeRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://dblog-web.zhyd.me/oauth/callback/eleme")
.build());
break;
case "twitter":
authRequest = new AuthTwitterRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("https://threelogin.31huiyi.com/oauth/callback/twitter")
// 针对国外平台配置代理
.httpConfig(HttpConfig.builder()
.timeout(15000)
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 10080)))
.build())
.build());
break;
case "wechat_mp":
authRequest = new AuthWeChatMpRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("")
.build());
break;
case "aliyun":
authRequest = new AuthAliyunRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/aliyun")
.build());
break;
case "xmly":
authRequest = new AuthXmlyRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/xmly")
.build());
break;
case "feishu":
authRequest = new AuthFeishuRequest(AuthConfig.builder()
.clientId("")
.clientSecret("")
.redirectUri("http://localhost:8443/oauth/callback/feishu")
.build());
break;
default:
break;
}
if (null == authRequest) {
throw new AuthException("未获取到有效的Auth配置");
}
return authRequest;
}
}

View File

@ -0,0 +1,78 @@
package com.xjrsoft.organization.service.impl;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.dto.SwitchPostDto;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.entity.Post;
import com.xjrsoft.organization.entity.User;
import com.xjrsoft.organization.mapper.DepartmentMapper;
import com.xjrsoft.organization.mapper.PostMapper;
import com.xjrsoft.organization.service.IPostService;
import com.xjrsoft.organization.vo.SwitchPostVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 岗位 服务实现类
* </p>
*
* @author tzx
* @since 2022-03-02
*/
@Service
@AllArgsConstructor
@Slf4j
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements IPostService {
private DepartmentMapper departmentMapper;
private RedisUtil redisUtil;
@Override
public SwitchPostVo switchPost(SwitchPostDto dto) {
SwitchPostVo result = new SwitchPostVo();
Post post = getById(dto.getPostId());
Department department = departmentMapper.selectById(post.getDeptId());
result.setPostId(post.getId());
result.setPostName(post.getName());
result.setDepartmentId(department.getId());
result.setDepartmentName(department.getName());
SaSession tokenSession = StpUtil.getTokenSession();
User loginUser = tokenSession.get(GlobalConstant.LOGIN_USER_INFO_KEY, new User());
loginUser.setPostId(post.getId());
loginUser.setDepartmentId(department.getId());
tokenSession.set(GlobalConstant.LOGIN_USER_INFO_KEY, loginUser);
tokenSession.set(GlobalConstant.LOGIN_USER_POST_INFO_KEY, post);
tokenSession.set(GlobalConstant.LOGIN_USER_DEPT_INFO_KEY, department);
//将登陆人所选择的身份缓存起来
//切换身份的时候 会一起修改
redisUtil.set(GlobalConstant.LOGIN_IDENTITY_CACHE_PREFIX + loginUser.getId(), post.getId());
return result;
}
@Override
public void postCache() {
log.info("刷新岗位表缓存开始");
List<Post> list = this.list();
redisUtil.set(GlobalConstant.POST_CACHE_KEY,list);
redisUtil.set(GlobalConstant.POST_NAME_CACHE_KEY,list.stream().collect(Collectors.toMap(Post::getId,Post::getName)));
log.info("刷新岗位表缓存结束");
}
}

View File

@ -0,0 +1,20 @@
package com.xjrsoft.organization.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjrsoft.organization.entity.Role;
import com.xjrsoft.organization.mapper.RoleMapper;
import com.xjrsoft.organization.service.IRoleService;
import org.springframework.stereotype.Service;
/**
* <p>
* 角色 服务实现类
* </p>
*
* @author tzx
* @since 2022-03-02
*/
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {
}

View File

@ -0,0 +1,507 @@
package com.xjrsoft.organization.service.impl;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.cloud.govern.service.invoke.ServiceSdk;
import com.cloud.govern.service.invoke.domain.query.DataQuery;
import com.cloud.govern.service.invoke.domain.query.SortFieldDTO;
import com.cloud.govern.service.invoke.domain.request.DataServiceScrollRequest;
import com.cloud.govern.service.invoke.utils.Tools;
import com.xjrsoft.common.core.config.CommonPropertiesConfig;
import com.xjrsoft.common.core.config.DataCenterServiceConfig;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.uitls.DateUtils;
import com.xjrsoft.common.core.uitls.MD5Encrypt;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.entity.SyncOrgAndUserFromDataCenter;
import com.xjrsoft.organization.entity.User;
import com.xjrsoft.organization.entity.UserDeptRelation;
import com.xjrsoft.organization.mapper.SyncOrgAndUserFromDataCenterMapper;
import com.xjrsoft.organization.service.IDepartmentService;
import com.xjrsoft.organization.service.IUserDeptRelationService;
import com.xjrsoft.organization.service.IUserService;
import com.xjrsoft.organization.vo.SyncOrgAndUserFromDataCenterPageVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import com.xjrsoft.organization.service.ISyncOrgAndUserService;
import com.xjrsoft.common.core.constant.SyncConstant;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Slf4j
@RequiredArgsConstructor
public class SyncOrgAndUserFromDataCenterServiceImpl extends ServiceImpl<SyncOrgAndUserFromDataCenterMapper, SyncOrgAndUserFromDataCenter> implements ISyncOrgAndUserService {
private final SyncOrgAndUserFromDataCenterMapper syncOrgAndUserFromDataCenterMapper;
private static Integer pageSize = 2000;
private static Integer batchSize = 500;
private final IDepartmentService departmentService;
private final IUserService userService;
private final IUserDeptRelationService userDeptRelationService;
private final CommonPropertiesConfig propertiesConfig;
private final DataCenterServiceConfig dataCenterServiceConfig;
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, String> sync(Integer syncType) throws Exception {
List<Department>rootDepartments=departmentService.getRootDepartment();
if(rootDepartments!=null){
Map<String, String>result=new HashMap<>(rootDepartments.size());
for(Department rootDepartment:rootDepartments){
result.put(rootDepartment.getCode(),JSONObject.toJSONString(sync(syncType,rootDepartment.getCode())));
}
return result;
}else{
return sync(syncType,null);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, String> sync(Integer syncType, String startRootCode) throws Exception {
log.info("start sync from "+ (SyncConstant.SYNC_TYPE_MANUAL==syncType?"MANUAL":"SCHEDULE")+" and startRootCode:"+startRootCode);
Map<String,String>result=new HashMap<>();
result.put("syncType",syncType+"");
Date startTime=new Date();
result.put("startTime", DateUtils.format(startTime,DateUtils.DATE_TIME_PATTERN));
//先把中台的数据同步到中间表里
pullDataAndSave();
//再把中间表的数据更新到组织和用户表里
Map<String,Map<Long, Department>>deptMap=new HashMap<>(3);
deptMap.put("add",new HashMap<>());
deptMap.put("update",new HashMap<>());
deptMap.put("delete",new HashMap<>());
Map<String,Map<Long, User>>userMap=new HashMap<>(3);
userMap.put("add",new HashMap<>());
userMap.put("update",new HashMap<>());
userMap.put("delete",new HashMap<>());
Map<String,Map<String, UserDeptRelation>>userDeptMap=new HashMap<>(3);
userDeptMap.put("add",new HashMap<>());
userDeptMap.put("update",new HashMap<>());
userDeptMap.put("delete",new HashMap<>());
//开始同步根节点
Department rootSync=null;
if(StringUtils.isNotBlank(startRootCode)){
rootSync=createDeptFromSync(getOne(Wrappers.<SyncOrgAndUserFromDataCenter>query().lambda().eq(SyncOrgAndUserFromDataCenter::getCode,startRootCode)));
}
if(rootSync==null) {
//没有指定根节点则赋值集团根节点
startRootCode="YDZ";
String startRootName="广东省能源集团有限公司";
Long startRootParentId=0L;
rootSync=new Department(MD5Encrypt.toLong(startRootCode),startRootCode,startRootName,startRootParentId);
rootSync.setDepartmentType(3);
}
result.put("startRootCode",startRootCode);
//先更新组织根节点
Department root=departmentService.getById(rootSync.getId());
if(root==null){
deptMap.get("add").put(rootSync.getId(), rootSync);
}else if(!root.equals(rootSync)){
deptMap.get("update").put(rootSync.getId(), rootSync);
}
//从根节点开始递归下级 TODO 不同步的
syncByParent(rootSync,deptMap,userMap,userDeptMap);
//保存数据
result.putAll(saveResult(deptMap, userMap, userDeptMap));
Date endTime=new Date();
result.put("endTime", DateUtils.format(endTime,DateUtils.DATE_TIME_PATTERN));
result.put("costTime",(endTime.getTime()-startTime.getTime())/1000+"");
log.info(JSONObject.toJSONString(result));
log.info("finish sync from "+ (SyncConstant.SYNC_TYPE_MANUAL==syncType?"MANUAL":"SCHEDULE")+" and startRootCode:"+startRootCode);
return result;
}
private Map<String,String>saveResult(Map<String,Map<Long,Department>>deptMap,Map<String,Map<Long,User>>userMap,Map<String,Map<String,UserDeptRelation>>userDeptMap)throws Exception{
Map<String,String>result=new HashMap<>();
Collection<Long>interDeptId=CollectionUtil.intersection(deptMap.get("add").keySet(),deptMap.get("delete").keySet());
for(Long deptId:interDeptId){
//部门delete和add的交集也是update
deptMap.get("update").put(deptId,deptMap.get("add").get(deptId));
//部门delete和add的差集是最终delete从delete中减去交集部分
deptMap.get("delete").remove(deptId);
//部门add和delete的差集是最终add从add中减去交集部分
deptMap.get("add").remove(deptId);
}
result.put("deleteDeptSize",deptMap.get("delete").size()+"");
if(deptMap.get("delete").size()>0) {
log.info("deleteDeptIdList->\n"+JSONArray.toJSONString(deptMap.get("delete").keySet()));
log.debug("deleteDeptList->\n"+JSONObject.toJSONString(deptMap.get("delete").values()));
//仅做逻辑删除
result.put("deleteDeptResult", departmentService.removeBatchByIds(deptMap.get("delete").keySet(), batchSize) + "");
}
result.put("addDeptSize",deptMap.get("add").size()+"");
if(deptMap.get("add").size()>0) {
log.info("addDeptIdList->\n"+JSONArray.toJSONString(deptMap.get("add").keySet()));
log.debug("addDeptList->\n"+JSONObject.toJSONString(deptMap.get("add").values()));
Object savePoint=TransactionAspectSupport.currentTransactionStatus().createSavepoint();
//部门已逻辑删除时,仅更新 TODO 已逻辑删除的要恢复?
try {
result.put("addDeptResult", departmentService.saveOrUpdateBatch(deptMap.get("add").values(), batchSize) + "");
}catch (Exception e){
log.error("failed to saveOrUpdateBatch department----------"+JSONObject.toJSONString(deptMap.get("add").values()),e);
//pg需要手动回滚否则会导致全部数据回滚
TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
}
}
result.put("updateDeptSize",deptMap.get("update").size()+"");
if(deptMap.get("update").size()>0) {
log.info("updateDeptIdList->\n"+JSONArray.toJSONString(deptMap.get("update").keySet()));
log.debug("updateDeptList->\n"+JSONObject.toJSONString(deptMap.get("update").values()));
result.put("updateDeptResult", departmentService.updateBatchById(deptMap.get("update").values(), batchSize) + "");
}
Collection<Long>interUserId=CollectionUtil.intersection(userMap.get("add").keySet(),userMap.get("delete").keySet());
for(Long userId:interUserId){
//人员delete和add的交集也是update
userMap.get("update").put(userId,userMap.get("add").get(userId));
//人员delete和add的差集是最终delete从delete中减去交集部分
userMap.get("delete").remove(userId);
//人员add和delete的差集是最终add从add中减去交集部分
userMap.get("add").remove(userId);
}
result.put("deleteUserSize",userMap.get("delete").size()+"");
if(userMap.get("delete").size()>0) {
log.info("deleteUserIdList->\n"+JSONArray.toJSONString(userMap.get("delete").keySet()));
log.debug("deleteUserList->\n"+JSONObject.toJSONString(userMap.get("delete").values()));
//人员减少兼职时也会导致人员被删除,理论上应该只删除只属于一个部门的用户,即需要等下面用户部门更新完删除无部门的用户,如果遇到这种情况,先手动恢复人员
//仅做逻辑删除
//不需删除用户,无部门的用户组织机构树上不可见即可
//result.put("deleteUserResult", userService.removeBatchByIds(userMap.get("delete").keySet(), batchSize) + "");
}
result.put("addUserSize",userMap.get("add").size()+"");
if(userMap.get("add").size()>0) {
log.info("addUserIdList->\n"+JSONArray.toJSONString(userMap.get("add").keySet()));
log.debug("addUserList->\n"+JSONObject.toJSONString(userMap.get("add").values()));
Object savePoint=TransactionAspectSupport.currentTransactionStatus().createSavepoint();
//人员增加兼职或已逻辑删除时人员已存在,仅更新 TODO 已逻辑删除的要恢复?
try {
result.put("addUserResult", userService.saveOrUpdateBatch(userMap.get("add").values(), batchSize) + "");
}catch (Exception e){
log.error("failed to saveOrUpdateBatch user----------"+JSONObject.toJSONString(userMap.get("add").values()),e);
//pg需要手动回滚否则会导致全部数据回滚
TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
}
}
result.put("updateUserSize",userMap.get("update").size()+"");
if(userMap.get("update").size()>0) {
log.info("updateUserIdList->\n"+JSONArray.toJSONString(userMap.get("update").keySet()));
log.debug("updateUserList->\n"+JSONObject.toJSONString(userMap.get("update").values()));
result.put("updateUserResult", userService.updateBatchById(userMap.get("update").values(), batchSize) + "");
}
//人员部门不会有交集的情况,全删全加即可
result.put("deleteUserDeptSize",userDeptMap.get("delete").size()+"");
if(userDeptMap.get("delete").size()>0) {
log.info("deleteUserDeptIdList->\n"+JSONArray.toJSONString(userDeptMap.get("delete").keySet()));
log.debug("deleteUserDeptList->\n"+JSONObject.toJSONString(userDeptMap.get("delete").values()));
result.put("deleteUserDeptResult", SqlHelper.retBool(userDeptRelationService.getBaseMapper().deleteBatchIds(userDeptMap.get("delete").values().stream().map(UserDeptRelation::getId).collect(Collectors.toList()))) + "");
}
result.put("addUserDeptSize",userDeptMap.get("add").size()+"");
if(userDeptMap.get("add").size()>0) {
log.info("addUserDeptIdList->\n"+JSONArray.toJSONString(userDeptMap.get("add").keySet()));
log.debug("addUserDeptList->\n"+JSONObject.toJSONString(userDeptMap.get("add").values()));
//可重复添加,不会主键冲突导致数据回滚
result.put("addUserDeptResult", userDeptRelationService.saveBatch(userDeptMap.get("add").values(), batchSize) + "");
}
result.put("updateUserDeptSize",userDeptMap.get("update").size()+"");
if(userDeptMap.get("update").size()>0) {
log.info("updateUserDeptIdList->\n"+JSONArray.toJSONString(userDeptMap.get("update").keySet()));
log.debug("updateUserDeptList->\n"+JSONObject.toJSONString(userDeptMap.get("update").values()));
result.put("updateUserDeptResult", userDeptRelationService.updateBatchById(userDeptMap.get("update").values(), batchSize) + "");
}
return result;
}
private void syncByParent(Department parent,Map<String,Map<Long,Department>>deptMap,Map<String,Map<Long,User>>userMap,Map<String,Map<String,UserDeptRelation>>userDeptMap)throws Exception{
if(parent==null){
return;
}
List<SyncOrgAndUserFromDataCenter>syncList=list(Wrappers.<SyncOrgAndUserFromDataCenter>query().lambda().eq(SyncOrgAndUserFromDataCenter::getParentLongId,parent.getId()));
List<Department>deptList=departmentService.list(Wrappers.<Department>query().lambda().eq(Department::getParentId,parent.getId()));
Map<Long,Department>deptTmpMap=new HashMap<>();
for(Department dept:deptList){
deptTmpMap.put(dept.getId(),dept);
}
List<UserDeptRelation>userDeptList=userDeptRelationService.list(Wrappers.<UserDeptRelation>query().lambda().eq(UserDeptRelation::getDeptId,parent.getId()));
Map<String,UserDeptRelation>userDeptTmpMap=new HashMap<>();
for(UserDeptRelation userDept:userDeptList){
userDeptTmpMap.put(userDept.getDeptId()+"_"+userDept.getUserId(),userDept);
}
List<User>userList=userDeptList.isEmpty()?new ArrayList<>():userService.list(Wrappers.<User>query().lambda().in(User::getId,userDeptList.stream().map(UserDeptRelation::getUserId).collect(Collectors.toList())));
Map<Long,User>userTmpMap=new HashMap<>();
for(User user:userList){
userTmpMap.put(user.getId(),user);
}
//以sync的为准比对出新增、更新、删除的数据
for(SyncOrgAndUserFromDataCenter sync:syncList){
if("3".equals(sync.getType())){
//比对人员
User user=createUserFromSync(sync);
//比对人员部门
UserDeptRelation userDept=createUserDeptFromSync(sync);
//用过即删
User userTmp=userTmpMap.remove(sync.getLongId());
if(userTmp!=null){
if("N".equals(userTmp.getIsSync())){
//人不同步
continue;
}
//部门组织关系已存在
UserDeptRelation userDeptTmp=userDeptTmpMap.remove(sync.getParentLongId()+"_"+sync.getLongId());
userDept.setId(userDeptTmp.getId());
//没有不同步用户部门
if(!"N".equals(userDeptTmp.getIsSync())&&!userDept.equals(userDeptTmp)){
userDeptMap.get("update").put(sync.getParentLongId()+"_"+sync.getLongId(),userDept);
}
//拷贝不同步的字段
copyUser(userTmp,user);
//如果密码为空,更新为默认密码
if(StringUtils.isBlank(user.getPassword())){
user.setPassword(SaSecureUtil.md5BySalt(propertiesConfig.getDefaultPassword(), GlobalConstant.SECRET_KEY));
}
//已存在,做比对更新
if(!user.equals(userTmp)&&"Y".equals(userDept.getIsMain())){
//只更新主职
userMap.get("update").put(user.getId(),user);
}
}else{
//不存在,放新增
//使用默认密码
user.setPassword(SaSecureUtil.md5BySalt(propertiesConfig.getDefaultPassword(), GlobalConstant.SECRET_KEY));
userMap.get("add").put(user.getId(),user);
//增加部门关系
userDeptMap.get("add").put(sync.getParentLongId()+"_"+sync.getLongId(),userDept);
}
}else{
//比对公司、部门
Department dept=createDeptFromSync(sync);
//用过即删
Department deptTmp=deptTmpMap.remove(sync.getLongId());
if(deptTmp!=null){
if("N".equals(deptTmp.getIsSync())){
//部门不同步
continue;
}
//拷贝不同步的字段
copyDept(deptTmp,dept);
//已存在,做比对更新
if(!dept.equals(deptTmp)){
deptMap.get("update").put(dept.getId(),dept);
}
}else{
//不存在,放新增
deptMap.get("add").put(dept.getId(),dept);
}
//递归下级,深度优先
syncByParent(dept,deptMap,userMap,userDeptMap);
}
}
//剩余的数据放删除中
for(Long key:deptTmpMap.keySet()){
if(!"N".equals(deptTmpMap.get(key).getIsSync())) {
deptMap.get("delete").put(key, deptTmpMap.get(key));
}
}
for(Long key:userTmpMap.keySet()){
if(!"N".equals(userTmpMap.get(key).getIsSync())) {
userMap.get("delete").put(key, userTmpMap.get(key));
}
}
for(String key:userDeptTmpMap.keySet()){
if(!"N".equals(userDeptTmpMap.get(key).getIsSync())) {
userDeptMap.get("delete").put(key, userDeptTmpMap.get(key));
}
}
}
private UserDeptRelation createUserDeptFromSync(SyncOrgAndUserFromDataCenter sync){
UserDeptRelation userDept=new UserDeptRelation(sync.getParentLongId(),sync.getLongId());
//是否主职
userDept.setIsMain("1".equals(sync.getIsMain())?"Y":"N");
if(StringUtils.isNotBlank(sync.getSort())) {
//存主职的排序
userDept.setSortCode(Integer.parseInt(sync.getSort()));
}
return userDept;
}
private void copyUser(User fromUser,User toUser){
toUser.setPassword(fromUser.getPassword());
if(toUser.getSortCode()==null){
toUser.setSortCode(fromUser.getSortCode());
}
}
private User createUserFromSync(SyncOrgAndUserFromDataCenter sync){
User user=new User(sync.getLongId(),sync.getCode(),sync.getName());
user.setCode(sync.getCode());
user.setNickName(sync.getName());
user.setGender("".equals(sync.getSex())?1:0);
user.setPhoneNumber(sync.getTelephonenumber());
user.setMobile(sync.getMobile());
user.setEmail(sync.getMail());
user.setAddress(sync.getOffice());
if(StringUtils.isNotBlank(sync.getSort())&&"1".equals(sync.getIsMain())) {
//存主职的排序
user.setSortCode(Integer.parseInt(sync.getSort()));
}
return user;
}
private void copyDept(Department fromDept,Department toDept){
toDept.setAddress(fromDept.getAddress());
}
private Department createDeptFromSync(SyncOrgAndUserFromDataCenter sync){
Department dept=new Department(sync.getLongId(),sync.getCode(),sync.getName(),sync.getParentLongId());
switch (sync.getType()){
case "0":
dept.setDepartmentType(2);
break;
case "1":
dept.setDepartmentType(1);
break;
case "2":
dept.setDepartmentType(0);
break;
}
if(StringUtils.isNotBlank(sync.getSort())) {
dept.setSortCode(Integer.parseInt(sync.getSort()));
}
return dept;
}
private List<SyncOrgAndUserFromDataCenter> pullDataAndSave()throws Exception{
Boolean hasMoreData=true;
List<SyncOrgAndUserFromDataCenter> syncOrgAndUser = new ArrayList<>();
SyncOrgAndUserFromDataCenterPageVo pageVo = new SyncOrgAndUserFromDataCenterPageVo(pageSize);
while (hasMoreData) {
JSONObject syncResponse = queryPlatformDataPage(pageVo);
if (syncResponse != null && syncResponse.getJSONObject("data") != null) {
JSONArray dataList = syncResponse.getJSONObject("data").getJSONArray("list");
if (dataList != null && dataList.size() > 0) {
syncOrgAndUser.addAll(dataList.toJavaList(SyncOrgAndUserFromDataCenter.class));
}
String nextToken=syncResponse.getJSONObject("data").getString("nextToken");
if(StringUtils.isNotBlank(nextToken)){
pageVo.setNextToken(nextToken);
}else{
hasMoreData=false;
}
}else{
hasMoreData=false;
}
}
if(!syncOrgAndUser.isEmpty()){
//预生成固定id
for(SyncOrgAndUserFromDataCenter obj:syncOrgAndUser){
obj.setLongId(MD5Encrypt.toLong(obj.getCode()));
obj.setParentLongId(MD5Encrypt.toLong(obj.getParentCode()));
}
//先清空表,再全部插入
if(count()>0){
log.info("removed all data:"+syncOrgAndUserFromDataCenterMapper.emptyAllData());
}
log.info("save sync org and user:"+syncOrgAndUser.size()+" result:"+saveBatch(syncOrgAndUser,batchSize));
}
return syncOrgAndUser;
}
private JSONObject queryPlatformDataPage(SyncOrgAndUserFromDataCenterPageVo page) throws Exception {
//请求URL
String url = "";
//用户ID
String userId = "";
//部门ID
String deptId = "";
//订阅ID
String subscribeId = "";
//认证token
String accessToken = "";
//应用系统标识没有应用系统即设置为null
String applicationId = null;
//分页大小
int size = page.getPageSize();
//构造查询条件
DataQuery query = null;
url = dataCenterServiceConfig.getUrl();
userId = dataCenterServiceConfig.getUserId();
deptId = dataCenterServiceConfig.getDeptId();
subscribeId = dataCenterServiceConfig.getSubscribeId();
accessToken = dataCenterServiceConfig.getAccessToken();
SortFieldDTO sortFieldDTO = new SortFieldDTO();
sortFieldDTO.setSort("code");
sortFieldDTO.setSortOrder("asc");
//第一次请求时nextToken位空下次请求从上次请求的结果中获取nextToken
String nextToken = StringUtils.isNotEmpty(page.getNextToken())? page.getNextToken():"";
// 构造请求
DataServiceScrollRequest req = null;
//当nextToken不为空时查询参数不生效请求按照第一次的查询条件执行
if(Tools.isNull(nextToken)){
//构造查询条件
/* query = new DataQuery.Builder()
//and 条件组合,可空
.must(new QueryFieldDTO("parent_code","c..","eq","12110"))
// or 条件组合,可空
.build();*/
req = new DataServiceScrollRequest.Builder()
.size(size)
// 设置是否返回字段名默认false
.includeColumns(true)
//设置数据查询条件,可空
//.dataQuery(query)
//设置排序字段,可空
.sort(sortFieldDTO)
.build();
} else {
req = new DataServiceScrollRequest.Builder()
.size(size)
//翻页token必填参数
.nextToken(nextToken)
// 设置是否返回字段名默认false
.includeColumns(false)
.build();
}
//返回分页查询的结果
String result = ServiceSdk.invoke(url,req,deptId,userId,
subscribeId,applicationId,accessToken);
//LOGGER.info("查询平台数据返回报文:" + result);
//解密数据示例,若返回字段设置了对称加密,空用此示例方法解密
//decryptData(result);
return StringUtils.isNotBlank(result)?JSONObject.parseObject(result):null;
}
}

View File

@ -0,0 +1,20 @@
package com.xjrsoft.organization.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjrsoft.organization.entity.UserChargeDept;
import com.xjrsoft.organization.mapper.UserChargeDeptMapper;
import com.xjrsoft.organization.service.IUserChargeDeptService;
import org.springframework.stereotype.Service;
/**
* <p>
* 用户负责部门表 服务实现类
* </p>
*
* @author hnyyzy
* @since 2023-12-20
*/
@Service
public class UserChargeDeptServiceImpl extends ServiceImpl<UserChargeDeptMapper, UserChargeDept> implements IUserChargeDeptService {
}

View File

@ -0,0 +1,11 @@
package com.xjrsoft.organization.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjrsoft.organization.entity.UserDeptRelation;
import com.xjrsoft.organization.mapper.UserDeptRelationMapper;
import com.xjrsoft.organization.service.IUserDeptRelationService;
import org.springframework.stereotype.Service;
@Service
public class UserDeptRelationServiceImpl extends ServiceImpl<UserDeptRelationMapper, UserDeptRelation> implements IUserDeptRelationService {
}

View File

@ -0,0 +1,115 @@
package com.xjrsoft.organization.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.enums.YesOrNoEnum;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.dto.UpdateUserPostDto;
import com.xjrsoft.organization.entity.Post;
import com.xjrsoft.organization.entity.UserDeptRelation;
import com.xjrsoft.organization.entity.UserPostRelation;
import com.xjrsoft.organization.mapper.UserPostRelationMapper;
import com.xjrsoft.organization.service.IUserDeptRelationService;
import com.xjrsoft.organization.service.IUserPostRelationService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@Service
@AllArgsConstructor
public class UserPostRelationServiceImpl extends ServiceImpl<UserPostRelationMapper, UserPostRelation> implements IUserPostRelationService {
private final IUserDeptRelationService userDeptRelationService;
private final RedisUtil redisUtil;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean addPostUser(UpdateUserPostDto dto) {
Long postId = dto.getPostId();
Long deptId = dto.getDeptId();
//从缓存中获取岗位、用户岗位、用户部门信息数据
List<Post> postList= redisUtil.get(GlobalConstant.POST_CACHE_KEY, new TypeReference<List<Post>>() {
});
List<UserDeptRelation> userDeptRelations= redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
});
List<UserPostRelation> userPostRelations= redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
});
List<Long> userIds = new ArrayList<>();
if (dto.getType() == YesOrNoEnum.NO.getCode()){
userIds = dto.getUserIds();
}else {
//把该组织下所以的人员全部添加到岗位下面
List<Long> deptIds = dto.getDepartmentIds();
if (CollectionUtil.isNotEmpty(deptIds)){
List<UserDeptRelation> list = userDeptRelations.stream().filter(x->deptIds.contains(x.getDeptId())).collect(Collectors.toList());
//去重操作,防止一个用户在多个组织下
userIds = list.stream().map(UserDeptRelation::getUserId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
}
}
List<UserPostRelation> userPostRelationList = new ArrayList<>(userIds.size());
for (Long userId : userIds) {
UserPostRelation userPostRelation = new UserPostRelation();
userPostRelation.setPostId(postId);
userPostRelation.setUserId(userId);
userPostRelationList.add(userPostRelation);
}
//查询该岗位下的人员,用于删除对应人员的部门信息
List<Long> userIdList = userPostRelations.stream().filter(x -> x.getPostId().equals(postId)).map(UserPostRelation::getUserId).collect(Collectors.toList());
//先删除用户岗位关联表,岗位下存在的人员
this.remove(Wrappers.<UserPostRelation>lambdaQuery().eq(UserPostRelation::getPostId, postId));
//再保存用户岗位关联关系表数据
this.saveBatch(userPostRelationList);
//查询此岗位对应的部门,并将此岗位对应的部门删除
Long deleteDeptId = postList.stream().filter(x->x.getId().equals(postId)).findFirst().orElse(new Post()).getDeptId();
//删除对应的用户部门关联关系表数据
List<UserDeptRelation> collect = userDeptRelations.stream().filter(x -> x.getDeptId().equals(deleteDeptId) && userIdList.contains(x.getUserId())).collect(Collectors.toList());
userDeptRelationService.removeBatchByIds(collect);
//如果部门下没有此人员,将此人员添加到该部门下
List<UserDeptRelation> list = userDeptRelationService.list(Wrappers.<UserDeptRelation>query().lambda().eq(UserDeptRelation::getDeptId, deptId));
List<UserDeptRelation> userDeptRelationList = new ArrayList<>();
//需要被过滤掉的用户id
List<Long> finalUserIds = userIds;
List<Long> containList = list.stream().map(UserDeptRelation::getUserId).filter(u -> finalUserIds.contains(u)).collect(Collectors.toList());
//拿userIds和userIdList的差集
List<Long> subtractList = (List<Long>) CollectionUtil.subtract(userIds, containList);
if (subtractList.size()>0){
for (Long userId : subtractList) {
UserDeptRelation userDeptRelation = new UserDeptRelation();
userDeptRelation.setUserId(userId);
userDeptRelation.setDeptId(deptId);
userDeptRelationList.add(userDeptRelation);
}
userDeptRelationService.saveBatch(userDeptRelationList);
}
List<Long> finalUserIds1 = userIds;
CompletableFuture.runAsync(() -> {
List<UserPostRelation> userRelationList = this.list();
redisUtil.set(GlobalConstant.USER_POST_RELATION_CACHE_KEY, userRelationList);
List<UserDeptRelation> deptRelationList = userDeptRelationService.list();
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, deptRelationList);
// 清空用户单签选择岗位缓存,以及用户重新登录
for (Long userId : finalUserIds1) {
redisUtil.delete(GlobalConstant.LOGIN_IDENTITY_CACHE_PREFIX + userId);
StpUtil.logout(userId);
}
});
return Boolean.TRUE;
}
}

View File

@ -0,0 +1,39 @@
package com.xjrsoft.organization.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xjrsoft.organization.entity.UserRoleRelation;
import com.xjrsoft.organization.mapper.UserRoleRelationMapper;
import com.xjrsoft.organization.service.IUserRoleRelationService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* 用户关联角色表 服务实现类
* </p>
*
* @author tzx
* @since 2022-03-02
*/
@Service
public class UserRoleRelationServiceImpl extends ServiceImpl<UserRoleRelationMapper, UserRoleRelation> implements IUserRoleRelationService {
@Override
@Transactional
public boolean addRoleUser(Long roleId, List<Long> userIds) {
List<UserRoleRelation> userRoleRelationList = new ArrayList<>(userIds.size());
for (Long userId : userIds) {
UserRoleRelation userRoleRelation = new UserRoleRelation();
userRoleRelation.setRoleId(roleId);
userRoleRelation.setUserId(userId);
userRoleRelationList.add(userRoleRelation);
}
// 先删除角色下存在的人员
this.remove(Wrappers.<UserRoleRelation>lambdaQuery().eq(UserRoleRelation::getRoleId, roleId));
return this.saveBatch(userRoleRelationList);
}
}

View File

@ -0,0 +1,578 @@
package com.xjrsoft.organization.service.impl;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.ObjectUtil;
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.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.toolkit.MPJWrappers;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.common.core.domain.page.PageOutput;
import com.xjrsoft.common.core.exception.MyException;
import com.xjrsoft.common.core.exception.ValidationException;
import com.xjrsoft.common.core.uitls.VoToColumnUtil;
import com.xjrsoft.common.mybatis.utils.ConventPage;
import com.xjrsoft.common.redis.service.RedisUtil;
import com.xjrsoft.organization.dto.AddUserDto;
import com.xjrsoft.organization.dto.UpdateUserDto;
import com.xjrsoft.organization.dto.UserPageDto;
import com.xjrsoft.organization.dto.WeChatPageDto;
import com.xjrsoft.organization.entity.*;
import com.xjrsoft.organization.mapper.UserMapper;
import com.xjrsoft.organization.service.*;
import com.xjrsoft.organization.vo.*;
import com.xjrsoft.system.client.ITenantClient;
import com.xjrsoft.system.entity.Tenant;
import com.xjrsoft.tenant.util.SecureUtil;
import com.xjrsoft.tenant.util.TenantUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* <p>
* 用户 服务实现类
* </p>
*
* @author tzx
* @since 2022-03-02
*/
@Service
@AllArgsConstructor
@Slf4j
public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, User> implements IUserService {
private final UserMapper userMapper;
private final IUserDeptRelationService userDeptRelationService;
private final IUserRoleRelationService userRoleRelationService;
private final IUserPostRelationService userPostRelationService;
private final IUserChargeDeptService userChargeDeptService;
private final IDepartmentService departmentService;
private final IPostService postService;
private final IRoleService roleService;
private final RedisUtil redisUtil;
private final ITenantClient tenantClient;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean add(AddUserDto dto) {
long count = count(Wrappers.<User>query().lambda().eq(User::getUserName, dto.getUserName()).or().eq(User::getCode, dto.getCode()));
if (count > 0) {
throw new MyException("用户名称或编码已存在");
}
User user = BeanUtil.toBean(dto, User.class);
//密码加密加盐存储到数据库
user.setPassword(SaSecureUtil.md5BySalt(dto.getPassword(), GlobalConstant.SECRET_KEY));
save(user);
List<UserDeptRelation> userDeptRelationList = new ArrayList<>();
if (StrUtil.isNotBlank(dto.getDepartmentIds())){
String allDeptIdStr = StrUtil.join(StringPool.COMMA, dto.getDepartmentIds());
List<Long> departmentIds = Arrays.stream(allDeptIdStr.split(StringPool.COMMA)).map(Convert::toLong).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(departmentIds)){
for (Long deptId : departmentIds) {
//将用户所选部门保存到关联表中
UserDeptRelation userDeptRelation = new UserDeptRelation();
userDeptRelation.setUserId(user.getId());
userDeptRelation.setDeptId(deptId);
userDeptRelationList.add(userDeptRelation);
}
}
userDeptRelationService.saveBatch(userDeptRelationList);
}
//将用户所选角色保存到关联表中
List<UserRoleRelation> userRoleRelationList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(dto.getRoleIds()) && dto.getRoleIds().size() > 0){
for (Long id : dto.getRoleIds()) {
UserRoleRelation userRoleRelation = new UserRoleRelation();
userRoleRelation.setRoleId(id);
userRoleRelation.setUserId(user.getId());
userRoleRelationList.add(userRoleRelation);
}
userRoleRelationService.saveBatch(userRoleRelationList);
}
//将用户所选岗位保存到关联表中
List<UserPostRelation> userPostRelationList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(dto.getPostIds()) && dto.getPostIds().size() > 0){
for (Long id : dto.getPostIds()) {
UserPostRelation userPostRelation = new UserPostRelation();
userPostRelation.setPostId(id);
userPostRelation.setUserId(user.getId());
userPostRelationList.add(userPostRelation);
}
userPostRelationService.saveBatch(userPostRelationList);
}
//将用户所负责的部门保存到关联表中
List<UserChargeDept> userChargeDeptList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(dto.getChargeDepartmentIds()) && dto.getChargeDepartmentIds().size() > 0){
for (Long id : dto.getChargeDepartmentIds()) {
UserChargeDept userChargeDept = new UserChargeDept();
userChargeDept.setDeptId(id);
userChargeDept.setUserId(user.getId());
userChargeDeptList.add(userChargeDept);
}
userChargeDeptService.saveBatch(userChargeDeptList);
}
//异步更新用户表、用户部门表、用户角色表、用户岗位表数据
CompletableFuture.runAsync(() -> {
userCache();
List<UserDeptRelation> deptRelationList = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class));
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, deptRelationList);
List<UserRoleRelation> roleRelationList = userRoleRelationService.list(Wrappers.lambdaQuery(UserRoleRelation.class));
redisUtil.set(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, roleRelationList);
List<UserPostRelation> postRelationList = userPostRelationService.list(Wrappers.lambdaQuery(UserPostRelation.class));
redisUtil.set(GlobalConstant.USER_POST_RELATION_CACHE_KEY, postRelationList);
});
return Boolean.TRUE;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean update(UpdateUserDto dto) {
long count = count(Wrappers.<User>query().lambda()
.eq(User::getCode, dto.getCode())
.ne(User::getId, dto.getId()));
if (count > 0) {
throw new MyException("用户名称或编码已存在");
}
User user = BeanUtil.toBean(dto, User.class);
updateById(user);
//先删除再新增
userDeptRelationService.remove(Wrappers.<UserDeptRelation>query().lambda().eq(UserDeptRelation::getUserId,user.getId()));
userRoleRelationService.remove(Wrappers.<UserRoleRelation>query().lambda().eq(UserRoleRelation::getUserId,user.getId()));
userPostRelationService.remove(Wrappers.<UserPostRelation>query().lambda().eq(UserPostRelation::getUserId,user.getId()));
userChargeDeptService.remove(Wrappers.<UserChargeDept>query().lambda().eq(UserChargeDept::getUserId,user.getId()));
List<UserDeptRelation> userDeptRelationList = new ArrayList<>();
if (StrUtil.isNotBlank(dto.getDepartmentIds())){
String allDeptIdStr = StrUtil.join(StringPool.COMMA, dto.getDepartmentIds());
List<Long> departmentIds = Arrays.stream(allDeptIdStr.split(StringPool.COMMA)).map(Convert::toLong).collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(departmentIds)){
for (Long deptId : departmentIds) {
//将用户所选部门保存到关联表中
UserDeptRelation userDeptRelation = new UserDeptRelation();
userDeptRelation.setUserId(user.getId());
userDeptRelation.setDeptId(deptId);
userDeptRelationList.add(userDeptRelation);
}
}
userDeptRelationService.saveBatch(userDeptRelationList);
}
//将用户所选角色保存到关联表中
List<UserRoleRelation> userRoleRelationList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(dto.getRoleIds()) && dto.getRoleIds().size() > 0){
for (Long id : dto.getRoleIds()) {
UserRoleRelation userRoleRelation = new UserRoleRelation();
userRoleRelation.setRoleId(id);
userRoleRelation.setUserId(user.getId());
userRoleRelationList.add(userRoleRelation);
}
userRoleRelationService.saveBatch(userRoleRelationList);
}
//将用户所选岗位保存到关联表中
List<UserPostRelation> userPostRelationList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(dto.getPostIds()) && dto.getPostIds().size() > 0){
for (Long id : dto.getPostIds()) {
UserPostRelation userPostRelation = new UserPostRelation();
userPostRelation.setPostId(id);
userPostRelation.setUserId(user.getId());
userPostRelationList.add(userPostRelation);
}
userPostRelationService.saveBatch(userPostRelationList);
}
//将用户所负责的部门保存到关联表中
List<UserChargeDept> userChargeDeptList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(dto.getChargeDepartmentIds()) && dto.getChargeDepartmentIds().size() > 0){
for (Long id : dto.getChargeDepartmentIds()) {
UserChargeDept userChargeDept = new UserChargeDept();
userChargeDept.setDeptId(id);
userChargeDept.setUserId(user.getId());
userChargeDeptList.add(userChargeDept);
}
userChargeDeptService.saveBatch(userChargeDeptList);
}
//异步更新用户表、用户部门表、用户角色表、用户岗位表数据
CompletableFuture.runAsync(() -> {
userCache();
List<UserDeptRelation> deptRelationList = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class));
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, deptRelationList);
List<UserRoleRelation> roleRelationList = userRoleRelationService.list(Wrappers.lambdaQuery(UserRoleRelation.class));
redisUtil.set(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, roleRelationList);
List<UserPostRelation> postRelationList = userPostRelationService.list(Wrappers.lambdaQuery(UserPostRelation.class));
redisUtil.set(GlobalConstant.USER_POST_RELATION_CACHE_KEY, postRelationList);
});
return Boolean.TRUE;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteBatch(List<Long> ids) {
//删除时需要同时删除用户部门关联表和用户角色关联表和用户岗位关系表和用户负责部门关联表的数据。
this.removeBatchByIds(ids);
//根据用户ids去缓存中查询到对应的三个表的数据
List<UserDeptRelation> userDeptRelationList = redisUtil.get(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, new TypeReference<List<UserDeptRelation>>() {
});
List<UserPostRelation> userPostRelationList = redisUtil.get(GlobalConstant.USER_POST_RELATION_CACHE_KEY, new TypeReference<List<UserPostRelation>>() {
});
List<UserRoleRelation> userRoleRelationList = redisUtil.get(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, new TypeReference<List<UserRoleRelation>>() {
});
List<UserChargeDept> userChargeDeptList = userChargeDeptService.list();
//拿用户ids进行过滤如果存在就删除
List<Long> deptRelationIds = userDeptRelationList.stream().filter(u -> ids.contains(u.getUserId())).map(UserDeptRelation::getId).collect(Collectors.toList());
List<Long> postRelationIds = userPostRelationList.stream().filter(u -> ids.contains(u.getUserId())).map(UserPostRelation::getId).collect(Collectors.toList());
List<Long> roleRelationIds = userRoleRelationList.stream().filter(u -> ids.contains(u.getUserId())).map(UserRoleRelation::getId).collect(Collectors.toList());
List<Long> userChargeIds = userChargeDeptList.stream().filter(u -> ids.contains(u.getUserId())).map(UserChargeDept::getId).collect(Collectors.toList());
//调用四个表的删除
if(CollectionUtil.isNotEmpty(deptRelationIds)){
userDeptRelationService.removeBatchByIds(deptRelationIds);
}
if(CollectionUtil.isNotEmpty(postRelationIds)) {
userPostRelationService.removeBatchByIds(postRelationIds);
}
if(CollectionUtil.isNotEmpty(roleRelationIds)) {
userRoleRelationService.removeBatchByIds(roleRelationIds);
}
if (CollectionUtil.isNotEmpty(userChargeIds)){
userChargeDeptService.removeBatchByIds(userChargeIds);
}
//更新缓存
CompletableFuture.runAsync(() -> {
userCache();
List<UserDeptRelation> deptRelationList = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class));
redisUtil.set(GlobalConstant.USER_DEPT_RELATION_CACHE_KEY, deptRelationList);
List<UserPostRelation> postRelationList = userPostRelationService.list(Wrappers.lambdaQuery(UserPostRelation.class));
redisUtil.set(GlobalConstant.USER_POST_RELATION_CACHE_KEY, postRelationList);
List<UserRoleRelation> roleRelationList = userRoleRelationService.list(Wrappers.lambdaQuery(UserRoleRelation.class));
redisUtil.set(GlobalConstant.USER_ROLE_RELATION_CACHE_KEY, roleRelationList);
});
return Boolean.TRUE;
}
@Override
public List<UserInfoVo> getUsersInfo(String ids) {
if (StrUtil.isBlank(ids)) {
return new ArrayList<>();
}
List<Long> idList = Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList());
List<User> list = userMapper.selectList(Wrappers.lambdaQuery(User.class)
.in(User::getId, idList)
.select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserInfoVo.class).contains(x.getProperty())));
return BeanUtil.copyToList(list, UserInfoVo.class);
}
public List<Department> queryDepartmentsOfUser(Long id)
{
if (id == null) {
return new ArrayList<>();
}
List<Department> list = userMapper.queryDepartmentsOfUser(id);
return list;
}
public List<UserRoleVo> queryRolesOfUser(Long id){
if (id == null) {
return new ArrayList<>();
}
List<UserRoleVo> list = userMapper.queryRolesOfUser(id);
return list;
}
@Override
public PageOutput<WeChatPageVO> getPage(WeChatPageDto dto) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StrUtil.isNotBlank(dto.getKeyword()),User::getName,dto.getKeyword())
.select(User.class,x -> VoToColumnUtil.fieldsToColumns(WeChatPageVO.class).contains(x.getProperty()));
IPage<User> page = userMapper.selectPage(ConventPage.getPage(dto), queryWrapper);
List<User> records = page.getRecords();
for (User record : records) {
record.setRemark("员工更新成功");
record.setSortCode(1);
}
return ConventPage.getPageOutput(page, WeChatPageVO.class);
}
public PageOutput<UserPageVo> page(UserPageDto dto) {
List<Long> deptIds = new ArrayList<>();
if (ObjectUtil.isNotNull(dto.getDepartmentId())){
List<Department> list = redisUtil.get(GlobalConstant.DEP_CACHE_KEY,new TypeReference<List<Department>>() {
});
//当前部门的层级
String hierarchy = list.stream().filter(x -> x.getId().equals(dto.getDepartmentId())).findFirst().orElse(new Department()).getHierarchy();
if (StrUtil.isNotBlank(hierarchy)){
//层级里面包含当前部门层级的就是它的子集如1-1下面包含了1-1、1-1-2这种
deptIds = list.stream().filter(x -> StrUtil.isNotBlank(x.getHierarchy())&&x.getHierarchy().contains(hierarchy)).map(Department::getId).collect(Collectors.toList());
}else {
//如果不存在层级就查询自己的数据
deptIds.add(dto.getDepartmentId());
}
}
//因为多表关联 会有多个表都使用了id字段 所以必须专门指定主表的Id
if (ObjectUtil.isNotNull(dto.getDepartmentId())){//不为空联合查询
IPage<UserPageVo> page = this.selectJoinListPage(ConventPage.getPage(dto), UserPageVo.class,
MPJWrappers.<User>lambdaJoin()
.distinct()
.and(StrUtil.isNotBlank(dto.getKeyword()),
x -> x.like(User::getCode, dto.getKeyword()).or().like(User::getName, dto.getKeyword()))
.like(StrUtil.isNotBlank(dto.getUserName()), User::getUserName, dto.getUserName())
.like(StrUtil.isNotBlank(dto.getCode()), User::getCode, dto.getCode())
.like(StrUtil.isNotBlank(dto.getName()), User::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getMobile()), User::getMobile, dto.getMobile())
.in(ObjectUtil.isNotNull(dto.getDepartmentId()), UserDeptRelation::getDeptId, deptIds)
//.orderByDesc(User::getCreateDate)
.select(User::getId)
.select(User.class, x -> !"sortCode".equals(x.getProperty())&&VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()))
.leftJoin(UserDeptRelation.class, UserDeptRelation::getUserId, User::getId)
.select(UserDeptRelation::getSortCode)
.orderByAsc(UserDeptRelation::getSortCode));
return ConventPage.getPageOutput(page);
}else {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.like(StrUtil.isNotBlank(dto.getKeyword()), User::getName, dto.getKeyword())
.or(StrUtil.isNotBlank(dto.getKeyword()), x -> x.like(StrUtil.isNotBlank(dto.getKeyword()), User::getCode, dto.getKeyword()))
.like(StrUtil.isNotBlank(dto.getUserName()), User::getUserName, dto.getUserName())
.like(StrUtil.isNotBlank(dto.getCode()), User::getCode, dto.getCode())
.like(StrUtil.isNotBlank(dto.getName()), User::getName, dto.getName())
.like(StrUtil.isNotBlank(dto.getMobile()), User::getMobile, dto.getMobile())
//.orderByDesc(User::getCreateDate)
.orderByAsc(User::getSortCode)
.select(User.class, x -> VoToColumnUtil.fieldsToColumns(UserPageVo.class).contains(x.getProperty()));
IPage<User> page = this.page(ConventPage.getPage(dto),queryWrapper);
return ConventPage.getPageOutput(page, UserPageVo.class);
}
}
@Override
public UserVo getInfoByUserName(String userName){
User user = this.getOne(Wrappers.lambdaQuery(User.class).eq(User::getUserName, userName)); //.select(User::getId));
if (user == null) {
throw new ValidationException("找不到此用户!");
}
UserInfoVo currentInfo = this.getCurrentInfo(user);
UserVo userVo = BeanUtil.toBean(user, UserVo.class);
List<Long> deptIds = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class)
.eq(UserDeptRelation::getUserId, user.getId()))
.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());
String allDeptIdStr = StrUtil.join(StringPool.COMMA, deptIds);
userVo.setDepartmentIds(allDeptIdStr);
userVo.setRoles(currentInfo.getRoles());
userVo.setPosts(currentInfo.getPosts());
userVo.setChargeDepartments(currentInfo.getChargeDepartments());
return userVo;
}
/**
* 根据id获取用户信息
* @param id
* @return
*/
@Override
public UserVo getInfo(Long id) {
User user = this.getById(id);
if (user == null) {
throw new ValidationException("找不到此用户!");
}
UserInfoVo currentInfo = this.getCurrentInfo(user);
UserVo userVo = BeanUtil.toBean(user, UserVo.class);
List<Long> deptIds = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class)
.eq(UserDeptRelation::getUserId, user.getId()))
.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());
String allDeptIdStr = StrUtil.join(StringPool.COMMA, deptIds);
userVo.setDepartmentIds(allDeptIdStr);
userVo.setRoles(currentInfo.getRoles());
userVo.setPosts(currentInfo.getPosts());
userVo.setChargeDepartments(currentInfo.getChargeDepartments());
return userVo;
}
@Override
public DepartmentCompanyVo getDepartmentInfo(Long id){
User user = this.getById(id);
if (user == null) {
throw new ValidationException("找不到此用户!");
}
//递归查找到类型为公司的ID
//最低级的部门,和最低级的公司
// select id,parent_id,name,code, department_type from xjr_department d where id =214889822920120060;
List<Long> deptIds = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class)
.eq(UserDeptRelation::getUserId, user.getId()))
.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());
//取部门的最小ID作为部门
Long deptId = deptIds.get(0);
Integer departmentType = null;
Long lastDeptId = null;
Long parentDeptId = null;
DepartmentCompanyVo departmentCompany = new DepartmentCompanyVo();
departmentCompany.setUserName(user.getName());
do {
departmentType = departmentService.list(Wrappers.lambdaQuery(Department.class).eq(Department::getId,deptId))
.stream().map(Department::getDepartmentType).collect(Collectors.toList()).get(0);
//如果已经找到了,下面的查询无效
if(!departmentType.equals(1)) {
parentDeptId = departmentService.list(Wrappers.lambdaQuery(Department.class).eq(Department::getId, deptId))
.stream().map(Department::getParentId).collect(Collectors.toList()).get(0);
lastDeptId = departmentService.list(Wrappers.lambdaQuery(Department.class).eq(Department::getId, parentDeptId))
.stream().map(Department::getId).collect(Collectors.toList()).get(0);
deptId = parentDeptId;
}
}
while(!departmentType.equals(1));
//根据lastDeptId得到公司名称
Department companyVo = departmentService.list(Wrappers.lambdaQuery(Department.class).eq(Department::getId,lastDeptId))
.stream().collect(Collectors.toList()).get(0);
//得到部门名称
Department departmentVo = departmentService.list(Wrappers.lambdaQuery(Department.class).eq(Department::getId,deptIds.get(0)))
.stream().collect(Collectors.toList()).get(0);
departmentCompany.setId(deptIds.get(0));
departmentCompany.setName(departmentVo.getName());
departmentCompany.setCompanyId(lastDeptId);
departmentCompany.setCompanyName(companyVo.getName());
departmentCompany.setUserId(id);
return departmentCompany;
}
@Override
public UserInfoVo getCurrentInfo(User user) {
List<Long> roleIds = userRoleRelationService.list(Wrappers.lambdaQuery(UserRoleRelation.class)
.eq(UserRoleRelation::getUserId, user.getId()))
.stream().map(UserRoleRelation::getRoleId).collect(Collectors.toList());
Boolean isAdmin= SecureUtil.isAdmin(roleIds);
List<Long> deptIds = userDeptRelationService.list(Wrappers.lambdaQuery(UserDeptRelation.class)
.eq(UserDeptRelation::getUserId, user.getId()))
.stream().map(UserDeptRelation::getDeptId).collect(Collectors.toList());
List<Long> postIds = userPostRelationService.list(Wrappers.lambdaQuery(UserPostRelation.class)
.eq(UserPostRelation::getUserId, user.getId()))
.stream().map(UserPostRelation::getPostId).collect(Collectors.toList());
List<Long> chargeDeptIds = userChargeDeptService.list(Wrappers.lambdaQuery(UserChargeDept.class)
.eq(UserChargeDept::getUserId,user.getId()))
.stream().map(UserChargeDept::getDeptId).collect(Collectors.toList());
UserInfoVo vo = BeanUtil.toBean(user, UserInfoVo.class);
if (roleIds.size() > 0) {
List<Role> list = roleService.list(Wrappers.lambdaQuery(Role.class).in(Role::getId, roleIds));
List<UserRoleVo> userRoleVoList = BeanUtil.copyToList(list, UserRoleVo.class);
vo.setRoles(userRoleVoList);
}
if (deptIds.size() > 0) {
List<Department> list = departmentService.list(Wrappers.lambdaQuery(Department.class).in(Department::getId, deptIds));
List<UserDeptVo> userDeptVoList = BeanUtil.copyToList(list, UserDeptVo.class);
vo.setDepartments(userDeptVoList);
}
if (postIds.size() > 0) {
List<Post> list = postService.list(Wrappers.lambdaQuery(Post.class).in(Post::getId, postIds));
List<UserPostVo> userPostVoList = BeanUtil.copyToList(list, UserPostVo.class);
vo.setPosts(userPostVoList);
}
if (chargeDeptIds.size() > 0){
List<Department> list = departmentService.list(Wrappers.lambdaQuery(Department.class).in(Department::getId, chargeDeptIds));
List<UserDeptVo> userDeptVoList = BeanUtil.copyToList(list, UserDeptVo.class);
vo.setChargeDepartments(userDeptVoList);
}
//查询有角色的租户
TenantUtil.ignore(true);
List<Long> tenantIds = userRoleRelationService.list(
Wrappers.lambdaQuery(UserRoleRelation.class)
.eq(UserRoleRelation::getUserId, user.getId())
).stream().map(UserRoleRelation::getTenantId).collect(Collectors.toList());
if(tenantIds.size()>0||isAdmin){
List<Tenant> list = tenantClient.getEnableTenantsByIdsFeign(tenantIds, isAdmin);
vo.setTenants(BeanUtil.copyToList(list, UserTenantVo.class));
}
TenantUtil.clear();
return vo;
}
@Override
public void userCache() {
log.info("刷新用户表缓存开始");
List<User> list = list();
redisUtil.set(GlobalConstant.USER_CACHE_KEY, list);
redisUtil.set(GlobalConstant.USER_NAME_CACHE_KEY, list.stream().collect(Collectors.toMap(User::getId, User::getName)));
log.info("刷新用户表缓存结束");
}
@Override
public User getUserByMobile(String mobile) {
return getOne(Wrappers.lambdaQuery(User.class).eq(User::getMobile, mobile), false);
}
@Override
public User getUserByCode(String code) {
return getOne(Wrappers.lambdaQuery(User.class).eq(User::getCode, code), false);
}
}

View File

@ -0,0 +1,150 @@
package com.xjrsoft.organization.service.impl;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.core.config.CommonPropertiesConfig;
import com.xjrsoft.common.core.constant.GlobalConstant;
import com.xjrsoft.organization.dto.WeChatDepartDto;
import com.xjrsoft.organization.dto.WeChatUserDto;
import com.xjrsoft.organization.entity.Department;
import com.xjrsoft.organization.entity.User;
import com.xjrsoft.organization.entity.UserDeptRelation;
import com.xjrsoft.organization.service.IDepartmentService;
import com.xjrsoft.organization.service.IUserDeptRelationService;
import com.xjrsoft.organization.service.IUserService;
import com.xjrsoft.organization.service.WeChatService;
import com.xjrsoft.organization.utils.WeChatUtil;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@AllArgsConstructor
public class WeChatServiceImgl implements WeChatService {
private final IDepartmentService departmentService;
private final IUserService userService;
private final IUserDeptRelationService userDeptRelationService;
private final WeChatUtil weChatUtil;
private final CommonPropertiesConfig propertiesConfig;
@Override
public boolean syncDepartments() {
List<WeChatDepartDto> weChatDeptList = weChatUtil.getWeChatDepartmentList(null);
if (CollectionUtils.isNotEmpty(weChatDeptList)) {
List<Long> weChatDeptIdList = weChatDeptList.stream().map(WeChatDepartDto::getId).collect(Collectors.toList());
List<Department> departmentList = departmentService.list(Wrappers.lambdaQuery(Department.class)
.select(Department::getId, Department::getWechatDeptId)
.in(Department::getWechatDeptId, weChatDeptIdList));
// id映射key企业微信部门idvalue系统部门id
Map<Long, Long> idMap = new HashMap<>(weChatDeptIdList.size());
List<Department> updateDepartmentList = new ArrayList<>(weChatDeptList.size());
for (WeChatDepartDto weChatDepartDto : weChatDeptList) {
boolean exist = false;
Long departmentId = null;
Department updateDepartment = new Department();
for (Department department : departmentList) {
if (weChatDepartDto.getId().equals(department.getWechatDeptId())) {
departmentId = department.getId();
exist = true;
break;
}
}
if (!exist) {
departmentId = IdUtil.getSnowflakeNextId();
}
updateDepartment.setName(weChatDepartDto.getName());
updateDepartment.setCode(weChatDepartDto.getName_en());
updateDepartment.setId(departmentId);
updateDepartment.setWechatDeptId(weChatDepartDto.getId());
updateDepartment.setParentId(weChatDepartDto.getParentid());
updateDepartmentList.add(updateDepartment);
idMap.put(weChatDepartDto.getId(), departmentId);
}
// 处理上级部门
for (Department updateDepartment : updateDepartmentList) {
Long parentId = idMap.get(updateDepartment.getParentId());
updateDepartment.setParentId(parentId == null ? 0L : parentId);
}
return departmentService.saveOrUpdateBatch(updateDepartmentList);
}
return true;
}
@Override
@Transactional
public boolean syncUsers(Long departmentId) {
Department department = departmentService.getById(departmentId);
if (department.getWechatDeptId() == null) {
throw new RuntimeException("请先同步部门!");
}
List<WeChatUserDto> weChatUserList = weChatUtil.getWeChatUsersOfDepartment(department.getWechatDeptId());
if (CollectionUtils.isNotEmpty(weChatUserList)) {
List<String> weChatUserIds = weChatUserList.stream().map(WeChatUserDto::getUserid).collect(Collectors.toList());
List<User> userList = userService.list(Wrappers.lambdaQuery(User.class).in(User::getWechatUserId, weChatUserIds));
List<User> updateUserList = new ArrayList<>(weChatUserList.size());
List<UserDeptRelation> userDeptRelationList = new ArrayList<>(weChatUserList.size());
List<Long> updateUserIdList = new ArrayList<>(weChatUserList.size());
for (WeChatUserDto weChatUserDto : weChatUserList) {
User updateUser = new User();
Long userId = null;
boolean exist = false;
for (User user : userList) {
if (StrUtil.equals(weChatUserDto.getUserid(), user.getWechatUserId())) {
userId = user.getId();
exist = true;
break;
}
}
if (!exist) {
userId = IdUtil.getSnowflakeNextId();
// 默认密码
updateUser.setPassword(SaSecureUtil.md5BySalt(propertiesConfig.getDefaultPassword(), GlobalConstant.SECRET_KEY));
}
// 构建同步的user信息
updateUser.setId(userId);
updateUser.setUserName(weChatUserDto.getUserid());
updateUser.setName(weChatUserDto.getName());
updateUser.setMobile(weChatUserDto.getMobile());
updateUser.setEmail(weChatUserDto.getEmail());
String gender = weChatUserDto.getGender();
if (StrUtil.isNotEmpty(gender)) {
updateUser.setGender(Integer.valueOf(gender));
}
updateUser.setWechatUserId(weChatUserDto.getUserid());
updateUserList.add(updateUser);
// 构建用户部门关系
UserDeptRelation userDeptRelation = new UserDeptRelation();
userDeptRelation.setUserId(userId);
userDeptRelation.setDeptId(departmentId);
userDeptRelationList.add(userDeptRelation);
updateUserIdList.add(userId);
}
userService.saveOrUpdateBatch(updateUserList);
// 删除旧的部门用户关联关系
userDeptRelationService.remove(Wrappers.lambdaQuery(UserDeptRelation.class)
.eq(UserDeptRelation::getDeptId, departmentId)
.in(UserDeptRelation::getUserId, updateUserIdList));
userDeptRelationService.saveBatch(userDeptRelationList);
return true;
} else {
throw new RuntimeException("企业微信没有人员!");
}
}
}

View File

@ -0,0 +1,139 @@
package com.xjrsoft.organization.utils;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiV2DepartmentListsubRequest;
import com.dingtalk.api.request.OapiV2UserListRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
import com.dingtalk.api.response.OapiV2UserListResponse;
import com.taobao.api.ApiException;
import com.xjrsoft.common.core.config.WechatEnterpriseConfig;
import com.xjrsoft.organization.dto.WeChatDepartDto;
import com.xjrsoft.organization.dto.WeChatUserDto;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@Component
@AllArgsConstructor
public class WeChatUtil {
private final WechatEnterpriseConfig wechatEnterpriseConfig;
//获取通讯录或发消息token
public String getWeChatToken() {
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("corpid", wechatEnterpriseConfig.getAppKey());
paramMap.put("corpsecret", wechatEnterpriseConfig.getAppSecret());
String result = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/gettoken", paramMap);
JSONObject jsonObject = JSONObject.parseObject(result);
String token = jsonObject.get("access_token").toString();
return token;
}
//根据所有部门信息
public List<WeChatDepartDto> getWeChatDepartmentList(Long dept_id) {
String token = this.getWeChatToken();
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("access_token", token);
if (dept_id != null) {
paramMap.put("id", dept_id);
}
String result = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/department/list", paramMap);
JSONObject jsonObject = JSONObject.parseObject(result);
if (jsonObject.getLong("errcode") != 0L) {
throw new RuntimeException(jsonObject.getString("errmsg"));
}
Object department = jsonObject.get("department");
List<WeChatDepartDto> weChatDepartDtos = JSONObject.parseArray(department.toString(), WeChatDepartDto.class);
return weChatDepartDtos;
}
//获取部门的所有用户信息
public List<WeChatUserDto> getWeChatUsersOfDepartment(Long departmentId) {
String token = this.getWeChatToken();
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("access_token", token);
paramMap.put("department_id", departmentId);
// paramMap.put("fetch_child", 1);
String result = HttpUtil.get("https://qyapi.weixin.qq.com/cgi-bin/user/list", paramMap);
JSONObject jsonObject = JSONObject.parseObject(result);
if (jsonObject.getLong("errcode") != 0L) {
throw new RuntimeException(jsonObject.getString("errmsg"));
}
Object department = jsonObject.get("userlist");
List<WeChatUserDto> weChatUserDtos = JSONObject.parseArray(department.toString(), WeChatUserDto.class);
return weChatUserDtos;
}
//获取通讯录或发消息token
public String getDingTalkToken(String appKey, String appSecret) {
OapiGettokenResponse response = null;
try {
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(appKey);
request.setAppsecret(appSecret);
request.setHttpMethod("GET");
response = client.execute(request);
} catch (ApiException e) {
throw new RuntimeException("获取钉钉token报错", e);
}
return response.getAccessToken();
}
//根据所有部门信息
public List<OapiV2DepartmentListsubResponse.DeptBaseResponse> getDingTalkDepartmentList(String appKey, String appSecret) {
String token = this.getDingTalkToken(appKey, appSecret);
List<OapiV2DepartmentListsubResponse.DeptBaseResponse> deptBaseResponselist=new ArrayList<>();
try {
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
// req.setDeptId(departmentId);
req.setLanguage("zh_CN");
OapiV2DepartmentListsubResponse response = client.execute(req, token);
if(!response.isSuccess()){
throw new Exception(response.getErrmsg());
}
deptBaseResponselist = response.getResult();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
return deptBaseResponselist;
}
//获取部门的所有用户信息
public List<OapiV2UserListResponse.ListUserResponse> getDingTalkUsersOfDepartment(Long departmentId, String appKey, String appSecret) {
String token = this.getDingTalkToken(appKey, appSecret);
List<OapiV2UserListResponse.ListUserResponse> userResponseList = new ArrayList<>();
try {
Long cursor=0L;
Boolean hasMore=true;
while (hasMore) {
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list");
OapiV2UserListRequest req = new OapiV2UserListRequest();
req.setDeptId(departmentId);
req.setCursor(cursor);
req.setSize(100L);
req.setOrderField("modify_desc");
req.setContainAccessLimit(false);
req.setLanguage("zh_CN");
OapiV2UserListResponse rsp = client.execute(req, token);
userResponseList.addAll(rsp.getResult().getList());
hasMore=rsp.getResult().getHasMore();
cursor=rsp.getResult().getNextCursor();
}
} catch (ApiException e) {
throw new RuntimeException(e.getMessage(), e);
}
return userResponseList;
}
}

View File

@ -0,0 +1,3 @@
spring:
profiles:
active: public

View File

@ -0,0 +1,78 @@
server:
port: 3002
spring:
application:
name: organization-service
main:
allow-bean-definition-overriding: true
autoconfigure:
#自动化配置 例外处理
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
datasource:
type: com.alibaba.druid.pool.DruidDataSource
dynamic:
primary: master
datasource:
master:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://new-energy-mysqlt.itc.gdyd.com:3307/fcd2-msat-init?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
username: learun4dev
password: ABcd1234@
cloud:
nacos: #nacos监控
discovery:
server-addr: 10.0.252.1:8848
namespace: ITC
group: DNE
username: nacos
password: ABcd1234@
config:
server-addr: 10.0.252.1:8848 # nacos 配置中心地址
namespace: ITC
group: DNE
username: nacos
password: ABcd1234@
file-extension: yml # 指定格式 xjrsoft-demo-service-dev.yml
extension-configs:
- data-id: global-config.yml #导入全局配置
refresh: true
group: DNE
- data-id: mybatis-plus-config.yml #导入mybatisplus 配置
refresh: true
group: DNE
- data-id: sa-token-client-config.yml #导入sa-token配置
refresh: true
group: DNE
- data-id: redis-config.yml #导入redis配置
refresh: true
group: DNE
- data-id: seata-config.yml #导入seata配置
refresh: true
group: DNE
# - data-id: feigh-config.yml #导入feigh配置
# refresh: true
# group: DNE
sentinel:
transport:
dashboard: localhost:8080 #sentinel dashboard 地址
port: 8719 #默认端口, 如果 被占用,会一直+1 直到未被占用为止
springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
show-extensions: true
api-docs:
path: /organization/v3/api-docs
group-configs:
- group: 'default'
paths-to-match: '/organization/**'
packages-to-scan: com.xjrsoft.organization
default-flat-param-object: false

View File

@ -0,0 +1,31 @@
{
"user": {
"user_name": "admin",
"name": "管理员",
"code": "10000",
"nickName": "管理员",
"password": "000000",
"gender": "1",
"mobile": "15555555555"},
"role": {
"name": "超级管理员",
"code": "ADMIN",
"remark": ""},
"post": {
"name": "默认岗位",
"code": "default",
"parentId": 0,
"remark": "",
"sortCode": 1},
"department": {
"name": "默认部门",
"code": "default",
"parentId": "0",
"mobile": "",
"email": "",
"website": "",
"address": "",
"sortCode": 1,
"remark": ""
}
}