package com.bocloud.sms.service; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.fastjson.JSONObject; import com.bocloud.cmp.boot.model.BocloudStatus; import com.bocloud.sms.entity.*; import com.bocloud.sms.interfaces.UserService; import com.bocloud.sms.model.*; import com.bocloud.sms.repository.*; import com.bocloud.sms.service.utils.ExportUtil; import com.bocloud.sms.service.utils.ImportExcelUtil; import com.bocloud.sms.utils.FavoriteComparator; import com.google.common.collect.Lists; import com.megatron.common.encrypt.AESEncryptor; import com.megatron.common.encrypt.Encryptor; import com.megatron.common.encrypt.SHAEncryptor; import com.megatron.common.enums.BaseStatus; import com.megatron.common.exception.InternalServerException; import com.megatron.common.model.*; import com.megatron.common.model.RequestContext.Catalog; import com.megatron.common.utils.Common; import com.megatron.common.utils.ListTool; import com.megatron.common.utils.MapTools; import com.megatron.common.utils.Tokens; import com.megatron.entity.bean.GenericEntity; import com.megatron.framework.core.CurrentService; import com.megatron.framework.lock.AutoCloseLock; import com.megatron.framework.lock.LockFactory; import io.jsonwebtoken.SignatureAlgorithm; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.*; import org.springframework.beans.BeanUtils; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collectors; import static com.bocloud.sms.service.utils.ExportUtil.exportExcel; import static com.bocloud.sms.service.utils.ExportUtil.getCellStringValue; /** * 用户抽象Service接口实现类 * * @author tyl */ @Service @Slf4j @RequiredArgsConstructor public class UserServiceImpl implements UserService { private final CurrentService currentService; private final StringRedisTemplate redisTemplate; private final LockFactory lockFactory; private final UserRepository userRepository; private final RoleRepository roleRepository; private final TenantRepository tenantRepository; private final PermissionRepository permissionRepository; private final ProjectRepository projectRepository; private final AccountSecurityRepository securityRepository; private final DepartmentRepository departmentRepository; private final ThreadPoolTaskExecutor taskExecutor; private final UserProjectRepository userProjectRepository; private final LoginRecordRepository loginRecordRepository; private final UserRoleRepository userRoleRepository; private final ManagerRoleRepository managerRoleRepository; private final FavoriteRepository favoriteRepository; private final CloudServiceBeanRepository cloudServiceBeanRepository; private final ApiPermissionRepository apiPermissionRepository; /** * 分页查询用户列表 * * @param pager 分页对象 * @param requestContext 请求对象 * @return */ @Override public GeneralResult> list(Pager pager, RequestContext requestContext) { List params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>()); HashMap map = new HashMap<>(4); map.put("gmtCreate", Common.ONE); map.put("id", Common.ONE); Map sorter = !pager.getSorter().isEmpty() ? pager.getSorter() : map; List list; int total; GridBean gridBean; Long roleId = null; // 有参数时判断是否有租户id for (Param next : params) { Map paramMap = next.getParam(); if (paramMap.containsKey("projectId")) { Integer projectId = (Integer) paramMap.get("projectId"); Param param = new Param(MapTools.simpleMap("projectId", projectId), Sign.EQ); params.add(param); total = userRepository.projectUserCount(params); list = userRepository.listProjectUser(pager.getPage(), pager.getRows(), params, sorter); for (User user : list) { Department department = departmentRepository.query(user.getDepartId()); if (department != null) { user.setDepartmentName(department.getName()); } } gridBean = new GridBean<>(pager.getPage(), pager.getRows(), total, list); return new GeneralResult<>(true, gridBean, "查询项目用户成功"); } if (paramMap.containsKey("roleId")) { roleId = Long.valueOf(paramMap.get("roleId").toString()); paramMap.remove("roleId"); } } // 无参数(租户请求获取用户列表),把requestContext里的租户Id作为参数 if (!Catalog.Manager.equals(requestContext.getCatalog())) { Map tenantMap = MapTools.simpleMap("tenantId", requestContext.getTenant()); Param param = new Param(tenantMap, Sign.EQ); params.add(param); } total = userRepository.count(params, roleId); Map departmentMap = departmentRepository.listAll().stream().collect(Collectors.toMap(Department::getId, Function.identity())); if (pager.getSimple()) { List beans = userRepository.list(params, sorter, roleId); gridBean = new GridBean(1, 1, total, beans); } else { list = userRepository.list(pager.getPage(), pager.getRows(), params, sorter, roleId); list.forEach(user -> { try { List roles = roleRepository.listByUser(user.getId()).stream().map(GenericEntity::getName) .collect(Collectors.toList()); user.setRoleNames(roles); Department department = departmentMap.get(user.getDepartId()); if (department != null) { user.setDepartmentName(department.getName()); List deptIdTree = getDeptIdTree(departmentMap, department); Collections.reverse(deptIdTree); String string = JSONObject.toJSONString(deptIdTree); user.setDepartIds(string); } else { user.setDepartIds("[]"); } } catch (Exception e) { log.error("list user {} role names error!", user.getAccount(), e); } }); gridBean = new GridBean<>(pager.getPage(), pager.getRows(), total, list); } return new GeneralResult<>(true, gridBean, "查询用户成功"); } private List getDeptIdTree(Map departmentMap, Department department) { List result = new ArrayList<>(); result.add(department.getId()); Department parent = departmentMap.get(department.getParentId()); if (parent != null) { List deptIdTree = getDeptIdTree(departmentMap, parent); result.addAll(deptIdTree); } return result; } /** * 用户登录 * * @param account 账号 * @param password 密码 * @param sessionId 会话id * @param requestIp 请求ip * @return * @throws InternalServerException */ @SneakyThrows @Override @Transactional(rollbackFor = InternalServerException.class) public GeneralResult> login(String account, String password, String sessionId, String requestIp, Boolean isManager) throws InternalServerException { log.info("UserService接受到调用请求"); long start; LoginRecord loginRecord = new LoginRecord(); loginRecord.setRequestIp(requestIp); String currentServiceHost = currentService.getService().getHost(); log.info("currentServiceHost={}", currentServiceHost); loginRecord.setResponseIp(currentServiceHost); loginRecord.setAccount(account); loginRecord.setCategory(LoginRecord.Category.User); loginRecord.setGmtCreate(new Date()); // 判断用户是否存在 User user; AccountSecurity security; log.info("Before Try"); try { log.info("Start Try"); start = System.currentTimeMillis(); user = userRepository.getByAccount(account); log.info("查询用户信息耗时{}ms", System.currentTimeMillis() - start); // 注释掉,允许普通用户也可登录 /*if (isManager) { if (!user.getIsManager()) { handleLoginLog(false, "该账号没有管理权限", loginRecord); return new GeneralResult<>(false, "该账号没有管理权限"); } }*/ if (null == user) { log.warn("User is null"); handleLoginLog(false, "账号或密码错误", loginRecord); return new GeneralResult<>(false, "账号或密码错误"); } start = System.currentTimeMillis(); security = securityRepository.getByTarget(user.getId(), Catalog.User); log.info("查询用户安全耗时{}ms", System.currentTimeMillis() - start); if (null == security) { log.warn("Security is null"); handleLoginLog(false, "账号或密码错误", loginRecord); return new GeneralResult<>(false, "账号或密码错误"); } // 对前端传过来的密码进行解密 Encryptor encryptor = new AESEncryptor(); password = encryptor.decrypt(password.trim(), null); if (!StringUtils.hasText(password)) { handleLoginLog(false, "账号或密码错误", loginRecord); return new GeneralResult<>(false, "账号或密码错误"); } // 密码加密 encryptor = new SHAEncryptor(); String encryptString = encryptor.encrypt(password, security.getSalt()); if (null == encryptString || !encryptString.equals(user.getPassword())) { log.warn("Wrong user account or password"); handleLoginLog(false, "账号或密码错误", loginRecord); return new GeneralResult<>(false, "账号或密码错误"); } } catch (Exception e) { handleLoginLog(false, "账号或密码错误", loginRecord); log.error("Get User fail by account:", e); return new GeneralResult<>(false, "账号或密码错误"); } // 更新用户登录状态 try { // 用户状态校验 if (user.getStatus().equals(BaseStatus.ABNORMAL.name())) { handleLoginLog(false, "账号已冻结", loginRecord); return new GeneralResult<>(false, "冻结用户无法登录"); } if (user.getStatus().equals(BocloudStatus.Basic.EXPIRED.name())) { handleLoginLog(false, "账号已过期", loginRecord); return new GeneralResult<>(false, "账号已过期,无法登录"); } start = System.currentTimeMillis(); Tenant tenant = tenantRepository.query(user.getTenantId()); log.info("查询用户租户耗时{}ms", System.currentTimeMillis() - start); if (tenant != null && tenant.getStatus().equals(BocloudStatus.Basic.EXPIRED.name())) { handleLoginLog(false, "所属租户账号已过期", loginRecord); return new GeneralResult<>(false, "所属租户账号已过期,无法登录,请联系管理员!"); } if (null == user.getTenantId() || 0L == user.getTenantId()) { if (!isManager) { handleLoginLog(false, "用户没有所属租户,不能登录该系统", loginRecord); return new GeneralResult<>(false, "用户没有所属租户,不能登录该系统!"); } } user.setLoginStatus(true); user.setSessionId(sessionId); Date lastLoginDate = user.getLastLoginDate(); user.setLastLoginDate(new Date()); start = System.currentTimeMillis(); userRepository.update(user); log.info("更新用户信息耗时{}ms", System.currentTimeMillis() - start); user.setLastLoginDate(lastLoginDate); } catch (Exception e) { handleLoginLog(false, "更新用户登录状态失败", loginRecord); log.error("Update user login status fail:", e); throw new InternalServerException("更新用户登录状态失败", e, e.getMessage()); } try { // 构建返回数据 isManager = Optional.ofNullable(isManager).orElse(false); start = System.currentTimeMillis(); if (isManager) { // 刷新权限缓存 flushRoleApiPermission(true, user.getId()); } else { flushRoleApiPermission(false, user.getTenantId()); } log.info("flushRoleApiPermission耗时{}ms", System.currentTimeMillis() - start); Map map = getResultMap(isManager, user, security); if (map != null) { handleLoginLog(true, "用户登录成功", loginRecord); return new GeneralResult<>(true, map, "用户登录成功"); } else { handleLoginLog(true, "用户登录失败", loginRecord); return new GeneralResult<>(false, "用户登录失败"); } } catch (Exception e) { handleLoginLog(true, "用户登录失败:" + e.getMessage(), loginRecord); return new GeneralResult<>(false, "用户登录失败"); } } private Map getResultMap(Boolean isManager, User user, AccountSecurity security) { try { Map map; if (isManager) { map = MapTools.simpleMap("manager", user); map.put(Common.API_KEY, security.getApiKey()); map.put("accountCategory", Catalog.Manager.name()); String token = buildToken(true, user, security); map.put(Common.TOKEN, token); } else { map = MapTools.simpleMap(Common.USER, user); map.put(Common.API_KEY, security.getApiKey()); map.put("accountCategory", Catalog.User.name()); String token = buildToken(false, user, security); map.put(Common.TOKEN, token); } return map; } catch (Exception e) { log.error("get login result error,", e); return null; } } private String buildToken(Boolean isManager, User user, AccountSecurity security) { long start; // 构建token Map header = MapTools.simpleMap("alg", SignatureAlgorithm.HS256.getValue()); header.put("typ", "JWT"); Map payload = MapTools.simpleMap(Common.ACCOUNT, user.getAccount()); payload.put(Common.API_KEY, security.getApiKey()); payload.put(Common.UUID, user.getId()); payload.put(Common.NAME, user.getName()); Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.MONTH, 3); if (isManager) { payload.put("catalog", Catalog.Manager.name()); } else { payload.put("catalog", Catalog.User.name()); payload.put(Common.TENANTID, user.getTenantId()); payload.put("tenantName", user.getTenantName()); payload.put("tenantAccount", user.getTenantAccount()); } // 加密jwt生成token并存入session和cookie String token = Tokens.generate(header, payload, calendar.getTime()); String tokenKey = isManager ? "token_" + Catalog.Manager.name() + "_" + user.getId() : "token_" + Catalog.User.name() + "_" + user.getId(); start = System.currentTimeMillis(); this.redisTemplate.delete(tokenKey + "_o"); log.info("删除Redis的Token耗时{}ms", System.currentTimeMillis() - start); HashMap tokenJson = new HashMap<>(8); tokenJson.put("token", token); tokenJson.put("refreshTime", LocalDateTime.now().plusMinutes(10).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); start = System.currentTimeMillis(); redisTemplate.opsForHash().putAll(tokenKey + "_n", tokenJson); this.redisTemplate.expire(tokenKey + "_n", 30L, TimeUnit.MINUTES); log.info("写入Redis的Token耗时{}ms", System.currentTimeMillis() - start); return token; } private void flushRoleApiPermission(Boolean isManager, Long id) { List roleIds; // 管理端API权限 if (isManager) { roleIds = roleRepository.listManagerApiRole(id).stream().map(Role::getId).collect(Collectors.toList()); } else { // 自服务API权限 roleIds = roleRepository.getTenantUserRole().stream().map(Role::getId).collect(Collectors.toList()); } List apiPermissions = apiPermissionRepository.listRoleApiPermission(roleIds); Map> rolePermissionMap = apiPermissions.stream().collect(Collectors.groupingBy(ApiPermission::getRoleId)); for (Map.Entry> rolePermissionEntry : rolePermissionMap.entrySet()) { Long roleId = rolePermissionEntry.getKey(); Map> permissionMap = rolePermissionEntry.getValue().stream().collect(Collectors.groupingBy(ApiPermission::getModule)); for (Map.Entry> permission : permissionMap.entrySet()) { String module = permission.getKey(); List patterns = permission.getValue().stream() .map(s -> new String(Base64.getDecoder().decode(s.getPattern()))).collect(Collectors.toList()); if (!patterns.isEmpty()) { redisTemplate.opsForHash().put("api_permission_" + roleId, module, JSONObject.toJSONString(patterns)); } } } } /** * 保存登录日志 * * @param status 登录状态 * @param detail 日志详情 * @param record 日志对象 */ private void handleLoginLog(boolean status, String detail, LoginRecord record) { record.setStatus(status); record.setDetail(detail); try { this.save(record); } catch (Exception e) { log.error("save login record error"); } } @Override @Transactional public Result create(UserBean userBean, RequestContext requestContext) { User user = new User(); BeanUtils.copyProperties(userBean, user); Assert.notNull(user, "user can't be null"); user.setCreatorId(requestContext.getTarget()); // 初始化密码 String salt = UUID.randomUUID().toString(); Encryptor encryptor = new SHAEncryptor(); // 查询创建者的租户信息并赋值给所创建的用户 if (Catalog.Tenant == requestContext.getCatalog()) { user.setTenantId(requestContext.getTenant()); } else if (Catalog.Manager == requestContext.getCatalog()) { user.setTenantId(null == userBean.getTenantId() ? 0L : userBean.getTenantId()); } else { user.setTenantId(0L); } User existUser = userRepository.getByAccount(user.getAccount()); Assert.isNull(existUser, "该账号已存在"); User existEmailUser = userRepository.getByEmail(user.getEmail()); Assert.isNull(existEmailUser, "该邮箱已被注册"); String password = encryptor.encrypt(new AESEncryptor().decrypt(user.getPassword().trim(), null), salt); user.setPassword(password); // 关键信息去空 user.setAccount(user.getAccount().trim()); user.setName(user.getName().trim()); user.setStatus(BaseStatus.NORMAL.name()); user.setLoginStatus(false); user.setLastPwdModifyDate(new Date()); user.setOrigin("SYSTEM"); userRepository.save(user); String account = user.getAccount(); User cacheUser = userRepository.getByAccount(account); redisTemplate.opsForValue().set(Catalog.User.name() + "_" + cacheUser.getId(), account); redisTemplate.opsForValue().set(Catalog.User.name() + "_Name_" + cacheUser.getId(), cacheUser.getName()); // 构建用户随机数对象 AccountSecurity security = new AccountSecurity(); String data = Long.toString(System.currentTimeMillis()); String apiKey = encryptor.encrypt(data, Common.API_KEY); String secKey = encryptor.encrypt(data, Common.SEC_KEY); security.setTargetId(user.getId()); security.setCategory(AccountSecurity.Category.User); security.setSalt(salt); security.setApiKey(apiKey); security.setSecKey(secKey); security.setTenantId(user.getTenantId()); securityRepository.baseSave(security); return new Result(true, "添加用户成功"); } @Override @Transactional public Result modify(Long id, UserBean userBean, RequestContext requestContext) { Assert.notNull(userBean, "user bean can't be null"); userBean.setName(userBean.getName().trim()); if (userBean.getTenantId() == null) { userBean.setTenantId(0L); } String path = User.class.getSimpleName() + "_" + id; try (AutoCloseLock lock = lockFactory.getACLock(path)) { Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时"); Assert.isTrue(id.equals(userBean.getId()), "非法请求"); if (Catalog.User == requestContext.getCatalog()) { Assert.isTrue(id.equals(requestContext.getTarget()), "非法请求"); } User user = userRepository.query(id); if (Catalog.Tenant == requestContext.getCatalog()) { Assert.isTrue(requestContext.getTenant().equals(user.getTenantId()), "非法请求"); } Assert.notNull(user, "用户不存在"); if (!userBean.getEmail().equals(user.getEmail())) { Tenant existName = tenantRepository.getByEmail(userBean.getEmail()); Assert.isNull(existName, "该邮箱已被注册"); } AccountSecurity security = null; if (userBean.getTenantId() == null || !userBean.getTenantId().equals(user.getTenantId())) { security = securityRepository.getByTarget(id, Catalog.User); security.setTenantId(userBean.getTenantId()); } // 判断是否修改有效期 long l = user.getExpiredDate() == null ? 0L : user.getExpiredDate().getTime(); if (userBean.getExpiredDate() != null && userBean.getExpiredDate().getTime() != l) { if (!BocloudStatus.Basic.NORMAL.name().equals(user.getStatus())) { user.setStatus(BocloudStatus.Basic.NORMAL.name()); } } BeanUtils.copyProperties(userBean, user, "password"); user.setMenderId(requestContext.getTarget()); boolean result = userRepository.update(user); // 缓存更新用户姓名 redisTemplate.opsForValue().set(Catalog.User.name() + "_Name_" + user.getId(), user.getName()); if (result) { if (security != null) { securityRepository.update(security); } return new Result(true, "修改成功"); } return new Result(false, "修改失败"); } } /** * 删除用户信息 * * @param id 用户id * @param requestContext 请求对象 * @return */ @Override @Transactional public Result remove(Long id, RequestContext requestContext) { String path = User.class.getSimpleName() + "_" + id; try (AutoCloseLock lock = lockFactory.getACLock(path)) { Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时"); if (RequestContext.Catalog.User == requestContext.getCatalog()) { Assert.isTrue(id.equals(requestContext.getTarget()), "非法请求"); } User user = userRepository.query(id); if (Catalog.Tenant == requestContext.getCatalog()) { Assert.isTrue(requestContext.getTenant().equals(user.getTenantId()), "非法请求"); } Assert.notNull(user, "用户不存在!"); // 删除用户角色 userRoleRepository.unBindUserRole(id); // 删除用户收藏数据 favoriteRepository.cancelFavorite(null, id, requestContext.getCatalog().name()); userRepository.delete(id, requestContext.getTarget()); // 删除用户账号安全表 securityRepository.delete(id, Catalog.User); // 删除用户项目关联 this.userProjectRepository.unBindProject(id); // 删除用户账号信息缓存 redisTemplate.delete(Catalog.User.name() + "_" + user.getId()); // redisTemplate.delete(Catalog.User.name() + "_Name_" + user.getId()); // 删除用户token String tokenKey = Common.TOKEN + "_" + Catalog.User.name() + "_" + id; redisTemplate.delete(tokenKey + "_n"); redisTemplate.delete(tokenKey + "_o"); return new Result(true, "删除用户成功"); } } @Override public Result updateStatus(Long id, ActionModel.Action action, RequestContext requestContext) throws InternalServerException { String path = User.class.getSimpleName() + "_" + id; try (AutoCloseLock lock = lockFactory.getACLock(path)) { Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时"); User user = userRepository.query(id); Assert.notNull(user, "用户信息不存在!"); Long menderId = requestContext.getTarget(); switch (action) { case active: Assert.isTrue(!id.equals(menderId), "用户不能冻结当前登录的用户。"); return userRepository.active(id, menderId) ? new Result(true, "解冻用户成功") : new Result(false, "解冻用户失败"); case lock: if (userRepository.lock(id, menderId)) { // 删除用户token String tokenKey = Common.TOKEN + "_" + Catalog.User.name() + "_" + id; redisTemplate.delete(tokenKey + "_n"); redisTemplate.delete(tokenKey + "_o"); return new Result(true, "冻结用户成功"); } else { return new Result(false, "冻结用户失败"); } default: break; } return new Result(false, "不支持的操作"); } catch (Exception e) { log.error("update user status fail:", e); return GeneralResult.FAILED("修改用户状态失败," + e.getMessage()); } } @Override public Result batchLock(List ids, RequestContext context) { try { boolean result = userRepository.batchUpdateStatus(ids, context.getTarget(), BaseStatus.ABNORMAL); for (Long id : ids) { String tokenKey = Common.TOKEN + "_" + Catalog.User.name() + "_" + id; redisTemplate.delete(tokenKey + "_n"); redisTemplate.delete(tokenKey + "_o"); } return result ? new Result(true, "批量冻结用户成功") : new Result(false, "批量冻结用户失败"); } catch (Exception e) { log.error("batch locked users fail:", e); return new Result(false, "批量冻结用户失败," + e.getMessage()); } } @Override public Result batchActive(List ids, RequestContext context) { try { boolean result = userRepository.batchUpdateStatus(ids, context.getTarget(), BaseStatus.NORMAL); return result ? new Result(true, "批量解冻用户成功") : new Result(false, "批量解冻用户失败"); } catch (Exception e) { log.error("batch active users fail:", e); return new Result(false, "批量解冻用户失败," + e.getMessage()); } } @Transactional @Override public Result batchRemove(List ids, RequestContext context) { for (Long id : ids) { this.remove(id, context); } return new Result(true, "用戶批量刪除成功"); } @Override @Transactional public Result changePwd(Long id, String oldPassword, String password, RequestContext requestContext) { String path = User.class.getSimpleName() + "_" + id; try (AutoCloseLock lock = lockFactory.getACLock(path)) { Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时"); Assert.isTrue(id.equals(requestContext.getTarget()), "非法请求"); User user = userRepository.query(id); Assert.notNull(user, "用户信息不存在!"); String salt = UUID.randomUUID().toString(); // 加密 SHAEncryptor sha = new SHAEncryptor(); Encryptor encryptor = new AESEncryptor(); // 对原密码解密,并校验。 oldPassword = encryptor.decrypt(oldPassword.trim(), null); Assert.isTrue(StringUtils.hasText(oldPassword), "旧密码不存在"); Result checkResult = this.check(id, oldPassword); if (checkResult.isFailed()) { return checkResult; } // 对前端传过来的密码进行解密 password = encryptor.decrypt(password.trim(), null); Assert.isTrue(StringUtils.hasText(password), "新密码不存在。"); String encrypt = sha.encrypt(password, salt); user.setPassword(encrypt); user.setLastPwdModifyDate(new Date()); userRepository.update(user); // 准备随机数数据 AccountSecurity security = securityRepository.getByTarget(user.getId(), Catalog.User); security.setSalt(salt); // 更新随机数 securityRepository.update(security); return new Result(true, "修改密码成功"); } } @Override public Result resetPwd(Long id, String password, RequestContext requestContext) { String path = User.class.getSimpleName() + "_" + id; try (AutoCloseLock lock = lockFactory.getACLock(path)) { Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时"); String salt = UUID.randomUUID().toString(); SHAEncryptor sha = new SHAEncryptor(); User user = userRepository.query(id); Assert.notNull(user, "用户息不存在!"); user.setPassword(sha.encrypt(new AESEncryptor().decrypt(password.trim(), null), salt)); user.setMenderId(requestContext.getTarget()); user.setLastPwdModifyDate(new Date()); userRepository.update(user); // 准备随机数数据 AccountSecurity userSecurity = securityRepository.getByTarget(user.getId(), Catalog.User); userSecurity.setSalt(salt); // 更新随机数 securityRepository.update(userSecurity); return new Result(true, "重置密码成功"); } catch (Exception e) { log.error("reset user password fail:", e); return GeneralResult.FAILED("重置密码失败," + e.getMessage()); } } @Override @Transactional(rollbackFor = Exception.class) public Result accredit(Long id, List roleIds, RequestContext requestContext) { String path = User.class.getSimpleName() + "_" + id; try (AutoCloseLock lock = lockFactory.getACLock(path)) { Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时"); User user = userRepository.query(id); Assert.notNull(user, "用户信息不存在"); if (requestContext.getCatalog().equals(Catalog.Manager)) { List roles = roleIds.stream().map(role -> new ManagerRole(id, role)).collect(Collectors.toList()); // 解绑管理员下角色 managerRoleRepository.unBindManagerRole(id); if (!roles.isEmpty()) { this.batchSaveManagerRoles(roles); } } else { List roles = roleIds.stream().map(role -> new UserRole(id, role)).collect(Collectors.toList()); // 解绑用户角色 userRoleRepository.unBindUserRole(id); if (!roles.isEmpty()) { this.batchSaveUserRoles(roles); } } user.setMenderId(requestContext.getTarget()); userRepository.update(user); return new Result(true, "用户角色授权成功"); } catch (Exception e) { log.error("accredit user role fail:", e); throw new InternalServerException("授权用户角色失败," + e.getMessage(), e, e.getMessage()); } } /** * 批量绑定用户角色 * * @param roles 用户角色集合 */ @Transactional public void batchSaveUserRoles(List roles) { for (UserRole userRole : roles) { userRoleRepository.save(userRole); } } /** * 批量保存管理员角色 * * @param roles 角色集合 */ private void batchSaveManagerRoles(List roles) { // userRepository.bindManagerRoles(roles); for (ManagerRole managerRole : roles) { managerRoleRepository.save(managerRole); } } @Override public GeneralResult detail(Long id) { User user = userRepository.query(id); Assert.notNull(user, "用户不存在。"); if (null != user.getTenantId() && 0L != user.getTenantId()) { Tenant tenant = tenantRepository.query(user.getTenantId()); if (null != tenant) { user.setTenantName(tenant.getName()); } } // 查询用户关联的项目 List userProjects = userProjectRepository.listUserProjectByUserId(id); List projectIds = Lists.newArrayList(); if (!ListTool.isEmpty(userProjects)) { for (UserProject userProject : userProjects) { projectIds.add(userProject.getProjectId()); } } user.setProjectIds(projectIds); List roleNames = new ArrayList<>(); List roles = roleRepository.listByUser(user.getId()); if (!roles.isEmpty()) { for (Role role : roles) { roleNames.add(role.getName()); } } //给用户设置管理端的角色名 List managerRoles = roleRepository.listByManager(user.getId()); if (!ListTool.isEmpty(managerRoles)) { for (Role role : managerRoles) { if(!roleNames.contains(role.getName())){ roleNames.add(role.getName()); } } } // 给用户设置角色名 user.setRoleNames(roleNames); Department department = departmentRepository.query(user.getDepartId()); if (department != null) { user.setDepartmentName(department.getName()); } return new GeneralResult<>(true, user, "查询用户详情成功"); } /** * 获取用户安全密钥 * * @param apiKey api密钥 * @return */ @Override public GeneralResult getAccountSecurity(String apiKey) { try { AccountSecurity security = securityRepository.getByApiKey(apiKey, Catalog.User); return new GeneralResult<>(true, security, "获取安全密钥成功"); } catch (Exception e) { log.error("get secKey fail:", e); return new GeneralResult<>(false, "获取安全密钥失败"); } } /** * 校验用户密码 * * @param id 用户id * @param password 密码 * @return */ @Override public Result check(Long id, String password) { try { User user = userRepository.query(id); AccountSecurity security = securityRepository.getByTarget(id, Catalog.User); Assert.isTrue(null != user && null != security, "原密码验证失败。"); SHAEncryptor sha = new SHAEncryptor(); String encrypt = sha.encrypt(password, security.getSalt()); Assert.isTrue(null != encrypt && encrypt.equals(user.getPassword()), "原密码验证失败"); return new Result(true, "原密码正确"); } catch (Exception e) { log.error("old password not correct:", e); return new Result(false, e.getMessage()); } } /** * 根据项目id获取用户项目关联 * * @param projectId * @param requestContext * @return */ @Override public GeneralResult> listProjectUser(Long projectId, RequestContext requestContext) { try { Project project = projectRepository.query(projectId); Assert.notNull(project, "项目信息不存在"); List userList; if (requestContext.getCatalog().equals(Catalog.Manager)) { userList = userRepository.list(); } else { userList = userRepository.listByTenant(project.getTenantId()); } List userProjects = userProjectRepository.listUserProject(projectId); List managerIds = new ArrayList<>(); List userIds = new ArrayList<>(); for (UserProject userProject : userProjects) { if (userProject.getProjectAdmin()) { managerIds.add(userProject.getUserId()); } else { userIds.add(userProject.getUserId()); } } for (User user : userList) { if (managerIds.contains(user.getId())) { user.setChecked(true); user.setProjectManager(true); } else if (userIds.contains(user.getId())) { user.setChecked(true); user.setProjectManager(false); } else { user.setChecked(false); user.setProjectManager(false); } } return new GeneralResult<>(true, userList, "查询成功"); } catch (Exception e) { log.error("Get error message:", e); return new GeneralResult<>(false, "查询失败:" + e.getMessage()); } } @Override public GeneralResult> listProjectManager(Long id) { try { List projectManagers = userRepository.getProjectManagers(id); return new GeneralResult<>(true, projectManagers, "查询成功"); } catch (Exception e) { log.error("list project managers message:", e); return new GeneralResult<>(false, "查询失败:" + e.getMessage()); } } /** * 校验用户状态 * * @param id 用户id * @param token token * @return */ @Override public Result checkUser(Long id, String token) { try { User user = userRepository.query(id); if (null != user) { if (BaseStatus.ABNORMAL.name().equals(user.getStatus())) { return new Result(false, "该用户已被冻结,请联系管理员进行解冻!"); } if ("LOGOUT".equals(user.getStatus())) { return new Result(false, "该用户已被注销!"); } String tokenKey = Common.TOKEN + "_" + Catalog.User + "_" + id; String newTokenCache = this.redisTemplate.opsForValue().get(tokenKey + "_n"); if (!token.equals(newTokenCache)) { return GeneralResult.FAILED("此用户已在别处登录!"); } return new Result(true, ""); } else { return new Result(false, "查询用户失败!"); } } catch (Exception e) { log.error("check user login fail:", e); return new Result(false, "检查用户登录失败!"); } } /** * 用户退出登录 * * @param id 用户id * @return * @throws InternalServerException */ @Override @Transactional(rollbackFor = InternalServerException.class) public Result logout(Long id) throws InternalServerException { try { User user = userRepository.query(id); if (user != null) { user.setLoginStatus(false); user.setSessionId(""); userRepository.update(user); String tokenKey = Common.TOKEN + "_" + Catalog.User.name() + "_" + id; redisTemplate.delete(tokenKey + "_n"); redisTemplate.delete(tokenKey + "_o"); String managerTokenKey = Common.TOKEN + "_" + Catalog.Manager.name() + "_" + id; redisTemplate.delete(managerTokenKey + "_n"); redisTemplate.delete(managerTokenKey + "_o"); } return new Result(true, "用户退出成功!"); } catch (Exception e) { log.error("get user fail:", e); throw new InternalServerException("获取用户信息失败!", e, e.getMessage()); } } /** * 查询用户角色列表 * * @param id 用户id * @param requestContext 请求对象 * @return */ @Override public GeneralResult> listRoles(Long id, String condition, RequestContext requestContext) { try { List roles; if (requestContext.getCatalog().equals(Catalog.Manager)) { if (null != condition) { if ("cmdbQueryRoles".equalsIgnoreCase(condition)) { roles = this.roleRepository.listByManager(id); return new GeneralResult<>(true, roles, "查询成功"); } } List list = this.roleRepository.listByManager(id); roles = this.roleRepository.listManagerRole(); if (null == roles || roles.isEmpty()) { return new GeneralResult<>(false, "查询所有角色失败!"); } // 构建返回对象,设置check值 for (Role role : roles) { if (null != list && !list.isEmpty()) { for (Role r : list) { // 管理员拥有的角色,check设置为true(前端显示用) if (role.getId().equals(r.getId())) { role.setChecked(true); } } } } } else { roles = this.roleRepository.listByUser(id); } return new GeneralResult<>(true, roles, "查询成功"); } catch (Exception e) { log.error("list permission by tenant id:", e); return new GeneralResult<>(false, "查询失败", null, null); } } /** * 根据账号锁定用户 * * @param account 用户账号 * @return * @throws InternalServerException */ @Override @Transactional(rollbackFor = InternalServerException.class) public Result lockByAccount(String account) throws InternalServerException { String path; boolean result; User user; try { user = userRepository.getByAccount(account); Assert.notNull(user, "user data don't exists"); } catch (Exception e) { log.error("get user data fail:", e); return new Result(false, "获取用户信息失败"); } path = User.class.getSimpleName() + "_" + user.getId(); try (AutoCloseLock lock = lockFactory.getACLock(path)) { Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时"); result = userRepository.lock(user.getId(), 1L); return result ? new Result(true, "冻结用户成功") : new Result(false, "冻结用户失败"); } catch (Exception e) { log.error("freeze user fail:", e); throw new InternalServerException("冻结用户失败", e, e.getMessage()); } } /** * 保存用户登录数据 * * @param * @return */ @Override @Transactional(rollbackFor = InternalServerException.class) public Result save(LoginRecord loginRecord) throws InternalServerException { String path = LoginRecord.class.getSimpleName() + "_" + loginRecord.getAccount(); try (AutoCloseLock lock = lockFactory.getACLock(path)) { Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时"); long start = System.currentTimeMillis(); loginRecordRepository.save(loginRecord); log.info("保存登录记录耗时{}ms", System.currentTimeMillis() - start); return new Result(true, "租户登录日志记录成功!"); } catch (Exception e) { log.error("save tenant login log fail:", e); throw new InternalServerException("保存租户登录日志记录失败", e, e.getMessage()); } } /** * 用户登录记录列表展示 * * @param pager * @return */ @Override public GeneralResult> list(Pager pager) { GridBean gridBean; try { List params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>()); Map sorter = Optional.ofNullable(pager.getSorter()).orElse(new HashMap<>()); sorter.put("gmt_create", Common.ONE); int total = loginRecordRepository.loginTimes(params); List list = loginRecordRepository.list(pager); gridBean = new GridBean<>(pager.getPage(), pager.getRows(), total, list); return new GeneralResult<>(true, gridBean, "查询成功"); } catch (Exception e) { log.error("Query user login record list fail:", e); return new GeneralResult<>(false, "查询失败:" + e.getMessage()); } } /** * 添加收藏 * * @param serviceId * @param requestContext * @return */ @Override @Transactional(rollbackFor = InternalServerException.class) public Result addFavorite(Long serviceId, RequestContext requestContext) throws InternalServerException { try { Favorite favorite = new Favorite(null, Favorite.Category.User, requestContext.getTarget(), serviceId, 0); favoriteRepository.save(favorite); return new Result(true, "添加收藏成功"); } catch (Exception e) { log.error("add favorite failed," + e); throw new InternalServerException("添加收藏失败", e, e.getMessage()); } } /** * 取消收藏 * * @param serviceId * @param requestContext * @return */ @Override @Transactional(rollbackFor = InternalServerException.class) public Result cancelFavorite(Long serviceId, RequestContext requestContext) throws InternalServerException { try { favoriteRepository.cancelFavorite(serviceId, requestContext.getTarget(), requestContext.getCatalog().name()); return new Result(true, "取消收藏成功"); } catch (Exception e) { log.error("add favorite failed," + e); throw new InternalServerException("取消收藏失败", e, e.getMessage()); } } /** * 获取服务目录 * * @param requestContext * @return */ @Override public GeneralResult> listServiceMenu(RequestContext requestContext) { try { // 获取用户角色授权的服务菜单权限 // List roles = roleRepository.listByUser(requestContext.getTarget()); // Map permissionMap = new HashMap<>(8); // for (Role role : roles) { // List permissions = roleRepository.listRoleServices(role.getId()); // permissionMap.putAll(permissions.stream().distinct().filter(cloudService -> // !"vmware.storage.disk".equals(cloudService.getCode())).collect(Collectors.toMap(CloudService::getCode, // Function.identity()))); // } // 获取用户所属租户的服务菜单权限 List allServices = cloudServiceBeanRepository .getFavoriteServices(requestContext.getTenant(), RequestContext.Catalog.Tenant.name()); // ArrayList cloudServices = new ArrayList<>(permissionMap.values()); // List allServices = // cloudServices.stream().map(CloudServiceBean::new).collect(Collectors.toList()); // 创建集合用于接收递归查询的相关权限 HashMap> serviceMenu = new HashMap<>(); // 获取用户收藏了的服务菜单权限 List favoriteServices = cloudServiceBeanRepository.getFavoriteServices(requestContext.getTarget(), Catalog.User.name()); List serviceIds = allServices.stream().map(CloudServiceBean::getId).collect(Collectors.toList()); // 获取授权的服务对应的菜单权限 List servicePermissions = permissionRepository.getServicesPermissions(serviceIds); // 查询服务编码集合 List permissionCodes = allServices.stream().map(CloudServiceBean::getCode).collect(Collectors.toList()); // List permissionCodes = new ArrayList<>(permissionMap.keySet()); HashMap> servicePermissionMap = new HashMap<>(8); for (String code : permissionCodes) { ArrayList permissions = new ArrayList<>(); for (Permission servicePermission : servicePermissions) { if (servicePermission.getServiceCodes().contains(code)) { permissions.add(servicePermission); } } servicePermissionMap.put(code, permissions); } for (CloudServiceBean cloudServiceBean : allServices) { ArrayList cloudServiceBeans = new ArrayList<>(); List permissions = servicePermissionMap.get(cloudServiceBean.getCode()); if (permissions != null && permissions.size() > 0) { Permission permission = permissions.stream().filter(permit -> "isServiceMenu".equals(permit.getProps())).findAny() .orElse(permissions.get(0)); cloudServiceBean.setPath(permission.getPath()); } if (favoriteServices.isEmpty()) { cloudServiceBean.setFavorite(false); } for (CloudServiceBean service : favoriteServices) { // 用户授权了该服务则设置收藏状态为true if (cloudServiceBean.getName().equals(service.getName())) { cloudServiceBean.setFavorite(true); break; } else { cloudServiceBean.setFavorite(false); } } // 按服务类型分组收集服务菜单权限 if (!serviceMenu.containsKey(cloudServiceBean.getCatalogName())) { // 不包含的服务类型就直接添加到集合中 cloudServiceBeans.add(cloudServiceBean); serviceMenu.put(cloudServiceBean.getCatalogName(), cloudServiceBeans); } else { // 存在的服务类型则获取该服务的菜单权限后再添加到原有的服务菜单权限中 List serviceMenus = serviceMenu.get(cloudServiceBean.getCatalogName()); serviceMenus.add(cloudServiceBean); serviceMenu.put(cloudServiceBean.getCatalogName(), serviceMenus); } } ArrayList serviceMenus = new ArrayList<>(); ArrayList categorys = Lists.newArrayList("计算", "存储", "网络", "数据库", "中间件", "运维", "编排", "监控"); for (String key : categorys) { List serviceBeanList = serviceMenu.get(key); if (null != serviceBeanList && !serviceBeanList.isEmpty()) { serviceMenus.add(new ServiceMenuBean(key, serviceBeanList)); } } return new GeneralResult<>(true, serviceMenus, "查询服务目录成功"); } catch (Exception e) { log.error("get service menus error,", e); return new GeneralResult<>(false, "查询失败:" + e.getMessage()); } } /** * 获取收藏夹 * * @param requestContext * @return */ @Override public GeneralResult> listFavorite(RequestContext requestContext) { try { // 获取用户收藏的服务菜单 List favoriteServices = cloudServiceBeanRepository.getFavoriteServices(requestContext.getTarget(), Catalog.User.name()); ArrayList favorites = new ArrayList<>(); List serviceIds = favoriteServices.stream().map(CloudServiceBean::getId).collect(Collectors.toList()); // 获取用户收藏的服务对应的菜单权限 List servicePermissions = permissionRepository.getServicesPermissions(serviceIds); // 查询服务编码集合 List permissionCodes = favoriteServices.stream().map(CloudServiceBean::getCode).collect(Collectors.toList()); HashMap> servicePermissionMap = new HashMap<>(); for (String code : permissionCodes) { ArrayList permissions = new ArrayList<>(); for (Permission servicePermission : servicePermissions) { if (servicePermission.getServiceCodes().contains(code)) { permissions.add(servicePermission); } } servicePermissionMap.put(code, permissions); } for (CloudServiceBean cloudServiceBean : favoriteServices) { List permissions = servicePermissionMap.get(cloudServiceBean.getCode()); if (permissions != null && permissions.size() > 0) { // 获取当前服务对应的菜单权限,并给对应的服务目录对象设置路由 Permission permission = permissions.stream().filter(permit -> "isServiceMenu".equals(permit.getProps())).findAny() .orElse(permissions.get(0)); cloudServiceBean.setPath(permission.getPath()); } cloudServiceBean.setFavorite(true); // 设置排序优先级 cloudServiceBean.setPriority(cloudServiceBean.getPriority()); favorites.add(cloudServiceBean); } favorites.sort(new FavoriteComparator()); return new GeneralResult<>(true, favorites, "查询服务收藏夹成功"); } catch (Exception e) { log.error("get favorite error," + e); return new GeneralResult<>(false, "查询失败:" + e.getMessage()); } } /** * 修改收藏夹排序 * * @param priorityModels * @param requestContext * @return */ @Override @Transactional(rollbackFor = InternalServerException.class) public Result changePriority(List priorityModels, RequestContext requestContext) throws InternalServerException { try { for (PriorityModel priorityModel : priorityModels) { favoriteRepository.changePriority(priorityModel.getId(), priorityModel.getPriority(), requestContext.getTarget()); } return new Result(true, "修改收藏夹排序成功"); } catch (Exception e) { log.error("change favorite priority error," + e); throw new InternalServerException("修改收藏夹排序失败", e, e.getMessage()); } } /** * 返回账号相关登录所需信息 * * @param account * @return */ @Override public GeneralResult> tokenLogin(String account) { // 判断用户是否存在 User user; try { user = userRepository.getByAccount(account); } catch (Exception e) { log.error("Get User fail by account:", e); return new GeneralResult<>(false, "该账号存在问题,校验失败"); } if (null == user) { log.warn("User is null"); return new GeneralResult<>(false, "该账号存在问题,校验失败"); } if (user.getStatus().equals(BaseStatus.ABNORMAL.name())) { return new GeneralResult<>(false, "该账号用户已被冻结,用户无法登录"); } // 查询随机数 AccountSecurity security; try { security = securityRepository.getByTarget(user.getId(), Catalog.User); } catch (Exception e) { log.error("Query Random fail:", e); return new GeneralResult<>(false, "该账号存在问题,校验失败"); } if (null == security) { log.warn("Security is null"); return new GeneralResult<>(false, "该账号存在问题,校验失败"); } Map map = MapTools.simpleMap(Common.USER, user); map.put(Common.API_KEY, security.getApiKey()); map.put(Common.SEC_KEY, security.getSecKey()); map.put("accountCategory", Catalog.User.name()); return new GeneralResult<>(true, map, "用户跳转成功"); } @Override public Result exist(String account) { try { User user = userRepository.getByAccount(account); return user == null ? new Result(true, "账号可以使用") : new Result(false, "账号已经存在"); } catch (Exception e) { log.error("query user by account error,", e); return new Result(false, "查询失败:" + e.getMessage()); } } @Override public GeneralResult> projects(Long id) { try { User user = userRepository.query(id); Assert.notNull(user, "用户不存在"); List projects = projectRepository.listUserProject(id); return new GeneralResult<>(true, projects, "查询成功"); } catch (Exception e) { log.error("List user project fail:", e); return new GeneralResult<>(false, "查询失败:" + e.getMessage()); } } @Override public Result importTemp(String name, HttpServletResponse response) { // 下拉列表数据 List departmentsName = new ArrayList<>(); List tenantsName = new ArrayList<>(); ArrayList sex = new ArrayList<>(); ArrayList IsManager = new ArrayList<>(); try { // 部门数据 departmentsName = departmentRepository.listAll().stream().map(Department::getName).collect(Collectors.toList()); // 租户数据 tenantsName = tenantRepository.list().stream().map(Tenant::getName).collect(Collectors.toList()); } catch (Exception e) { log.error("获取租户或部门数据异常", e); } sex.add("男"); sex.add("女"); IsManager.add("管理用户"); IsManager.add("普通用户"); // 校验数据 map: k 表示列 index,v 表示下拉列表数据 HashMap> map = new HashMap<>(8); map.put(4, sex); if (tenantsName.size() > 0) { map.put(5, tenantsName); } if (departmentsName.size() > 0) { map.put(10, departmentsName); } map.put(11, IsManager); CellWriteHandler cellWriteHandler = ExportUtil.getCellWriteHandler(map); boolean res = exportExcel("用户列表模板", "导出模板", response, new ArrayList<>(), ImportUserTemplate.class, cellWriteHandler); return res ? new Result(true, "用户模板下载成功") : new Result(false, "用户模板下载失败"); } @Override public Result importData(MultipartFile multipartFile, Long tenantId, RequestContext requestContext) { try { String originalFilename = multipartFile.getOriginalFilename(); Assert.notNull(originalFilename, "文件名不能为空"); String[] checkedHead = new String[]{"用户名称", "登录账号", "钉钉账号", "微信账号", "用户性别", "所属租户", "电子邮箱", "联系电话", "用户工号", "公司名称", "所属组织", "是否为管理员", "用户描述"}; Map paramMap = MapTools.simpleMap("requestContext", requestContext); paramMap.put("tenantId", tenantId); AnalysisEventListener analysisEventListener = ImportExcelUtil.getListener(this.batchInsert(), 1000, checkedHead, paramMap); EasyExcel.read(multipartFile.getInputStream(), ImportUserTemplate.class, analysisEventListener).sheet() .doRead(); return ImportExcelUtil.getResult(); } catch (Exception e) { log.error("用户导入异常", e); return ImportExcelUtil.getResult(); } } private BiFunction, Map, Result> batchInsert() { return (impUserTemp, paramsMap) -> { StringBuilder errorMsg = new StringBuilder(); ArrayList users = new ArrayList<>(); RequestContext requestContext = (RequestContext) paramsMap.get("requestContext"); Long tenantId = (Long) paramsMap.get("tenantId"); if (!impUserTemp.isEmpty()) { for (ImportUserTemplate userTemplate : impUserTemp) { // 防止导入空行 if (userTemplate.getAccount() == null && userTemplate.getName() == null && userTemplate.getMobile() == null) { continue; } User user = new User(); user.setName(userTemplate.getName()); user.setAccount(userTemplate.getAccount()); user.setEmail(userTemplate.getEmail()); user.setIsManager("管理用户".equals(userTemplate.getIsManager())); if (tenantId == null || tenantId == 0L) { user.setTenantName(userTemplate.getTenantName()); } user.setCompany(userTemplate.getCompany()); user.setDepartmentName(userTemplate.getDepartmentName()); user.setDingtalk(userTemplate.getDingtalk()); user.setJobNumber(userTemplate.getJobNumber()); user.setMobile(userTemplate.getMobile()); user.setRemark(userTemplate.getRemark()); user.setWechat(userTemplate.getWechat()); if (userTemplate.getSex() == null) { user.setSex(null); } else { user.setSex("男".equals(userTemplate.getSex())); } users.add(user); } } try { if (null != tenantId && 0L != tenantId) { Tenant tenant = tenantRepository.query(tenantId); for (User user : users) { user.setTenantId(tenantId); user.setDepartId(tenant.getDepartId()); user.setTenantName(tenant.getName()); } } else { for (User user : users) { user.setTenantId(0L); } } int successNum = 0; int errorNumber = 0; List existNames = userRepository.list().stream().map(User::getName).toList(); List existAccounts = userRepository.list().stream().map(User::getAccount).toList(); Map tenantMap = tenantRepository.list().stream().collect(Collectors.toMap(Tenant::getName, Function.identity())); Map departmentMap = departmentRepository.listAll().stream() .collect(Collectors.toMap(Department::getName, Function.identity())); ListIterator listIterator = users.listIterator(); // 邮箱格式 String EMAIL_REGEX = "^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$"; while (listIterator.hasNext()) { User user = listIterator.next(); if (user.getName() == null || user.getAccount() == null || user.getIsManager() == null || user.getEmail() == null || user.getSex() == null || user.getMobile() == null) { errorNumber++; listIterator.remove(); log.error("{} 用户名称,登录账号、是否为管理员、电子邮箱、用户性别、联系电话,存在空值", user.getName()); errorMsg.append(user.getName()).append(":用户名称,登录账号、是否为管理员、电子邮箱、用户性别、联系电话,存在空值"); continue; } String name = user.getName(); if (existNames.contains(name)) { errorNumber++; listIterator.remove(); log.error("user {} has existed", name); errorMsg.append(name).append(":用户名已存在"); continue; } String account = user.getAccount(); if (existAccounts.contains(account)) { errorNumber++; listIterator.remove(); log.error("user account {} has existed", account); errorMsg.append(account).append(":账号已存在"); continue; } if (user.getEmail() != null && !user.getEmail().matches(EMAIL_REGEX)) { errorNumber++; log.error("{}邮箱格式错误", user.getName()); errorMsg.append(user.getName()).append(":邮箱格式错误"); listIterator.remove(); continue; } if (!StringUtils.hasText(account) || !StringUtils.hasText(name)) { errorNumber++; listIterator.remove(); log.error("user account or name can't be empty."); errorMsg.append("用户名、账号不能为空"); continue; } if (StringUtils.hasText(user.getTenantName())) { if (!tenantMap.containsKey(user.getTenantName())) { errorNumber++; listIterator.remove(); errorMsg.append(user.getName()).append(":租户不存在"); log.error("user {} 's tenant {} don't exist", user.getName(), user.getTenantName()); } else { Tenant tenant = tenantMap.get(user.getTenantName()); user.setTenantId(tenant.getId()); user.setDepartId(tenant.getDepartId()); } } else { if (!departmentMap.containsKey(user.getDepartmentName()) && user.getDepartmentName() != null) { errorNumber++; listIterator.remove(); errorMsg.append(user.getName()).append(":部门不存在"); log.error("user {} 's department {} don't exist", user.getName(), user.getTenantName()); } // 设置用户部门id if (departmentMap.get(user.getDepartmentName()) != null) { user.setDepartId(departmentMap.get(user.getDepartmentName()).getId()); } } } List list = new ArrayList<>(); for (User user : users) { Future future = taskExecutor.submit(() -> this.createUser(user, requestContext)); Result result = future.get(); list.add(result); } for (Result res : list) { if (res.isSuccess()) { successNum++; } else { errorMsg.append(res.getMessage()); } } if (successNum == users.size() && errorNumber == 0) { return new Result(true, "导入用户信息成功"); } else if (successNum > 0) { return new Result(true, successNum + "条用户信息导入成功," + (users.size() - successNum + errorNumber) + "条用户信息导入异常 " + errorMsg); } else { return new Result(true, successNum + "条用户信息导入成功," + (users.size() - successNum + errorNumber) + "条用户信息导入异常" + errorMsg); } } catch (Exception e) { log.error("用户导入异常", e); return new Result(false, "用户信息导入异常" + errorMsg); } }; } private GeneralResult> readExcel(Workbook wb, Long tenantId) { Sheet sheet = wb.getSheetAt(0); List users = new ArrayList<>(); for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) { Row row = sheet.getRow(rowNum); User user = new User(); Cell name = row.getCell(0); user.setName(getCellStringValue(name)); Cell account = row.getCell(1); user.setAccount(getCellStringValue(account)); Cell sex = row.getCell(4); String sexValue = getCellStringValue(sex); user.setSex(sexValue == null ? null : "男".equals(sexValue)); if (null == tenantId || 0L == tenantId) { Cell dingtalk = row.getCell(2); user.setDingtalk(getCellStringValue(dingtalk)); Cell wechat = row.getCell(3); user.setWechat(getCellStringValue(wechat)); Cell tenant = row.getCell(5); user.setTenantName(getCellStringValue(tenant)); Cell email = row.getCell(6); user.setEmail(getCellStringValue(email)); Cell mobile = row.getCell(7); CellType cellTypeEnum = mobile.getCellTypeEnum(); if (!cellTypeEnum.name().equals(CellType.NUMERIC.name())) { return new GeneralResult<>(false, null, "手机号列仅限数字格式"); } user.setMobile(getCellStringValue(mobile)); Cell jobNumber = row.getCell(8); user.setJobNumber(getCellStringValue(jobNumber)); Cell company = row.getCell(9); user.setCompany(getCellStringValue(company)); Cell manager = row.getCell(10); user.setIsManager("是".equals(getCellStringValue(manager))); Cell remark = row.getCell(11); user.setRemark(getCellStringValue(remark)); } else { Cell dingtalk = row.getCell(2); user.setDingtalk(getCellStringValue(dingtalk)); Cell wechat = row.getCell(3); user.setWechat(getCellStringValue(wechat)); Cell email = row.getCell(5); user.setEmail(getCellStringValue(email)); Cell mobile = row.getCell(6); user.setMobile(getCellStringValue(mobile)); Cell jobNumber = row.getCell(7); user.setJobNumber(getCellStringValue(jobNumber)); Cell company = row.getCell(8); user.setCompany(getCellStringValue(company)); Cell manager = row.getCell(9); user.setIsManager("是".equals(getCellStringValue(manager))); Cell remark = row.getCell(10); user.setRemark(getCellStringValue(remark)); } users.add(user); } return new GeneralResult<>(true, users, ""); } private Result createUser(User user, RequestContext requestContext) { StringBuilder errMsg = new StringBuilder(); try { user.setCreatorId(requestContext.getTarget()); // 初始化密码 String salt = UUID.randomUUID().toString(); Encryptor encryptor = new SHAEncryptor(); User existUser = userRepository.getByAccount(user.getAccount()); if (existUser != null) { errMsg.append(existUser.getName()).append("该账号已存在"); throw new IllegalArgumentException("该账号已存在"); } if (StringUtils.hasText(user.getEmail())) { User existEmailUser = userRepository.getByEmail(user.getEmail()); if (null != existEmailUser) { errMsg.append(existEmailUser.getName()).append("该邮箱已被注册"); throw new IllegalArgumentException("该邮箱已被注册"); } } String password = encryptor.encrypt("Aa123456", salt); user.setPassword(password); // 关键信息去空 user.setAccount(user.getAccount().trim()); user.setName(user.getName().trim()); user.setStatus(BaseStatus.NORMAL.name()); user.setLoginStatus(false); user.setLastPwdModifyDate(new Date()); user.setOrigin("SYSTEM"); userRepository.save(user); String account = user.getAccount(); User cacheUser = userRepository.getByAccount(account); redisTemplate.opsForValue().set(Catalog.User.name() + "_" + cacheUser.getId(), account); redisTemplate.opsForValue().set(Catalog.User.name() + "_Name_" + cacheUser.getId(), cacheUser.getName()); // 构建用户随机数对象 AccountSecurity security = new AccountSecurity(); String data = user.getAccount() + System.currentTimeMillis(); String apiKey = encryptor.encrypt(data, Common.API_KEY); String secKey = encryptor.encrypt(data, Common.SEC_KEY); security.setTargetId(user.getId()); security.setCategory(AccountSecurity.Category.User); security.setSalt(salt); security.setApiKey(apiKey); security.setSecKey(secKey); security.setTenantId(user.getTenantId()); boolean success = securityRepository.baseSave(security); if (!success) { callback(user.getId(), requestContext); } return new Result(true, ""); } catch (Exception e) { log.error("create user fail:", e); this.callback(user.getId(), requestContext); return new Result(false, errMsg.toString()); } } private void callback(Long targetId, RequestContext context) { try { User user = userRepository.query(targetId); if (user != null) { userRepository.delete(targetId, context.getTarget()); redisTemplate.delete(RequestContext.Catalog.User.name() + "_" + user.getId()); redisTemplate.delete(RequestContext.Catalog.User.name() + "_Name_" + user.getId()); } securityRepository.delete(targetId, RequestContext.Catalog.User); } catch (Exception e) { log.error("call back error:{}", e.getMessage()); } } @Override public Result export(List paramList, RequestContext requestContext, HttpServletResponse response) { try { Map sorter = new HashMap<>(8); if (!Catalog.Manager.equals(requestContext.getCatalog())) { Map tenantMap = MapTools.simpleMap("tenantId", requestContext.getTenant()); Param param = new Param(tenantMap, Sign.EQ); paramList.add(param); } sorter.put("gmtCreate", Common.ONE); Long roleId = null; Iterator paramIterator = paramList.iterator(); // 有参数时判断是否有租户id if (paramIterator.hasNext()) { Param next = paramIterator.next(); Map paramMap = next.getParam(); if (paramMap.containsKey("roleId")) { roleId = Long.valueOf(paramMap.get("roleId").toString()); paramMap.remove("roleId"); } } List users = userRepository.list(1, Integer.MAX_VALUE, paramList, sorter, roleId); for (User user : users) { Department department = departmentRepository.query(user.getDepartId()); if (department != null) { user.setDepartmentName(department.getName()); } } ArrayList list = new ArrayList<>(); for (User user : users) { ImportUserTemplate userTemplate = new ImportUserTemplate(); userTemplate.setAccount(user.getAccount()); userTemplate.setName(user.getName()); userTemplate.setDingtalk(user.getDingtalk()); userTemplate.setWechat(user.getWechat()); userTemplate.setSex(user.getSex() ? "男" : "女"); userTemplate.setTenantName(user.getTenantName()); userTemplate.setEmail(user.getEmail()); userTemplate.setMobile(user.getMobile()); userTemplate.setJobNumber(user.getJobNumber()); userTemplate.setCompany(user.getCompany()); userTemplate.setDepartmentName(user.getDepartmentName()); userTemplate.setRemark(user.getRemark()); userTemplate.setIsManager(null != user.getIsManager() && user.getIsManager() ? "管理用户" : "普通用户"); list.add(userTemplate); } boolean exportExcel = exportExcel("用户列表" + System.currentTimeMillis(), "用户列表", response, list, ImportUserTemplate.class, null); return exportExcel ? new Result(true, "用户导出成功") : new Result(false, "用户导出失败"); } catch (Exception e) { log.error("create user work book failed:", e); return new Result(false, "用户导出异常"); } } @Override public Result unBindTenants(Long id, RequestContext requestContext) { String path = User.class.getSimpleName() + "_" + id; try (AutoCloseLock lock = lockFactory.getACLock(path)) { Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时"); User user = userRepository.query(id); Assert.notNull(user, "用户信息不存在"); user.setTenantId(0L); user.setMenderId(requestContext.getTarget()); userRepository.update(user); return new Result(true, "操作成功"); } catch (Exception e) { log.error("user unbind tenant failed:", e); return new Result(false, "操作失败"); } } @Override public GeneralResult checkPassword(RequestContext requestContext, String password) { User user; AccountSecurity security; try { user = userRepository.query(requestContext.getTarget()); security = securityRepository.getByTarget(user.getId(), Catalog.User); // 对前端传过来的密码进行解密 Encryptor encryptor = new AESEncryptor(); password = encryptor.decrypt(password.trim(), null); if (!StringUtils.hasText(password)) { return new GeneralResult<>(false, "账号或密码错误"); } // 密码加密 encryptor = new SHAEncryptor(); String encryptString = encryptor.encrypt(password, security.getSalt()); if (null == encryptString || !encryptString.equals(user.getPassword())) { log.warn("Wrong user account or password"); return new GeneralResult<>(false, "账号或密码错误"); } } catch (Exception e) { log.error("用户密码解密异常{}", e.getMessage()); return new GeneralResult<>(false, "密码错误"); } return new GeneralResult<>(true, "密码正确"); } }