Compare commits

..

2 Commits

Author SHA1 Message Date
e4bf57f3ec feat(user): 增加用户角色管理功能
- 在 User 实体中添加 roles 字段,用于存储用户拥有的所有角色
- 在 UserCreateDto 中添加 roleIds 字段,用于创建用户时指定多个角色
- 修改 UserDetailsImpl以支持多个角色
- 新增 UserRolesRepository 接口,用于管理用户角色关联
- 更新 UserServiceImpl 中的 create 方法,支持创建用户时分配多个角色
2025-02-06 15:45:00 +08:00
7624d94145 feat(module): 添加操作日志模块
- 新增操作日志相关实体类、DTO、Mapper、Repository和服务接口
- 实现基本的操作日志记录功能
- 为后续的 SpEL 表达式解析和动态日志内容生成做准备
2025-02-06 15:02:55 +08:00
14 changed files with 266 additions and 20 deletions

View File

@ -2,15 +2,11 @@ package com.zsc.edu.gateway.framework.security;
import com.zsc.edu.gateway.common.util.TreeUtil;
import com.zsc.edu.gateway.exception.StateException;
import com.zsc.edu.gateway.modules.system.entity.Dept;
import com.zsc.edu.gateway.modules.system.entity.Menu;
import com.zsc.edu.gateway.modules.system.entity.RoleAuthority;
import com.zsc.edu.gateway.modules.system.entity.User;
import com.zsc.edu.gateway.modules.system.repo.AuthorityRepository;
import com.zsc.edu.gateway.modules.system.repo.MenuRepository;
import com.zsc.edu.gateway.modules.system.repo.RoleAuthoritiesRepository;
import com.zsc.edu.gateway.modules.system.repo.UserRepository;
import com.zsc.edu.gateway.modules.system.entity.*;
import com.zsc.edu.gateway.modules.system.repo.*;
import com.zsc.edu.gateway.modules.system.service.DeptService;
import com.zsc.edu.gateway.modules.system.service.RoleService;
import com.zsc.edu.gateway.modules.system.service.impl.RoleServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
@ -33,6 +29,9 @@ public class JpaUserDetailsServiceImpl implements UserDetailsService {
private final AuthorityRepository authorityRepository;
private final MenuRepository menuRepository;
private final DeptService deptService;
private final RoleRepository roleRepository;
private final RoleService roleService;
private final UserRolesRepository userRolesRepository;
@Override
@Transactional(rollbackFor = Exception.class)
@ -41,6 +40,9 @@ public class JpaUserDetailsServiceImpl implements UserDetailsService {
if (!user.getEnableState()) {
throw new StateException("用户 '" + username + "' 已被禁用!请联系管理员");
}
List<Long> roleIds = userRolesRepository.selectByUserId(user.getId());
List<Role> roles = roleRepository.selectByIds(roleIds);
user.setRoles(roles);
List<Dept> depts = deptService.listTree(user.deptId);
List<Dept> flat = TreeUtil.flat(depts, Dept::getChildren, d -> d.setChildren(null));
Set<Long> dataScopeDeptIds = flat.stream().map(Dept::getId).collect(Collectors.toSet());

View File

@ -11,6 +11,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@ -32,11 +33,12 @@ public class UserDetailsImpl implements UserDetails {
public String name;
public Dept dept;
public Role role;
public List<Role> roles;
public Set<Authority> authorities;
public Set<String> permissions;
public Set<Long> dataScopeDeptIds;
public UserDetailsImpl(Long id, String username, String password, String name, Boolean enableState, Dept dept, Set<Long> dataScopeDeptIds, Role role, Set<Authority> authorities, Set<String> permissions) {
public UserDetailsImpl(Long id, String username, String password, String name, Boolean enableState, Dept dept, Set<Long> dataScopeDeptIds, Role role, Set<Authority> authorities, Set<String> permissions, List<Role> roles) {
this.id = id;
this.username = username;
this.password = password;
@ -47,6 +49,7 @@ public class UserDetailsImpl implements UserDetails {
this.role = role;
this.authorities = authorities;
this.permissions = permissions;
this.roles = roles;
}
public static UserDetailsImpl from(User user, Set<String> permissions) {
@ -60,7 +63,8 @@ public class UserDetailsImpl implements UserDetails {
user.dataScopeDeptIds,
user.role,
user.role.authorities,
permissions
permissions,
user.roles
);
}

View File

@ -0,0 +1,36 @@
package com.zsc.edu.gateway.modules.operationLog.dto;
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* @author zhuang
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OperationLogDto {
/**
* 模块类型
*/
private OperationLog.ModelType modelType;
/**
* 操作类型
*/
private OperationLog.OperationType operationType;
/**
* 操作内容
*/
private String content;
/**
* 操作时间
*/
private LocalDateTime makeTime;
}

View File

@ -0,0 +1,19 @@
package com.zsc.edu.gateway.modules.operationLog.entity;
public class ExpressionRootObject {
private final Object object;
private final Object[] args;
public ExpressionRootObject(Object object, Object[] args) {
this.object = object;
this.args = args;
}
public Object getObject() {
return object;
}
public Object[] getArgs() {
return args;
}
}

View File

@ -0,0 +1,95 @@
package com.zsc.edu.gateway.modules.operationLog.entity;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.zsc.edu.gateway.common.enums.IState;
import lombok.*;
import java.time.LocalDateTime;
/**
* @author zhuang
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@TableName("operation_log")
public class OperationLog {
/**
* 主键
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 模块类型
*/
private ModelType modelType;
/**
* 操作类型
*/
private OperationType operationType;
/**
* 操作内容
*/
private String content;
/**
* 操作时间
*/
private LocalDateTime makeTime;
public enum ModelType implements IEnum<Integer>, IState<ModelType> {
ATTACHMENT(1, "附件模块"),
IOT(2, "物模型模块"),
MESSAGE(3, "公告消息模块"),
SYSTEM(4, "系统模块");
private final Integer value;
private final String name;
ModelType(int value, String name) {
this.value = value;
this.name = name;
}
@Override
public Integer getValue() {
return this.value;
}
@Override
public String toString() {
return this.name;
}
}
public enum OperationType implements IEnum<Integer>, IState<OperationType> {
CREATE(1, "添加"),
UPDATE(2, "更新"),
DELETE(3, "删除");
private final Integer value;
private final String name;
OperationType(int value, String name) {
this.value = value;
this.name = name;
}
@Override
public Integer getValue() {
return this.value;
}
@Override
public String toString() {
return this.name;
}
}
}

View File

@ -0,0 +1,16 @@
package com.zsc.edu.gateway.modules.operationLog.entity;
import java.lang.annotation.*;
/**
* @author zhuang
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationLogAnnotation {
/**
* 日志内容支持SpEL表达式
*/
String content() default "";
}

View File

@ -0,0 +1,15 @@
package com.zsc.edu.gateway.modules.operationLog.mapper;
import com.zsc.edu.gateway.common.mapstruct.BaseMapper;
import com.zsc.edu.gateway.modules.operationLog.dto.OperationLogDto;
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;
import org.mapstruct.ReportingPolicy;
/**
* @author zhuang
*/
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface OperationLogMapper extends BaseMapper<OperationLog, OperationLogDto> {
}

View File

@ -0,0 +1,7 @@
package com.zsc.edu.gateway.modules.operationLog.repo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
public interface OperationLogRepository extends BaseMapper<OperationLog> {
}

View File

@ -0,0 +1,7 @@
package com.zsc.edu.gateway.modules.operationLog.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
public interface OperationLogService extends IService<OperationLog> {
}

View File

@ -0,0 +1,16 @@
package com.zsc.edu.gateway.modules.operationLog.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
import com.zsc.edu.gateway.modules.operationLog.repo.OperationLogRepository;
import com.zsc.edu.gateway.modules.operationLog.service.OperationLogService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
/**
* @author zhuang
*/
@AllArgsConstructor
@Service
public class OperationLogServiceImpl extends ServiceImpl<OperationLogRepository, OperationLog> implements OperationLogService {
}

View File

@ -6,6 +6,8 @@ import lombok.NoArgsConstructor;
import jakarta.validation.constraints.*;
import java.util.Set;
/**
* 用户新建Dto
*
@ -53,7 +55,7 @@ public class UserCreateDto {
public Long deptId;
/**
* 用户身份集合
* 用户当前身份
*/
@NotEmpty(message = "角色不能为空")
public Long roleId;
@ -79,4 +81,8 @@ public class UserCreateDto {
*/
public Integer code;
/**
* 用户角色id集合
*/
public Set<Long> roleIds;
}

View File

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;
import java.util.List;
import java.util.Set;
/**
@ -77,6 +78,12 @@ public class User extends BaseEntity {
*/
@TableField(exist = false)
public Role role;
/**
* 拥有的所有角色
*/
@TableField(exist = false)
public List<Role> roles;
/**
* 头像
*/

View File

@ -2,9 +2,15 @@ package com.zsc.edu.gateway.modules.system.repo;
import com.zsc.edu.gateway.modules.system.entity.UserRole;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author zhuang
*/
public interface UserRolesRepository extends BaseMapper<UserRole> {
@Select("select role_id from sys_users_roles where user_id = #{userId}")
List<Long> selectByUserId(@Param("userId") Long userId);
}

View File

@ -9,15 +9,9 @@ import com.zsc.edu.gateway.modules.system.dto.UserCreateDto;
import com.zsc.edu.gateway.modules.system.dto.UserSelfUpdateDto;
import com.zsc.edu.gateway.modules.system.dto.UserSelfUpdatePasswordDto;
import com.zsc.edu.gateway.modules.system.dto.UserUpdateDto;
import com.zsc.edu.gateway.modules.system.entity.Menu;
import com.zsc.edu.gateway.modules.system.entity.Role;
import com.zsc.edu.gateway.modules.system.entity.RoleMenu;
import com.zsc.edu.gateway.modules.system.entity.User;
import com.zsc.edu.gateway.modules.system.entity.*;
import com.zsc.edu.gateway.modules.system.mapper.UserMapper;
import com.zsc.edu.gateway.modules.system.repo.MenuRepository;
import com.zsc.edu.gateway.modules.system.repo.RoleMenuRepository;
import com.zsc.edu.gateway.modules.system.repo.RoleRepository;
import com.zsc.edu.gateway.modules.system.repo.UserRepository;
import com.zsc.edu.gateway.modules.system.repo.*;
import com.zsc.edu.gateway.modules.system.service.MenuService;
import com.zsc.edu.gateway.modules.system.service.UserService;
import com.zsc.edu.gateway.modules.system.utils.sendMail;
@ -53,12 +47,28 @@ public class UserServiceImpl extends ServiceImpl<UserRepository, User> implement
private final RoleMenuRepository RoleMenuRepository;
private final RoleMenuRepository roleMenuRepository;
private final MenuRepository menuRepository;
private final UserRolesRepository userRolesRepository;
@Override
public Boolean create(UserCreateDto dto) {
User user = new User();
userMapper.convert(dto, user);
return save(user);
boolean saveSuccess = save(user);
if (!saveSuccess) {
return false;
}
if (dto.getRoleIds() != null && !dto.getRoleIds().isEmpty()) {
List<UserRole> userRoles = dto.getRoleIds().stream()
.map(roleId -> {
UserRole userRole = new UserRole();
userRole.setUserId(user.getId());
userRole.setRoleId(roleId);
return userRole;
})
.collect(Collectors.toList());
userRolesRepository.insert(userRoles);
}
return true;
}
@Override