mirror of
https://github.com/continew-org/continew-admin.git
synced 2025-10-26 06:57:08 +08:00
chore: 优化用户管理相关代码
This commit is contained in:
@@ -23,7 +23,7 @@ import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import top.continew.admin.common.config.mybatis.DataPermissionMapper;
|
||||
import top.continew.admin.system.model.entity.UserDO;
|
||||
import top.continew.admin.system.model.resp.UserDetailResp;
|
||||
import top.continew.admin.system.model.resp.user.UserDetailResp;
|
||||
import top.continew.starter.extension.datapermission.annotation.DataPermission;
|
||||
import top.continew.starter.security.crypto.annotation.FieldEncrypt;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.req;
|
||||
package top.continew.admin.system.model.req.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.req;
|
||||
package top.continew.admin.system.model.req.user;
|
||||
|
||||
import cn.hutool.core.lang.RegexPool;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.req;
|
||||
package top.continew.admin.system.model.req.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.req;
|
||||
package top.continew.admin.system.model.req.user;
|
||||
|
||||
import cn.hutool.core.lang.RegexPool;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.req;
|
||||
package top.continew.admin.system.model.req.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.req;
|
||||
package top.continew.admin.system.model.req.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.req;
|
||||
package top.continew.admin.system.model.req.user;
|
||||
|
||||
import cn.hutool.core.lang.RegexPool;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.req;
|
||||
package top.continew.admin.system.model.req.user;
|
||||
|
||||
import cn.hutool.core.lang.RegexPool;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.req;
|
||||
package top.continew.admin.system.model.req.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.resp;
|
||||
package top.continew.admin.system.model.resp.user;
|
||||
|
||||
import cn.crane4j.annotation.Assemble;
|
||||
import cn.crane4j.annotation.AssembleMethod;
|
||||
@@ -30,6 +30,7 @@ import top.continew.admin.common.constant.ContainerConstants;
|
||||
import top.continew.admin.common.context.UserContextHolder;
|
||||
import top.continew.admin.common.enums.DisEnableStatusEnum;
|
||||
import top.continew.admin.common.enums.GenderEnum;
|
||||
import top.continew.admin.system.model.resp.DeptResp;
|
||||
import top.continew.admin.system.service.DeptService;
|
||||
import top.continew.starter.extension.crud.model.resp.BaseDetailResp;
|
||||
import top.continew.starter.file.excel.converter.ExcelBaseEnumConverter;
|
||||
@@ -14,31 +14,35 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.resp;
|
||||
package top.continew.admin.system.model.resp.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户导入结果
|
||||
* 用户导入解析结果
|
||||
*
|
||||
* @author kils
|
||||
* @since 2024-06-18 14:37
|
||||
* @since 2024/6/18 14:37
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "用户导入结果")
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class UserImportParseResp {
|
||||
@Schema(description = "用户导入解析结果")
|
||||
public class UserImportParseResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 导入会话KEY
|
||||
* 导入会话 Key
|
||||
*/
|
||||
@Schema(description = "导入会话KEY", example = "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed")
|
||||
@Schema(description = "导入会话Key", example = "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed")
|
||||
private String importKey;
|
||||
|
||||
/**
|
||||
@@ -54,9 +58,9 @@ public class UserImportParseResp {
|
||||
private Integer validRows;
|
||||
|
||||
/**
|
||||
* 用户重复行数
|
||||
* 重复行数
|
||||
*/
|
||||
@Schema(description = "用户重复行数", example = "100")
|
||||
@Schema(description = "重复行数", example = "100")
|
||||
private Integer duplicateUserRows;
|
||||
|
||||
/**
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.resp;
|
||||
package top.continew.admin.system.model.resp.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.resp;
|
||||
package top.continew.admin.system.model.resp.user;
|
||||
|
||||
import cn.crane4j.annotation.Assemble;
|
||||
import cn.crane4j.core.executor.handler.ManyToManyAssembleOperationHandler;
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.admin.system.model.resp;
|
||||
package top.continew.admin.system.model.resp.user;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
@@ -20,11 +20,11 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.admin.system.model.entity.UserDO;
|
||||
import top.continew.admin.system.model.query.UserQuery;
|
||||
import top.continew.admin.system.model.req.*;
|
||||
import top.continew.admin.system.model.resp.UserDetailResp;
|
||||
import top.continew.admin.system.model.resp.UserImportParseResp;
|
||||
import top.continew.admin.system.model.resp.UserImportResp;
|
||||
import top.continew.admin.system.model.resp.UserResp;
|
||||
import top.continew.admin.system.model.req.user.*;
|
||||
import top.continew.admin.system.model.resp.user.UserDetailResp;
|
||||
import top.continew.admin.system.model.resp.user.UserImportParseResp;
|
||||
import top.continew.admin.system.model.resp.user.UserImportResp;
|
||||
import top.continew.admin.system.model.resp.user.UserResp;
|
||||
import top.continew.starter.data.mp.service.IService;
|
||||
import top.continew.starter.extension.crud.service.BaseService;
|
||||
|
||||
@@ -47,6 +47,30 @@ public interface UserService extends BaseService<UserResp, UserDetailResp, UserQ
|
||||
*/
|
||||
Long add(UserDO user);
|
||||
|
||||
/**
|
||||
* 下载导入模板
|
||||
*
|
||||
* @param response 响应对象
|
||||
* @throws IOException /
|
||||
*/
|
||||
void downloadImportTemplate(HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 解析导入数据
|
||||
*
|
||||
* @param file 导入文件
|
||||
* @return 解析结果
|
||||
*/
|
||||
UserImportParseResp parseImport(MultipartFile file);
|
||||
|
||||
/**
|
||||
* 导入数据
|
||||
*
|
||||
* @param req 导入信息
|
||||
* @return 导入结果
|
||||
*/
|
||||
UserImportResp importUser(UserImportReq req);
|
||||
|
||||
/**
|
||||
* 重置密码
|
||||
*
|
||||
@@ -139,28 +163,4 @@ public interface UserService extends BaseService<UserResp, UserDetailResp, UserQ
|
||||
* @return 用户数量
|
||||
*/
|
||||
Long countByDeptIds(List<Long> deptIds);
|
||||
|
||||
/**
|
||||
* 下载用户导入模板
|
||||
*
|
||||
* @param response 响应对象
|
||||
* @throws IOException /
|
||||
*/
|
||||
void downloadImportUserTemplate(HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 导入用户
|
||||
*
|
||||
* @param req 导入信息
|
||||
* @return 导入结果
|
||||
*/
|
||||
UserImportResp importUser(UserImportReq req);
|
||||
|
||||
/**
|
||||
* 解析用户导入数据
|
||||
*
|
||||
* @param file 导入用户文件
|
||||
* @return 解析结果
|
||||
*/
|
||||
UserImportParseResp parseImportUser(MultipartFile file);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import top.continew.admin.system.model.query.DeptQuery;
|
||||
import top.continew.admin.system.model.query.UserQuery;
|
||||
import top.continew.admin.system.model.req.DeptReq;
|
||||
import top.continew.admin.system.model.resp.DeptResp;
|
||||
import top.continew.admin.system.model.resp.UserResp;
|
||||
import top.continew.admin.system.model.resp.user.UserResp;
|
||||
import top.continew.admin.system.service.DeptService;
|
||||
import top.continew.admin.system.service.RoleDeptService;
|
||||
import top.continew.admin.system.service.UserService;
|
||||
|
||||
@@ -44,6 +44,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.ahoo.cosid.IdGenerator;
|
||||
import me.ahoo.cosid.provider.DefaultIdGeneratorProvider;
|
||||
import net.dreamlu.mica.core.result.R;
|
||||
@@ -66,11 +67,11 @@ import top.continew.admin.system.model.entity.RoleDO;
|
||||
import top.continew.admin.system.model.entity.UserDO;
|
||||
import top.continew.admin.system.model.entity.UserRoleDO;
|
||||
import top.continew.admin.system.model.query.UserQuery;
|
||||
import top.continew.admin.system.model.req.*;
|
||||
import top.continew.admin.system.model.resp.UserDetailResp;
|
||||
import top.continew.admin.system.model.resp.UserImportParseResp;
|
||||
import top.continew.admin.system.model.resp.UserImportResp;
|
||||
import top.continew.admin.system.model.resp.UserResp;
|
||||
import top.continew.admin.system.model.req.user.*;
|
||||
import top.continew.admin.system.model.resp.user.UserDetailResp;
|
||||
import top.continew.admin.system.model.resp.user.UserImportParseResp;
|
||||
import top.continew.admin.system.model.resp.user.UserImportResp;
|
||||
import top.continew.admin.system.model.resp.user.UserResp;
|
||||
import top.continew.admin.system.service.*;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
@@ -99,6 +100,7 @@ import static top.continew.admin.system.enums.PasswordPolicyEnum.*;
|
||||
* @author Charles7c
|
||||
* @since 2022/12/21 21:49
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserResp, UserDetailResp, UserQuery, UserReq> implements UserService, CommonUserService {
|
||||
@@ -133,6 +135,89 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
return BeanUtil.copyToList(entityList, UserResp.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeAdd(UserReq req) {
|
||||
final String errorMsgTemplate = "新增失败,[{}] 已存在";
|
||||
String username = req.getUsername();
|
||||
CheckUtils.throwIf(this.isNameExists(username, null), errorMsgTemplate, username);
|
||||
String email = req.getEmail();
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(email) && this.isEmailExists(email, null), errorMsgTemplate, email);
|
||||
String phone = req.getPhone();
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(phone) && this.isPhoneExists(phone, null), errorMsgTemplate, phone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAdd(UserReq req, UserDO user) {
|
||||
Long userId = user.getId();
|
||||
baseMapper.lambdaUpdate().set(UserDO::getPwdResetTime, LocalDateTime.now()).eq(UserDO::getId, userId).update();
|
||||
// 保存用户和角色关联
|
||||
userRoleService.add(req.getRoleIds(), userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheUpdate(key = "#id", value = "#req.nickname", name = CacheConstants.USER_KEY_PREFIX)
|
||||
public void update(UserReq req, Long id) {
|
||||
final String errorMsgTemplate = "修改失败,[{}] 已存在";
|
||||
String username = req.getUsername();
|
||||
CheckUtils.throwIf(this.isNameExists(username, id), errorMsgTemplate, username);
|
||||
String email = req.getEmail();
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(email) && this.isEmailExists(email, id), errorMsgTemplate, email);
|
||||
String phone = req.getPhone();
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(phone) && this.isPhoneExists(phone, id), errorMsgTemplate, phone);
|
||||
DisEnableStatusEnum newStatus = req.getStatus();
|
||||
CheckUtils.throwIf(DisEnableStatusEnum.DISABLE.equals(newStatus) && ObjectUtil.equal(id, UserContextHolder
|
||||
.getUserId()), "不允许禁用当前用户");
|
||||
UserDO oldUser = super.getById(id);
|
||||
if (Boolean.TRUE.equals(oldUser.getIsSystem())) {
|
||||
CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, newStatus, "[{}] 是系统内置用户,不允许禁用", oldUser
|
||||
.getNickname());
|
||||
Collection<Long> disjunctionRoleIds = CollUtil.disjunction(req.getRoleIds(), userRoleService
|
||||
.listRoleIdByUserId(id));
|
||||
CheckUtils.throwIfNotEmpty(disjunctionRoleIds, "[{}] 是系统内置用户,不允许变更角色", oldUser.getNickname());
|
||||
}
|
||||
// 更新信息
|
||||
UserDO newUser = BeanUtil.toBean(req, UserDO.class);
|
||||
newUser.setId(id);
|
||||
baseMapper.updateById(newUser);
|
||||
// 保存用户和角色关联
|
||||
boolean isSaveUserRoleSuccess = userRoleService.add(req.getRoleIds(), id);
|
||||
// 如果禁用用户,则踢出在线用户
|
||||
if (DisEnableStatusEnum.DISABLE.equals(newStatus)) {
|
||||
onlineUserService.kickOut(id);
|
||||
return;
|
||||
}
|
||||
// 如果角色有变更,则更新在线用户权限信息
|
||||
if (isSaveUserRoleSuccess) {
|
||||
UserContext userContext = UserContextHolder.getContext(id);
|
||||
if (null != userContext) {
|
||||
userContext.setRoles(roleService.listByUserId(id));
|
||||
userContext.setPermissions(roleService.listPermissionByUserId(id));
|
||||
UserContextHolder.setContext(userContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheInvalidate(key = "#ids", name = CacheConstants.USER_KEY_PREFIX, multi = true)
|
||||
public void delete(List<Long> ids) {
|
||||
CheckUtils.throwIf(CollUtil.contains(ids, UserContextHolder.getUserId()), "不允许删除当前用户");
|
||||
List<UserDO> list = baseMapper.lambdaQuery()
|
||||
.select(UserDO::getNickname, UserDO::getIsSystem)
|
||||
.in(UserDO::getId, ids)
|
||||
.list();
|
||||
Optional<UserDO> isSystemData = list.stream().filter(UserDO::getIsSystem).findFirst();
|
||||
CheckUtils.throwIf(isSystemData::isPresent, "所选用户 [{}] 是系统内置用户,不允许删除", isSystemData.orElseGet(UserDO::new)
|
||||
.getNickname());
|
||||
// 删除用户和角色关联
|
||||
userRoleService.deleteByUserIds(ids);
|
||||
// 删除历史密码
|
||||
userPasswordHistoryService.deleteByUserIds(ids);
|
||||
// 删除用户
|
||||
super.delete(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long add(UserDO user) {
|
||||
user.setStatus(DisEnableStatusEnum.ENABLE);
|
||||
@@ -141,12 +226,12 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadImportUserTemplate(HttpServletResponse response) throws IOException {
|
||||
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
|
||||
try {
|
||||
FileUploadUtils.download(response, ResourceUtil
|
||||
.getStream("templates/import/userImportTemplate.xlsx"), "用户导入模板.xlsx");
|
||||
.getStream("templates/import/user.xlsx"), "用户导入模板.xlsx");
|
||||
} catch (Exception e) {
|
||||
log.error("下载用户导入模板失败:", e);
|
||||
log.error("下载用户导入模板失败:{}", e.getMessage(), e);
|
||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||
response.setContentType(ContentType.JSON.toString());
|
||||
response.getWriter().write(JSONUtil.toJsonStr(R.fail("下载用户导入模板失败")));
|
||||
@@ -154,69 +239,64 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserImportParseResp parseImportUser(MultipartFile file) {
|
||||
public UserImportParseResp parseImport(MultipartFile file) {
|
||||
UserImportParseResp userImportResp = new UserImportParseResp();
|
||||
List<UserImportRowReq> userRowList;
|
||||
List<UserImportRowReq> importRowList;
|
||||
// 读取表格数据
|
||||
try {
|
||||
userRowList = EasyExcel.read(file.getInputStream())
|
||||
importRowList = EasyExcel.read(file.getInputStream())
|
||||
.head(UserImportRowReq.class)
|
||||
.sheet()
|
||||
.headRowNumber(1)
|
||||
.doReadSync();
|
||||
} catch (Exception e) {
|
||||
log.error("用户导入数据文件解析异常:", e);
|
||||
log.error("用户导入数据文件解析异常:{}", e.getMessage(), e);
|
||||
throw new BusinessException("数据文件解析异常");
|
||||
}
|
||||
userImportResp.setTotalRows(userRowList.size());
|
||||
if (CollUtil.isEmpty(userRowList)) {
|
||||
throw new BusinessException("数据文件格式错误");
|
||||
}
|
||||
|
||||
// 过滤无效数据
|
||||
List<UserImportRowReq> validUserRowList = filterErrorUserImportData(userRowList);
|
||||
userImportResp.setValidRows(validUserRowList.size());
|
||||
if (CollUtil.isEmpty(validUserRowList)) {
|
||||
throw new BusinessException("数据文件格式错误");
|
||||
}
|
||||
// 总计行数
|
||||
userImportResp.setTotalRows(importRowList.size());
|
||||
CheckUtils.throwIfEmpty(importRowList, "数据文件格式错误");
|
||||
// 有效行数:过滤无效数据
|
||||
List<UserImportRowReq> validRowList = this.filterImportData(importRowList);
|
||||
userImportResp.setValidRows(validRowList.size());
|
||||
CheckUtils.throwIfEmpty(validRowList, "数据文件格式错误");
|
||||
|
||||
// 检测表格内数据是否合法
|
||||
Set<String> seenEmails = new HashSet<>();
|
||||
boolean hasDuplicateEmail = validUserRowList.stream()
|
||||
boolean hasDuplicateEmail = validRowList.stream()
|
||||
.map(UserImportRowReq::getEmail)
|
||||
.anyMatch(email -> email != null && !seenEmails.add(email));
|
||||
CheckUtils.throwIf(hasDuplicateEmail, "存在重复邮箱,请检测数据");
|
||||
Set<String> seenPhones = new HashSet<>();
|
||||
boolean hasDuplicatePhone = validUserRowList.stream()
|
||||
boolean hasDuplicatePhone = validRowList.stream()
|
||||
.map(UserImportRowReq::getPhone)
|
||||
.anyMatch(phone -> phone != null && !seenPhones.add(phone));
|
||||
CheckUtils.throwIf(hasDuplicatePhone, "存在重复手机,请检测数据");
|
||||
|
||||
// 校验是否存在错误角色
|
||||
List<String> roleNames = validUserRowList.stream().map(UserImportRowReq::getRoleName).distinct().toList();
|
||||
List<String> roleNames = validRowList.stream().map(UserImportRowReq::getRoleName).distinct().toList();
|
||||
int existRoleCount = roleService.countByNames(roleNames);
|
||||
CheckUtils.throwIf(existRoleCount < roleNames.size(), "存在错误角色,请检查数据");
|
||||
// 校验是否存在错误部门
|
||||
List<String> deptNames = validUserRowList.stream().map(UserImportRowReq::getDeptName).distinct().toList();
|
||||
List<String> deptNames = validRowList.stream().map(UserImportRowReq::getDeptName).distinct().toList();
|
||||
int existDeptCount = deptService.countByNames(deptNames);
|
||||
CheckUtils.throwIf(existDeptCount < deptNames.size(), "存在错误部门,请检查数据");
|
||||
|
||||
// 查询重复用户
|
||||
userImportResp
|
||||
.setDuplicateUserRows(countExistByField(validUserRowList, UserImportRowReq::getUsername, UserDO::getUsername, false));
|
||||
.setDuplicateUserRows(countExistByField(validRowList, UserImportRowReq::getUsername, UserDO::getUsername, false));
|
||||
// 查询重复邮箱
|
||||
userImportResp
|
||||
.setDuplicateEmailRows(countExistByField(validUserRowList, UserImportRowReq::getEmail, UserDO::getEmail, true));
|
||||
.setDuplicateEmailRows(countExistByField(validRowList, UserImportRowReq::getEmail, UserDO::getEmail, true));
|
||||
// 查询重复手机
|
||||
userImportResp
|
||||
.setDuplicatePhoneRows(countExistByField(validUserRowList, UserImportRowReq::getPhone, UserDO::getPhone, true));
|
||||
.setDuplicatePhoneRows(countExistByField(validRowList, UserImportRowReq::getPhone, UserDO::getPhone, true));
|
||||
|
||||
// 设置导入会话并缓存数据,有效期10分钟
|
||||
String importKey = UUID.fastUUID().toString(true);
|
||||
RedisUtils.set(CacheConstants.DATA_IMPORT_KEY + importKey, JSONUtil.toJsonStr(validUserRowList), Duration
|
||||
RedisUtils.set(CacheConstants.DATA_IMPORT_KEY + importKey, JSONUtil.toJsonStr(validRowList), Duration
|
||||
.ofMinutes(10));
|
||||
userImportResp.setImportKey(importKey);
|
||||
|
||||
return userImportResp;
|
||||
}
|
||||
|
||||
@@ -290,7 +370,6 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
return new UserImportResp(insertList.size() + updateList.size(), insertList.size(), updateList.size());
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void doImportUser(List<UserDO> insertList, List<UserDO> updateList, List<UserRoleDO> userRoleDOList) {
|
||||
if (CollUtil.isNotEmpty(insertList)) {
|
||||
baseMapper.insert(insertList);
|
||||
@@ -304,70 +383,6 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheUpdate(key = "#id", value = "#req.nickname", name = CacheConstants.USER_KEY_PREFIX)
|
||||
public void update(UserReq req, Long id) {
|
||||
final String errorMsgTemplate = "修改失败,[{}] 已存在";
|
||||
String username = req.getUsername();
|
||||
CheckUtils.throwIf(this.isNameExists(username, id), errorMsgTemplate, username);
|
||||
String email = req.getEmail();
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(email) && this.isEmailExists(email, id), errorMsgTemplate, email);
|
||||
String phone = req.getPhone();
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(phone) && this.isPhoneExists(phone, id), errorMsgTemplate, phone);
|
||||
DisEnableStatusEnum newStatus = req.getStatus();
|
||||
CheckUtils.throwIf(DisEnableStatusEnum.DISABLE.equals(newStatus) && ObjectUtil.equal(id, UserContextHolder
|
||||
.getUserId()), "不允许禁用当前用户");
|
||||
UserDO oldUser = super.getById(id);
|
||||
if (Boolean.TRUE.equals(oldUser.getIsSystem())) {
|
||||
CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, newStatus, "[{}] 是系统内置用户,不允许禁用", oldUser
|
||||
.getNickname());
|
||||
Collection<Long> disjunctionRoleIds = CollUtil.disjunction(req.getRoleIds(), userRoleService
|
||||
.listRoleIdByUserId(id));
|
||||
CheckUtils.throwIfNotEmpty(disjunctionRoleIds, "[{}] 是系统内置用户,不允许变更角色", oldUser.getNickname());
|
||||
}
|
||||
// 更新信息
|
||||
UserDO newUser = BeanUtil.toBean(req, UserDO.class);
|
||||
newUser.setId(id);
|
||||
baseMapper.updateById(newUser);
|
||||
// 保存用户和角色关联
|
||||
boolean isSaveUserRoleSuccess = userRoleService.add(req.getRoleIds(), id);
|
||||
// 如果禁用用户,则踢出在线用户
|
||||
if (DisEnableStatusEnum.DISABLE.equals(newStatus)) {
|
||||
onlineUserService.kickOut(id);
|
||||
return;
|
||||
}
|
||||
// 如果角色有变更,则更新在线用户权限信息
|
||||
if (isSaveUserRoleSuccess) {
|
||||
UserContext userContext = UserContextHolder.getContext(id);
|
||||
if (null != userContext) {
|
||||
userContext.setRoles(roleService.listByUserId(id));
|
||||
userContext.setPermissions(roleService.listPermissionByUserId(id));
|
||||
UserContextHolder.setContext(userContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@CacheInvalidate(key = "#ids", name = CacheConstants.USER_KEY_PREFIX, multi = true)
|
||||
public void delete(List<Long> ids) {
|
||||
CheckUtils.throwIf(CollUtil.contains(ids, UserContextHolder.getUserId()), "不允许删除当前用户");
|
||||
List<UserDO> list = baseMapper.lambdaQuery()
|
||||
.select(UserDO::getNickname, UserDO::getIsSystem)
|
||||
.in(UserDO::getId, ids)
|
||||
.list();
|
||||
Optional<UserDO> isSystemData = list.stream().filter(UserDO::getIsSystem).findFirst();
|
||||
CheckUtils.throwIf(isSystemData::isPresent, "所选用户 [{}] 是系统内置用户,不允许删除", isSystemData.orElseGet(UserDO::new)
|
||||
.getNickname());
|
||||
// 删除用户和角色关联
|
||||
userRoleService.deleteByUserIds(ids);
|
||||
// 删除历史密码
|
||||
userPasswordHistoryService.deleteByUserIds(ids);
|
||||
// 删除用户
|
||||
super.delete(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetPassword(UserPasswordResetReq req, Long id) {
|
||||
super.getById(id);
|
||||
@@ -515,25 +530,6 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
.in(CollUtil.isNotEmpty(userIdList), "t1.id", userIdList);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeAdd(UserReq req) {
|
||||
final String errorMsgTemplate = "新增失败,[{}] 已存在";
|
||||
String username = req.getUsername();
|
||||
CheckUtils.throwIf(this.isNameExists(username, null), errorMsgTemplate, username);
|
||||
String email = req.getEmail();
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(email) && this.isEmailExists(email, null), errorMsgTemplate, email);
|
||||
String phone = req.getPhone();
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(phone) && this.isPhoneExists(phone, null), errorMsgTemplate, phone);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterAdd(UserReq req, UserDO user) {
|
||||
Long userId = user.getId();
|
||||
baseMapper.lambdaUpdate().set(UserDO::getPwdResetTime, LocalDateTime.now()).eq(UserDO::getId, userId).update();
|
||||
// 保存用户和角色关联
|
||||
userRoleService.add(req.getRoleIds(), userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否跳过导入
|
||||
*
|
||||
@@ -617,12 +613,14 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤无效的导入用户数据,批量导入不严格校验数据
|
||||
* 过滤无效的导入用户数据(批量导入不严格校验数据)
|
||||
*
|
||||
* @param importRowList 导入数据
|
||||
*/
|
||||
private List<UserImportRowReq> filterErrorUserImportData(List<UserImportRowReq> userImportList) {
|
||||
private List<UserImportRowReq> filterImportData(List<UserImportRowReq> importRowList) {
|
||||
// 校验过滤
|
||||
List<UserImportRowReq> list = userImportList.stream()
|
||||
.filter(row -> ValidationUtil.validate(row).size() == 0)
|
||||
List<UserImportRowReq> list = importRowList.stream()
|
||||
.filter(row -> ValidationUtil.validate(row).isEmpty())
|
||||
.toList();
|
||||
// 用户名去重
|
||||
return list.stream()
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
LEFT JOIN sys_dept AS t2 ON t2.id = t1.dept_id
|
||||
</sql>
|
||||
|
||||
<select id="selectUserPage" resultType="top.continew.admin.system.model.resp.UserDetailResp">
|
||||
<select id="selectUserPage" resultType="top.continew.admin.system.model.resp.user.UserDetailResp">
|
||||
<include refid="selectUser" />
|
||||
${ew.customSqlSegment}
|
||||
</select>
|
||||
|
||||
<select id="selectUserList" resultType="top.continew.admin.system.model.resp.UserDetailResp">
|
||||
<select id="selectUserList" resultType="top.continew.admin.system.model.resp.user.UserDetailResp">
|
||||
<include refid="selectUser" />
|
||||
${ew.customSqlSegment}
|
||||
</select>
|
||||
|
||||
@@ -38,7 +38,7 @@ import top.continew.admin.common.constant.CacheConstants;
|
||||
import top.continew.admin.common.context.UserContext;
|
||||
import top.continew.admin.common.context.UserContextHolder;
|
||||
import top.continew.admin.common.util.SecureUtils;
|
||||
import top.continew.admin.system.model.resp.UserDetailResp;
|
||||
import top.continew.admin.system.model.resp.user.UserDetailResp;
|
||||
import top.continew.admin.system.service.UserService;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.core.util.ExceptionUtils;
|
||||
|
||||
@@ -35,12 +35,12 @@ import top.continew.admin.common.context.UserContextHolder;
|
||||
import top.continew.admin.common.util.SecureUtils;
|
||||
import top.continew.admin.system.enums.SocialSourceEnum;
|
||||
import top.continew.admin.system.model.entity.UserSocialDO;
|
||||
import top.continew.admin.system.model.req.UserBasicInfoUpdateReq;
|
||||
import top.continew.admin.system.model.req.UserEmailUpdateRequest;
|
||||
import top.continew.admin.system.model.req.UserPasswordUpdateReq;
|
||||
import top.continew.admin.system.model.req.UserPhoneUpdateReq;
|
||||
import top.continew.admin.system.model.req.user.UserBasicInfoUpdateReq;
|
||||
import top.continew.admin.system.model.req.user.UserEmailUpdateRequest;
|
||||
import top.continew.admin.system.model.req.user.UserPasswordUpdateReq;
|
||||
import top.continew.admin.system.model.req.user.UserPhoneUpdateReq;
|
||||
import top.continew.admin.system.model.resp.AvatarResp;
|
||||
import top.continew.admin.system.model.resp.UserSocialBindResp;
|
||||
import top.continew.admin.system.model.resp.user.UserSocialBindResp;
|
||||
import top.continew.admin.system.service.UserService;
|
||||
import top.continew.admin.system.service.UserSocialService;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
|
||||
@@ -32,14 +32,14 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.admin.common.constant.RegexConstants;
|
||||
import top.continew.admin.common.util.SecureUtils;
|
||||
import top.continew.admin.system.model.query.UserQuery;
|
||||
import top.continew.admin.system.model.req.UserImportReq;
|
||||
import top.continew.admin.system.model.req.UserPasswordResetReq;
|
||||
import top.continew.admin.system.model.req.UserReq;
|
||||
import top.continew.admin.system.model.req.UserRoleUpdateReq;
|
||||
import top.continew.admin.system.model.resp.UserDetailResp;
|
||||
import top.continew.admin.system.model.resp.UserImportParseResp;
|
||||
import top.continew.admin.system.model.resp.UserImportResp;
|
||||
import top.continew.admin.system.model.resp.UserResp;
|
||||
import top.continew.admin.system.model.req.user.UserImportReq;
|
||||
import top.continew.admin.system.model.req.user.UserPasswordResetReq;
|
||||
import top.continew.admin.system.model.req.user.UserReq;
|
||||
import top.continew.admin.system.model.req.user.UserRoleUpdateReq;
|
||||
import top.continew.admin.system.model.resp.user.UserDetailResp;
|
||||
import top.continew.admin.system.model.resp.user.UserImportParseResp;
|
||||
import top.continew.admin.system.model.resp.user.UserImportResp;
|
||||
import top.continew.admin.system.model.resp.user.UserResp;
|
||||
import top.continew.admin.system.service.UserService;
|
||||
import top.continew.starter.core.util.ExceptionUtils;
|
||||
import top.continew.starter.core.util.validate.ValidationUtils;
|
||||
@@ -83,24 +83,24 @@ public class UserController extends BaseController<UserService, UserResp, UserDe
|
||||
return super.add(req);
|
||||
}
|
||||
|
||||
@Operation(summary = "下载用户导入模板", description = "下载用户导入模板")
|
||||
@Operation(summary = "下载导入模板", description = "下载导入模板")
|
||||
@SaCheckPermission("system:user:import")
|
||||
@GetMapping(value = "downloadImportUserTemplate", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
public void downloadImportUserTemplate(HttpServletResponse response) throws IOException {
|
||||
userService.downloadImportUserTemplate(response);
|
||||
@GetMapping(value = "/import/template", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
|
||||
userService.downloadImportTemplate(response);
|
||||
}
|
||||
|
||||
@Operation(summary = "解析用户导入数据", description = "解析用户导入数据")
|
||||
@Operation(summary = "解析导入数据", description = "解析导入数据")
|
||||
@SaCheckPermission("system:user:import")
|
||||
@PostMapping(value = "parseImportUser")
|
||||
public UserImportParseResp parseImportUser(@NotNull(message = "文件不能为空") MultipartFile file) {
|
||||
@PostMapping("/import/parse")
|
||||
public UserImportParseResp parseImport(@NotNull(message = "文件不能为空") MultipartFile file) {
|
||||
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
|
||||
return userService.parseImportUser(file);
|
||||
return userService.parseImport(file);
|
||||
}
|
||||
|
||||
@Operation(summary = "导入用户", description = "导入用户")
|
||||
@Operation(summary = "导入数据", description = "导入数据")
|
||||
@SaCheckPermission("system:user:import")
|
||||
@PostMapping(value = "import")
|
||||
@PostMapping(value = "/import")
|
||||
public UserImportResp importUser(@Validated @RequestBody UserImportReq req) {
|
||||
return userService.importUser(req);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user