【新增】 1、学生账号导入可以新增角色权限字段;2、教师账号导入新增

This commit is contained in:
DESKTOP-9ERGOBP\任维炳
2025-10-18 21:47:51 +08:00
parent 3dcadae6dd
commit 981fb9b466
8 changed files with 278 additions and 10 deletions

View File

@@ -231,13 +231,31 @@ public class UserController {
public void importTemplateStu(HttpServletResponse response) throws IOException {
// 手动创建导出 demo
List<UserStuImportExcelVO> list = Arrays.asList(
UserStuImportExcelVO.builder().userType("学生").username("xueshen").password("xxxxxxx").classId("三年二班").schoolName("xx学校").mobile("xxxxxxxx")
.nickname("xxxx").sfz("xxxxxxxxxxxxx").status(CommonStatusEnum.ENABLE.getStatus()).sex(SexEnum.MALE.getSex()).build()
UserStuImportExcelVO.builder().userType("学生").username("xueshen").password("不填写默认学生账号为登录用户名,直接为空即可").classId("三年二班").schoolName("xx学校").mobile("xxxxxxxx")
.nickname("xxxx").sfz("xxxxxxxxxxxxx").permission("系统中角色管理中名称").status(CommonStatusEnum.ENABLE.getStatus()).sex(SexEnum.MALE.getSex()).build()
);
// 输出
ExcelUtils.write(response, "学生导入模板.xls", "学生列表", UserStuImportExcelVO.class, list);
}
@GetMapping("/get-import-template-teacher")
@Operation(summary = "获得导入教师模板")
public void importTemplateTeacher(HttpServletResponse response) throws IOException {
// 手动创建导出 demo
List<UserTeacherImportExcelVO> list = Arrays.asList(
UserTeacherImportExcelVO.builder().userType("教师").username("jiaoshi").password("不填写默认教师账号为登录用户名,直接为空即可").classId("三年二班,三年三班,三年四班").mobile("xxxxxxxx").permission("系统中角色管理中名称")
.nickname("xxxx").professionalAuthority("[\n" +
" \"计算机专业\",\n" +
" [\n" +
" [\"Mysql\", [\"程序设计\"]],\n" +
" [\"C语言\", [\"编程题\"]]\n" +
" ]\n" +
"]").status(CommonStatusEnum.ENABLE.getStatus()).sex(SexEnum.MALE.getSex()).build()
);
// 输出
ExcelUtils.write(response, "教师导入模板.xls", "教师列表", UserTeacherImportExcelVO.class, list);
}
@PostMapping("/import")
@Operation(summary = "导入用户")
@Parameters({
@@ -263,6 +281,18 @@ public class UserController {
return success(userService.importUserStuList(list, updateSupport));
}
@PostMapping("/importTeacher")
@Operation(summary = "导入教师")
@Parameters({
@Parameter(name = "file", description = "Excel 文件", required = true),
@Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true")
})
public CommonResult<UserImportRespVO> importTeacherExcel(@RequestParam("file") MultipartFile file,
@RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception {
List<UserTeacherImportExcelVO> list = ExcelUtils.read(file, UserTeacherImportExcelVO.class);
return success(userService.importUserTeacherList(list, updateSupport));
}
@GetMapping("/getSpecialtListByUser")
@Operation(summary = "获取专业信息,判断用户类型")

View File

@@ -19,19 +19,19 @@ import pc.exam.pp.module.system.enums.DictTypeConstants;
@NoArgsConstructor
@Accessors(chain = false) // 设置 chain = false避免用户导入有问题
public class UserStuImportExcelVO {
@ExcelProperty("属性学生*")
@ExcelProperty("*属性(学生)")
private String userType;
@ExcelProperty("学生账号*")
@ExcelProperty("*学生账号")
private String username;
@ExcelProperty("密码")
private String password;
@ExcelProperty("姓名*")
@ExcelProperty("*姓名")
private String nickname;
@ExcelProperty("班级*")
@ExcelProperty("*班级")
private String classId;
@ExcelProperty("学校名称")
@@ -43,11 +43,14 @@ public class UserStuImportExcelVO {
@ExcelProperty("身份证")
private String sfz;
@ExcelProperty(value = "用户性别", converter = DictConvert.class)
@ExcelProperty("*学生权限名称")
private String permission;
@ExcelProperty(value = "性别", converter = DictConvert.class)
@DictFormat(DictTypeConstants.USER_SEX)
private Integer sex;
@ExcelProperty(value = "账号状态*", converter = DictConvert.class)
@ExcelProperty(value = "*账号状态(开启/关闭)", converter = DictConvert.class)
@DictFormat(DictTypeConstants.COMMON_STATUS)
private Integer status;

View File

@@ -0,0 +1,54 @@
package pc.exam.pp.module.system.controller.admin.user.vo.user;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import pc.exam.pp.framework.excel.core.annotations.DictFormat;
import pc.exam.pp.framework.excel.core.convert.DictConvert;
import pc.exam.pp.module.system.enums.DictTypeConstants;
/**
* 用户 Excel 导入 VO
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = false) // 设置 chain = false避免用户导入有问题
public class UserTeacherImportExcelVO {
@ExcelProperty("*属性(教师)")
private String userType;
@ExcelProperty("*教师账号")
private String username;
@ExcelProperty("密码")
private String password;
@ExcelProperty("*姓名")
private String nickname;
@ExcelProperty("*班级列表")
private String classId;
@ExcelProperty("手机号码")
private String mobile;
@ExcelProperty("*教师权限名称")
private String permission;
@ExcelProperty("*教师专业权限列表")
private String professionalAuthority;
@ExcelProperty(value = "性别", converter = DictConvert.class)
@DictFormat(DictTypeConstants.USER_SEX)
private Integer sex;
@ExcelProperty(value = "*账号状态(开启/关闭)", converter = DictConvert.class)
@DictFormat(DictTypeConstants.COMMON_STATUS)
private Integer status;
}

View File

@@ -1,6 +1,7 @@
package pc.exam.pp.module.system.dal.mysql.permission;
import pc.exam.pp.framework.mybatis.core.mapper.BaseMapperX;
import pc.exam.pp.module.system.dal.dataobject.permission.RoleDO;
import pc.exam.pp.module.system.dal.dataobject.permission.UserRoleDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper;

View File

@@ -1,6 +1,7 @@
package pc.exam.pp.module.system.service.permission;
import pc.exam.pp.module.system.api.permission.dto.DeptDataPermissionRespDTO;
import pc.exam.pp.module.system.dal.dataobject.permission.RoleDO;
import java.util.Collection;
import java.util.Set;
@@ -161,4 +162,6 @@ public interface PermissionService {
*/
DeptDataPermissionRespDTO getDeptDataPermission(Long userId);
RoleDO getRoleByName(String name);
}

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.extra.spring.SpringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import pc.exam.pp.framework.common.enums.CommonStatusEnum;
import pc.exam.pp.framework.common.util.collection.CollectionUtils;
import pc.exam.pp.framework.datapermission.core.annotation.DataPermission;
@@ -13,6 +14,7 @@ import pc.exam.pp.module.system.dal.dataobject.permission.RoleDO;
import pc.exam.pp.module.system.dal.dataobject.permission.RoleMenuDO;
import pc.exam.pp.module.system.dal.dataobject.permission.UserRoleDO;
import pc.exam.pp.module.system.dal.dataobject.user.TeacherSpecialtyDO;
import pc.exam.pp.module.system.dal.mysql.permission.RoleMapper;
import pc.exam.pp.module.system.dal.mysql.permission.RoleMenuMapper;
import pc.exam.pp.module.system.dal.mysql.permission.UserRoleMapper;
import pc.exam.pp.module.system.dal.mysql.user.TeacherSpecialtyMapper;
@@ -62,6 +64,8 @@ public class PermissionServiceImpl implements PermissionService {
private DeptService deptService;
@Resource
private AdminUserService userService;
@Resource
private RoleMapper roleMapper;
@Override
public boolean hasAnyPermissions(Long userId, String... permissions) {
@@ -348,6 +352,11 @@ public class PermissionServiceImpl implements PermissionService {
return result;
}
@Override
public RoleDO getRoleByName(String name) {
return roleMapper.selectByName(name);
}
/**
* 获得自身的代理对象,解决 AOP 生效问题
*

View File

@@ -251,6 +251,15 @@ public interface AdminUserService {
*/
UserImportRespVO importUserStuList(List<UserStuImportExcelVO> importUsers, boolean isUpdateSupport);
/**
* 批量导入教师
*
* @param importUsers 导入教师列表
* @param isUpdateSupport 是否支持更新
* @return 导入结果
*/
UserImportRespVO importUserTeacherList(List<UserTeacherImportExcelVO> importUsers, boolean isUpdateSupport);
/**
* 获得指定状态的用户们
*

View File

@@ -4,6 +4,8 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import pc.exam.pp.framework.common.enums.CommonStatusEnum;
import pc.exam.pp.framework.common.exception.ServiceException;
import pc.exam.pp.framework.common.pojo.PageResult;
@@ -29,11 +31,14 @@ import pc.exam.pp.module.system.controller.admin.user.vo.profile.UserProfileUpda
import pc.exam.pp.module.system.controller.admin.user.vo.user.*;
import pc.exam.pp.module.system.dal.dataobject.dept.DeptDO;
import pc.exam.pp.module.system.dal.dataobject.dept.UserPostDO;
import pc.exam.pp.module.system.dal.dataobject.permission.RoleDO;
import pc.exam.pp.module.system.dal.dataobject.permission.UserRoleDO;
import pc.exam.pp.module.system.dal.dataobject.tenant.TenantSpcialtyDO;
import pc.exam.pp.module.system.dal.dataobject.user.AdminUserDO;
import pc.exam.pp.module.system.dal.dataobject.user.TeacherClassDO;
import pc.exam.pp.module.system.dal.dataobject.user.TeacherSpecialtyDO;
import pc.exam.pp.module.system.dal.mysql.dept.UserPostMapper;
import pc.exam.pp.module.system.dal.mysql.permission.UserRoleMapper;
import pc.exam.pp.module.system.dal.mysql.tenant.TenantSpecialtyMapper;
import pc.exam.pp.module.system.dal.mysql.user.AdminUserMapper;
import pc.exam.pp.module.system.dal.mysql.user.TeacherClassMapper;
@@ -57,6 +62,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import static pc.exam.pp.framework.common.exception.util.ServiceExceptionUtil.exception;
import static pc.exam.pp.framework.common.util.collection.CollectionUtils.*;
@@ -105,6 +111,8 @@ public class AdminUserServiceImpl implements AdminUserService {
private ExamSpecialtyMapper examSpecialtyMapper;
@Resource
TenantSpecialtyMapper tenantSpecialtyMapper;
@Resource
private UserRoleMapper userRoleMapper;
@Override
@Transactional(rollbackFor = Exception.class)
@@ -753,6 +761,8 @@ public class AdminUserServiceImpl implements AdminUserService {
UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>())
.updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
importUsers.forEach(importUser -> {
// 权限名称
String permissionName = importUser.getPermission();
String password = "";
// 判断上传文件是否存在密码,如果存在密码,则使用密码,不存在密码,则使用用户名
if (importUser.getPassword() == null) {
@@ -767,6 +777,7 @@ public class AdminUserServiceImpl implements AdminUserService {
respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
return;
}
// 判断角色权限
// 2.1.2 校验,判断是否有不符合的原因
// try {
// validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(),
@@ -791,8 +802,17 @@ public class AdminUserServiceImpl implements AdminUserService {
// 2.2.1 判断如果不存在,在进行插入
AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername());
if (existUser == null) {
userMapper.insert(BeanUtils.toBean(importUser, AdminUserDO.class)
.setPassword(encodePassword(password)).setPostIds(new HashSet<>())); // 设置默认密码(如果没有密码填写username)及空岗位编号数组
AdminUserDO newUser = BeanUtils.toBean(importUser, AdminUserDO.class)
.setPassword(encodePassword(password)).setPostIds(new HashSet<>());
userMapper.insert(newUser); // 设置默认密码(如果没有密码填写username)及空岗位编号数组
// 获取权限ID
RoleDO roleDO = permissionService.getRoleByName(permissionName);
// 更新用户权限关联表
UserRoleDO userRoleDO = new UserRoleDO();
userRoleDO.setUserId(newUser.getId());
userRoleDO.setRoleId(roleDO.getId());
userRoleMapper.insert(userRoleDO);
// TODO
respVO.getCreateUsernames().add(importUser.getUsername());
return;
}
@@ -804,11 +824,150 @@ public class AdminUserServiceImpl implements AdminUserService {
AdminUserDO updateUser = BeanUtils.toBean(importUser, AdminUserDO.class);
updateUser.setId(existUser.getId());
userMapper.updateById(updateUser);
userRoleMapper.selectListByUserId(updateUser.getId()).forEach(role -> {
// 获取权限ID
RoleDO roleDO = permissionService.getRoleByName(permissionName);
// 更新用户权限关联表
role.setUserId(updateUser.getId());
role.setRoleId(roleDO.getId());
userRoleMapper.updateById(role);
});
respVO.getUpdateUsernames().add(importUser.getUsername());
});
return respVO;
}
@Override
public UserImportRespVO importUserTeacherList(List<UserTeacherImportExcelVO> importUsers, boolean isUpdateSupport) {
// 1.1 参数校验
if (CollUtil.isEmpty(importUsers)) {
throw exception(USER_IMPORT_LIST_IS_EMPTY);
}
// 1.2 初始化密码不能为空
String initPassword = configApi.getConfigValueByKey(USER_INIT_PASSWORD_KEY);
if (StrUtil.isEmpty(initPassword)) {
throw exception(USER_IMPORT_INIT_PASSWORD);
}
// 2. 遍历,逐个创建 or 更新
UserImportRespVO respVO = UserImportRespVO.builder().createUsernames(new ArrayList<>())
.updateUsernames(new ArrayList<>()).failureUsernames(new LinkedHashMap<>()).build();
importUsers.forEach(importUser -> {
String pro = importUser.getProfessionalAuthority();
ObjectMapper mapper = new ObjectMapper();
// 将字符串转换为 List 对象
// 权限名称
String permissionName = importUser.getPermission();
String password = "";
// 判断上传文件是否存在密码,如果存在密码,则使用密码,不存在密码,则使用用户名
if (importUser.getPassword() == null) {
password = importUser.getUsername();
} else {
password = importUser.getPassword();
}
// 2.1.1 校验字段是否符合要求
try {
ValidationUtils.validate(BeanUtils.toBean(importUser, UserSaveReqVO.class).setPassword(password));
} catch (ConstraintViolationException ex) {
respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
return;
}
// 判断角色权限
// 2.1.2 校验,判断是否有不符合的原因
// try {
// validateUserForCreateOrUpdate(null, null, importUser.getMobile(), importUser.getEmail(),
// importUser.getDeptId(), null);
// } catch (ServiceException ex) {
// respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
// return;
// }
// 教师 to 1
importUser.setUserType("1");
// 1.3 导入的报警是必须存在的,如果不存在不允许导入
String[] classNames = importUser.getClassId().split(",");
Set<Long> classIds = new HashSet<>();
boolean flagClassIds = true;
for (String className : classNames) {
// 通过名称查询班级ID
ClassDO classDO = classMapper.getClassNameOne(className);
if (classDO != null) {
classIds.add(classDO.getId());
} else {
flagClassIds = false;
respVO.getFailureUsernames().put(importUser.getUsername(), className + ":班级不存在!");
}
}
// 2.2.1 判断如果不存在,在进行插入
AdminUserDO existUser = userMapper.selectByUsername(importUser.getUsername());
if (existUser == null) {
importUser.setClassId(null);
AdminUserDO newUser = BeanUtils.toBean(importUser, AdminUserDO.class)
.setPassword(encodePassword(password)).setPostIds(new HashSet<>());
if (flagClassIds) {
newUser.setClassIds(classIds);
}
userMapper.insert(newUser); // 设置默认密码(如果没有密码填写username)及空岗位编号数组
try {
List<Object> data = mapper.readValue(pro, List.class);
// 提取数据
// 使用流式处理获取所有字段
List<String> allFields = flattenData(data);
System.out.println("所有字段 (" + allFields.size() + " 个):");
for (String field : allFields) {
TeacherSpecialtyDO teacherSpecialtyDO = new TeacherSpecialtyDO();
teacherSpecialtyDO.setUserId(newUser.getId());
teacherSpecialtyDO.setSpecialtyId(examSpecialtyMapper.selectExamSpecialtyBySpNameOne(field).getSpId());
teacherSpecialtyMapper.insert(teacherSpecialtyDO);
}
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
// 获取权限ID
RoleDO roleDO = permissionService.getRoleByName(permissionName);
// 更新用户权限关联表
UserRoleDO userRoleDO = new UserRoleDO();
userRoleDO.setUserId(newUser.getId());
userRoleDO.setRoleId(roleDO.getId());
userRoleMapper.insert(userRoleDO);
respVO.getCreateUsernames().add(importUser.getUsername());
return;
}
// 2.2.2 如果存在,判断是否允许更新
if (!isUpdateSupport) {
respVO.getFailureUsernames().put(importUser.getUsername(), USER_USERNAME_EXISTS.getMsg());
return;
}
AdminUserDO updateUser = BeanUtils.toBean(importUser, AdminUserDO.class);
updateUser.setId(existUser.getId());
updateUser.setClassIds(classIds);
userMapper.updateById(updateUser);
userRoleMapper.selectListByUserId(updateUser.getId()).forEach(role -> {
// 获取权限ID
RoleDO roleDO = permissionService.getRoleByName(permissionName);
// 更新用户权限关联表
role.setUserId(updateUser.getId());
role.setRoleId(roleDO.getId());
userRoleMapper.updateById(role);
});
respVO.getUpdateUsernames().add(importUser.getUsername());
});
return respVO;
}
/**
* 扁平化数据结构,获取所有字符串
*/
public static List<String> flattenData(Object obj) {
if (obj instanceof String) {
return Collections.singletonList((String) obj);
} else if (obj instanceof List) {
return ((List<?>) obj).stream()
.flatMap(item -> flattenData(item).stream())
.collect(Collectors.toList());
}
return Collections.emptyList();
}
@Override
public List<AdminUserDO> getUserListByStatus(Integer status) {