refactor all
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package com.imyeyu.api.modules.user.bean;
|
||||
|
||||
import com.imyeyu.api.TimiServerAPI;
|
||||
import com.imyeyu.api.bean.CoreRoleCode;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.modules.user.entity.Role;
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.api.modules.user.entity.UserRole;
|
||||
import com.imyeyu.api.modules.user.mapper.RoleMapper;
|
||||
import com.imyeyu.api.modules.user.mapper.UserMapper;
|
||||
import com.imyeyu.java.bean.timi.TimiCode;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 自举数据常量
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-06-07 10:42
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class BootstrapData {
|
||||
|
||||
/** System 用户名 */
|
||||
public static final String SYS_USER_NAME = "System";
|
||||
|
||||
/** System 用户昵称 */
|
||||
public static final String SYS_USER_NICK = "System";
|
||||
|
||||
/** System 角色代码 */
|
||||
public static final String SYS_ROLE_CODE = CoreRoleCode.SYSTEM.name();
|
||||
|
||||
/** 管理角色代码 */
|
||||
public static final String ADMIN_ROLE_CODE = CoreRoleCode.ADMIN.name();
|
||||
|
||||
/** System 角色模块 */
|
||||
public static final ModuleCode SYS_ROLE_MODULE_CODE = ModuleCode.CORE;
|
||||
|
||||
/** 管理角色模块 */
|
||||
public static final ModuleCode ADMIN_ROLE_MODULE_CODE = ModuleCode.CORE;
|
||||
|
||||
/** System 角色名称 */
|
||||
public static final String SYS_ROLE_NAME = CoreRoleCode.SYSTEM.getDefaultName();
|
||||
|
||||
/** 管理角色名称 */
|
||||
public static final String ADMIN_ROLE_NAME = CoreRoleCode.ADMIN.getDefaultName();
|
||||
|
||||
/** 自举权限代码集合 */
|
||||
public static final Set<String> PROTECTED_PERMISSION_CODE_SET = BuiltinAuthRegistry.SYSTEM_PERMISSION_CODE_SET;
|
||||
|
||||
public static boolean isProtectedRoleCode(ModuleCode moduleCode, String code) {
|
||||
return BuiltinAuthRegistry.isProtectedRole(moduleCode, code);
|
||||
}
|
||||
|
||||
public static void checkProtectedRoleCode(ModuleCode moduleCode, String code) {
|
||||
if (BootstrapData.isProtectedRoleCode(moduleCode, code)) {
|
||||
throw new TimiException(TimiCode.PERMISSION_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为自举权限
|
||||
*
|
||||
* @param code 权限码
|
||||
* @return 是否为自举权限
|
||||
*/
|
||||
public static boolean isProtectedPermissionCode(BuiltinPermissionCode code) {
|
||||
return code != null && code.isGrantToSystem();
|
||||
}
|
||||
|
||||
public static boolean isProtectedPermissionCode(String code) {
|
||||
return PROTECTED_PERMISSION_CODE_SET.contains(code);
|
||||
}
|
||||
|
||||
public static void checkProtectedPermissionCode(BuiltinPermissionCode code) {
|
||||
if (BootstrapData.isProtectedPermissionCode(code)) {
|
||||
throw new TimiException(TimiCode.PERMISSION_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isProtectedUserRole(UserRole userRole) {
|
||||
if (userRole == null) {
|
||||
return false;
|
||||
}
|
||||
UserMapper userMapper = TimiServerAPI.applicationContext.getBean(UserMapper.class);
|
||||
RoleMapper roleMapper = TimiServerAPI.applicationContext.getBean(RoleMapper.class);
|
||||
|
||||
User user = userMapper.select(userRole.getUserId());
|
||||
if (user == null || !BootstrapData.SYS_USER_NAME.equals(user.getName())) {
|
||||
return false;
|
||||
}
|
||||
Role role = roleMapper.select(userRole.getRoleId());
|
||||
return isProtectedRole(role);
|
||||
}
|
||||
|
||||
public static void checkProtectedUserRole(UserRole userRole) {
|
||||
if (BootstrapData.isProtectedUserRole(userRole)) {
|
||||
throw new TimiException(TimiCode.PERMISSION_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isProtectedRole(Role role) {
|
||||
return role != null && isProtectedRoleCode(role.getModuleCode(), role.getCode());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.imyeyu.api.modules.user.bean;
|
||||
|
||||
import com.imyeyu.api.bean.CorePermissionCode;
|
||||
import com.imyeyu.api.bean.CoreRoleCode;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
///
|
||||
/// 内建权限与角色注册中心
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-07-28
|
||||
public final class BuiltinAuthRegistry {
|
||||
|
||||
private BuiltinAuthRegistry() {
|
||||
}
|
||||
|
||||
/// 内建权限列表
|
||||
public static final List<BuiltinPermissionCode> PERMISSION_CODE_LIST = Stream.concat(
|
||||
Arrays.stream(CorePermissionCode.values()),
|
||||
Arrays.stream(GaoPermissionCode.values())
|
||||
).map(BuiltinPermissionCode.class::cast).toList();
|
||||
|
||||
/// 内建角色列表
|
||||
public static final List<BuiltinRoleCode> ROLE_CODE_LIST = Stream.concat(
|
||||
Arrays.stream(CoreRoleCode.values()),
|
||||
Arrays.stream(GaoRoleCode.values())
|
||||
).map(BuiltinRoleCode.class::cast).toList();
|
||||
|
||||
/// SYSTEM 角色必有权限集合
|
||||
public static final Set<String> SYSTEM_PERMISSION_CODE_SET = PERMISSION_CODE_LIST.stream()
|
||||
.filter(BuiltinPermissionCode::isGrantToSystem)
|
||||
.map(BuiltinPermissionCode::getValue)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
|
||||
/// 受保护角色集合
|
||||
public static final Set<String> PROTECTED_ROLE_KEY_SET = ROLE_CODE_LIST.stream()
|
||||
.filter(BuiltinRoleCode::isProtected)
|
||||
.map(item -> toRoleKey(item.getModuleCode(), ((Enum<?>) item).name()))
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
|
||||
public static String toRoleKey(ModuleCode moduleCode, String code) {
|
||||
return "%s:%s".formatted(moduleCode.name(), code);
|
||||
}
|
||||
|
||||
public static String toPermissionKey(ModuleCode moduleCode, String code) {
|
||||
return "%s:%s".formatted(moduleCode.name(), code);
|
||||
}
|
||||
|
||||
public static boolean isProtectedRole(ModuleCode moduleCode, String code) {
|
||||
return PROTECTED_ROLE_KEY_SET.contains(toRoleKey(moduleCode, code));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.imyeyu.api.modules.user.bean;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
|
||||
///
|
||||
/// 内建权限定义
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-07-28
|
||||
public interface BuiltinPermissionCode {
|
||||
|
||||
/// 权限模块
|
||||
///
|
||||
/// @return 模块代码
|
||||
ModuleCode getModuleCode();
|
||||
|
||||
/// 权限值
|
||||
///
|
||||
/// @return 权限值
|
||||
String getValue();
|
||||
|
||||
/// 默认名称
|
||||
///
|
||||
/// @return 默认名称
|
||||
String getDefaultName();
|
||||
|
||||
/// true 为初始化时授权给 SYSTEM 角色
|
||||
///
|
||||
/// @return 是否授权给 SYSTEM 角色
|
||||
boolean isGrantToSystem();
|
||||
|
||||
/// true 为初始化时授权给 ADMIN 角色
|
||||
///
|
||||
/// @return 是否授权给 ADMIN 角色
|
||||
boolean isGrantToAdmin();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.imyeyu.api.modules.user.bean;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
|
||||
///
|
||||
/// 内建角色定义
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-07-28
|
||||
public interface BuiltinRoleCode {
|
||||
|
||||
/// 角色模块
|
||||
///
|
||||
/// @return 模块代码
|
||||
ModuleCode getModuleCode();
|
||||
|
||||
/// 默认名称
|
||||
///
|
||||
/// @return 默认名称
|
||||
String getDefaultName();
|
||||
|
||||
/// true 为受保护角色
|
||||
///
|
||||
/// @return 是否受保护
|
||||
boolean isProtected();
|
||||
|
||||
/// 父角色代码
|
||||
///
|
||||
/// @return 父角色代码
|
||||
String getParentCode();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.imyeyu.api.modules.user.bean;
|
||||
|
||||
///
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-07-30 14:35
|
||||
public enum Gender {
|
||||
|
||||
MALE,
|
||||
|
||||
FEMALE,
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.imyeyu.api.modules.user.controller;
|
||||
|
||||
import com.imyeyu.api.annotation.RequireCorePermission;
|
||||
import com.imyeyu.api.annotation.RequireCoreRole;
|
||||
import com.imyeyu.api.bean.CorePermissionCode;
|
||||
import com.imyeyu.api.bean.CoreRoleCode;
|
||||
import com.imyeyu.api.modules.user.entity.Permission;
|
||||
import com.imyeyu.api.modules.user.service.PermissionService;
|
||||
import com.imyeyu.api.modules.user.vo.permission.BatchCreateReq;
|
||||
import com.imyeyu.spring.annotation.AOPLog;
|
||||
import com.imyeyu.spring.bean.Page;
|
||||
import com.imyeyu.spring.bean.PageResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 权限 SDK 控制器
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2025-11-02 09:54
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/user/permission")
|
||||
public class PermissionController {
|
||||
|
||||
private final PermissionService service;
|
||||
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.PERMISSION_READ)
|
||||
@PostMapping("/list")
|
||||
public PageResult<Permission> list(@RequestBody Page<Permission> page) {
|
||||
return service.page(page);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.PERMISSION_READ)
|
||||
@PostMapping("/create")
|
||||
public void create(@RequestBody Permission permission) {
|
||||
service.create(permission);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.PERMISSION_CREATE)
|
||||
@PostMapping("/create/batch")
|
||||
public void createBatch(@RequestBody BatchCreateReq req) {
|
||||
service.create(req);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.PERMISSION_UPDATE)
|
||||
@PostMapping("/update")
|
||||
public void update(@RequestBody Permission permission) {
|
||||
service.update(permission);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.PERMISSION_DELETE)
|
||||
@PostMapping("/delete")
|
||||
public void delete(@RequestParam("id") String id) {
|
||||
service.delete(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package com.imyeyu.api.modules.user.controller;
|
||||
|
||||
import com.imyeyu.api.annotation.RequireCorePermission;
|
||||
import com.imyeyu.api.annotation.RequireCoreRole;
|
||||
import com.imyeyu.api.bean.CorePermissionCode;
|
||||
import com.imyeyu.api.bean.CoreRoleCode;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.modules.user.entity.Permission;
|
||||
import com.imyeyu.api.modules.user.entity.Role;
|
||||
import com.imyeyu.api.modules.user.service.PermissionService;
|
||||
import com.imyeyu.api.modules.user.service.RoleService;
|
||||
import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeReq;
|
||||
import com.imyeyu.spring.annotation.AOPLog;
|
||||
import com.imyeyu.spring.bean.Page;
|
||||
import com.imyeyu.spring.bean.PageResult;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 角色 SDK 控制器
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2025-11-02 10:00
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/user/role")
|
||||
public class RoleController {
|
||||
|
||||
private final RoleService service;
|
||||
private final PermissionService permissionService;
|
||||
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.ROLE_READ)
|
||||
@PostMapping("/list")
|
||||
public PageResult<Role> list(@RequestBody Page<Role> page) {
|
||||
PageResult<Role> result = service.page(page);
|
||||
if (result.getList() != null) {
|
||||
result.getList().forEach(this::fillRoleDetail);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.ROLE_READ)
|
||||
@PostMapping("/detail")
|
||||
public Role detail(@RequestParam String id) {
|
||||
Role role = service.get(id);
|
||||
fillRoleDetail(role);
|
||||
return role;
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.ROLE_CREATE)
|
||||
@PostMapping("/create")
|
||||
public void create(@RequestBody Role role) {
|
||||
service.create(role);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.ROLE_UPDATE)
|
||||
@PostMapping("/update")
|
||||
public void update(@RequestBody Role role) {
|
||||
service.update(role);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.ROLE_DELETE)
|
||||
@PostMapping("/delete")
|
||||
public void delete(@RequestParam String id) {
|
||||
service.delete(id);
|
||||
}
|
||||
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.USER_ROLE_READ)
|
||||
@PostMapping("/authorized/list")
|
||||
public List<Role> listUserRole(@RequestParam String userId, @RequestParam(required = false) ModuleCode moduleCode) {
|
||||
if (moduleCode != null) {
|
||||
return service.listByUserId(userId, moduleCode);
|
||||
}
|
||||
return service.listByUserId(userId);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(value = {CorePermissionCode.USER_ROLE_CREATE, CorePermissionCode.USER_ROLE_DELETE})
|
||||
@PostMapping("/authorized/create")
|
||||
public void authorizeUserRole(@RequestBody UserRoleAuthorizeReq req) {
|
||||
service.authorizeUserRole(req);
|
||||
}
|
||||
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequireCorePermission(CorePermissionCode.USER_ROLE_READ)
|
||||
@PostMapping("/authorized/permission")
|
||||
public List<Permission> listAuthorizedPermission(@RequestParam String userId) {
|
||||
return service.listAllPermissionByUserId(userId);
|
||||
}
|
||||
|
||||
private void fillRoleDetail(Role role) {
|
||||
role.setPermissionList(permissionService.listByRoleId(role.getId()));
|
||||
role.setAllPermissionList(service.listPermissionByRoleId(role.getId()));
|
||||
role.setChildRoleList(service.listChildByParentRoleId(role.getId()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
package com.imyeyu.api.modules.user.controller;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.imyeyu.api.annotation.RequireCorePermission;
|
||||
import com.imyeyu.api.annotation.RequireCoreRole;
|
||||
import com.imyeyu.api.bean.CorePermissionCode;
|
||||
import com.imyeyu.api.bean.CoreRoleCode;
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||
import com.imyeyu.api.modules.common.vo.attach.BizUpdateReq;
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||
import com.imyeyu.api.modules.user.service.UserService;
|
||||
import com.imyeyu.api.modules.user.vo.CancelRequest;
|
||||
import com.imyeyu.api.modules.user.vo.LoginRequest;
|
||||
import com.imyeyu.api.modules.user.vo.LoginResponse;
|
||||
import com.imyeyu.api.modules.user.vo.PhoneVerifyCodeSendRequest;
|
||||
import com.imyeyu.api.modules.user.vo.PhoneVerifyRequest;
|
||||
import com.imyeyu.api.modules.user.vo.UpdatePasswordRequest;
|
||||
import com.imyeyu.spring.TimiSpring;
|
||||
import com.imyeyu.spring.annotation.AOPLog;
|
||||
import com.imyeyu.spring.annotation.CaptchaValid;
|
||||
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||
import com.imyeyu.spring.annotation.RequiredToken;
|
||||
import com.imyeyu.spring.bean.CaptchaData;
|
||||
import com.imyeyu.spring.bean.Page;
|
||||
import com.imyeyu.spring.bean.PageResult;
|
||||
import com.imyeyu.spring.util.ResponseView;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户接口
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2021-02-23 21:38
|
||||
*/
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/user")
|
||||
public class UserController {
|
||||
|
||||
private final UserService userService;
|
||||
private final UserLoginService userLoginService;
|
||||
private final AttachmentService attachmentService;
|
||||
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequestRateLimit
|
||||
@RequireCorePermission(CorePermissionCode.USER_READ)
|
||||
@PostMapping("/list")
|
||||
public PageResult<User> list(@RequestBody Page<User> page) {
|
||||
return userService.page(page);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequestRateLimit
|
||||
@RequireCorePermission(CorePermissionCode.USER_READ)
|
||||
@RequestMapping("/detail")
|
||||
public User detail(@RequestParam String id) {
|
||||
return userService.get(id);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequestRateLimit
|
||||
@RequireCorePermission(CorePermissionCode.USER_CREATE)
|
||||
@PostMapping("/create")
|
||||
public void create(@RequestBody User user) {
|
||||
userService.create(user);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequestRateLimit
|
||||
@RequireCorePermission(CorePermissionCode.USER_UPDATE)
|
||||
@PostMapping("/update")
|
||||
public void update(@RequestBody User user) {
|
||||
userService.update(user);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
||||
@RequestRateLimit
|
||||
@RequestMapping("/delete")
|
||||
public void delete(@RequestParam String id) {
|
||||
userService.delete(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
*/
|
||||
@AOPLog
|
||||
@JsonView(ResponseView.Public.class)
|
||||
@RequestRateLimit
|
||||
@CaptchaValid
|
||||
@PostMapping("/register")
|
||||
public LoginResponse register(@RequestBody @Valid CaptchaData<User> user) {
|
||||
userService.create(user.getData());
|
||||
// 登录
|
||||
LoginRequest loginRequest = new LoginRequest();
|
||||
loginRequest.setUser(user.getData().getName());
|
||||
loginRequest.setPassword(user.getData().getPassword());
|
||||
return userLoginService.login(loginRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
*
|
||||
* @param req 登录请求
|
||||
* @return 登录结果
|
||||
*/
|
||||
@AOPLog
|
||||
@JsonView(ResponseView.Public.class)
|
||||
@RequestRateLimit
|
||||
@PostMapping("/login")
|
||||
public LoginResponse login(@RequestBody @Valid CaptchaData<LoginRequest> req) {
|
||||
return userLoginService.login(req.getData());
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequiredToken
|
||||
@RequestRateLimit
|
||||
@RequestMapping("/login/token")
|
||||
public LoginResponse token() {
|
||||
return userLoginService.login(TimiSpring.getToken(), userLoginService.getRequireLoginUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新当前用户资料
|
||||
*
|
||||
* @param req 用户资料
|
||||
* @return 最新登录用户
|
||||
*/
|
||||
@AOPLog
|
||||
@RequiredToken
|
||||
@RequestRateLimit
|
||||
@RequireCorePermission(CorePermissionCode.USER_UPDATE)
|
||||
@PostMapping("/current/update")
|
||||
public LoginResponse updateCurrent(@RequestBody User req) {
|
||||
User loginUser = userLoginService.getRequireLoginUser();
|
||||
User user = userService.get(loginUser.getId());
|
||||
if (req.getName() != null) {
|
||||
user.setName(req.getName());
|
||||
}
|
||||
if (req.getNick() != null) {
|
||||
user.setNick(req.getNick());
|
||||
}
|
||||
if (req.getGender() != null) {
|
||||
user.setGender(req.getGender());
|
||||
}
|
||||
if (req.getDescription() != null) {
|
||||
user.setDescription(req.getDescription());
|
||||
}
|
||||
if (req.getAvatarType() != null) {
|
||||
user.setAvatarType(req.getAvatarType());
|
||||
}
|
||||
if (req.getWrapperType() != null) {
|
||||
user.setWrapperType(req.getWrapperType());
|
||||
}
|
||||
userService.update(user);
|
||||
updateCurrentAvatar(loginUser.getId(), req.getTempFileIdList());
|
||||
return userLoginService.login(TimiSpring.getToken(), loginUser.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登出
|
||||
*/
|
||||
@AOPLog
|
||||
@PostMapping("/logout")
|
||||
public void logout() {
|
||||
userLoginService.logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改当前用户密码
|
||||
*
|
||||
* @param req 修改密码请求
|
||||
*/
|
||||
@AOPLog
|
||||
@RequireCorePermission(CorePermissionCode.USER_UPDATE)
|
||||
@PostMapping("/update/password")
|
||||
public void updatePassword(@RequestBody @Valid UpdatePasswordRequest req) {
|
||||
userLoginService.updatePassword(req.getOldValue(), req.getNewValue());
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCorePermission(CorePermissionCode.USER_UPDATE)
|
||||
@PostMapping("/update/email")
|
||||
public void updateEmail() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送手机号验证码
|
||||
*
|
||||
* @param req 手机号验证码请求
|
||||
*/
|
||||
@AOPLog
|
||||
@RequiredToken
|
||||
@RequireCorePermission(CorePermissionCode.USER_UPDATE)
|
||||
@PostMapping("/phone/verify/send")
|
||||
public void sendPhoneCode(@RequestBody @Valid PhoneVerifyCodeSendRequest req) {
|
||||
userLoginService.sendPhoneVerifyCode(req.getPhoneNo());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证手机号
|
||||
*
|
||||
* @param req 手机号验证请求
|
||||
*/
|
||||
@AOPLog
|
||||
@RequiredToken
|
||||
@RequireCorePermission(CorePermissionCode.USER_UPDATE)
|
||||
@PostMapping("/phone/verify")
|
||||
public void verifyPhone(@RequestBody @Valid PhoneVerifyRequest req) {
|
||||
userLoginService.verifyPhoneNo(req.getPhoneNo(), req.getVerifyCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销当前用户
|
||||
*
|
||||
* @param req 注销请求
|
||||
*/
|
||||
@AOPLog
|
||||
@RequireCorePermission(CorePermissionCode.USER_DELETE)
|
||||
@PostMapping("/cancel")
|
||||
public void cancel(@RequestBody @Valid CancelRequest req) {
|
||||
userLoginService.deactivate(req.getPassword());
|
||||
}
|
||||
|
||||
private void updateCurrentAvatar(String userId, List<String> tempFileIdList) {
|
||||
if (tempFileIdList == null || tempFileIdList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
BizUpdateReq req = new BizUpdateReq();
|
||||
req.setBizType(Attachment.BizType.USER);
|
||||
req.setBizId(userId);
|
||||
List<Attachment> items = attachmentService.listByBizId(Attachment.BizType.USER, userId).stream()
|
||||
.filter(item -> !User.AttachType.AVATAR.name().equals(item.getAttachType()))
|
||||
.map(item -> {
|
||||
Attachment attachment = new Attachment();
|
||||
attachment.setId(item.getId());
|
||||
return attachment;
|
||||
})
|
||||
.toList();
|
||||
List<Attachment> avatarItems = tempFileIdList.stream().map(tempFileId -> {
|
||||
Attachment attachment = new Attachment();
|
||||
attachment.setTempFileId(tempFileId);
|
||||
attachment.setAttachTypeValue(User.AttachType.AVATAR);
|
||||
return attachment;
|
||||
}).toList();
|
||||
items = new ArrayList<>(items);
|
||||
items.addAll(avatarItems);
|
||||
req.setItems(items);
|
||||
attachmentService.updateByBiz(req);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.imyeyu.api.modules.user.entity;
|
||||
|
||||
import com.imyeyu.api.annotation.MultilingualField;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.spring.annotation.table.Transient;
|
||||
import com.imyeyu.spring.entity.UUIDEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 权限
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-13 14:40
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class Permission extends UUIDEntity {
|
||||
|
||||
/** 模块代码 */
|
||||
private ModuleCode moduleCode;
|
||||
|
||||
/** 代码 */
|
||||
private String code;
|
||||
|
||||
/** 名称多语言映射 ID */
|
||||
private String nameLangId;
|
||||
|
||||
/** 说明 */
|
||||
private String description;
|
||||
|
||||
@Transient
|
||||
@MultilingualField("nameLangId")
|
||||
private String name;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.imyeyu.api.modules.user.entity;
|
||||
|
||||
import com.imyeyu.api.annotation.MultilingualField;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.spring.annotation.table.Transient;
|
||||
import com.imyeyu.spring.entity.UUIDEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 角色
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-13 14:40
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class Role extends UUIDEntity {
|
||||
|
||||
/** 模块代码 */
|
||||
private ModuleCode moduleCode;
|
||||
|
||||
/** 代码 */
|
||||
private String code;
|
||||
|
||||
/** 名称 */
|
||||
private String nameLangId;
|
||||
|
||||
/** 说明 */
|
||||
private String description;
|
||||
|
||||
@Transient
|
||||
@MultilingualField("nameLangId")
|
||||
private String name;
|
||||
|
||||
/** 角色自身的权限列表,用于编辑 */
|
||||
@Transient
|
||||
protected List<Permission> permissionList;
|
||||
|
||||
/** 所有权限列表,包含从子角色继承的权限 */
|
||||
@Transient
|
||||
protected List<Permission> allPermissionList;
|
||||
|
||||
/** 子角色列表 */
|
||||
@Transient
|
||||
protected List<Role> childRoleList;
|
||||
|
||||
/** 权限 ID 列表 */
|
||||
@Transient
|
||||
protected Set<String> permissionIdList;
|
||||
|
||||
/** 子角色 ID 列表 */
|
||||
@Transient
|
||||
protected Set<String> childRoleIdList;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.imyeyu.api.modules.user.entity;
|
||||
|
||||
import com.imyeyu.api.modules.user.bean.BootstrapData;
|
||||
import com.imyeyu.spring.annotation.table.AutoUUID;
|
||||
import com.imyeyu.spring.annotation.table.DeleteColumn;
|
||||
import com.imyeyu.spring.annotation.table.Id;
|
||||
import com.imyeyu.spring.annotation.table.Transient;
|
||||
import com.imyeyu.spring.entity.Creatable;
|
||||
import com.imyeyu.spring.entity.Deletable;
|
||||
import com.imyeyu.spring.entity.IDEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 角色权限
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-13 14:40
|
||||
*/
|
||||
@Data
|
||||
public class RolePermission implements IDEntity<String>, Creatable, Deletable {
|
||||
|
||||
/** 主键 */
|
||||
@Id
|
||||
@AutoUUID
|
||||
protected String id;
|
||||
|
||||
/** 角色 ID */
|
||||
protected String roleId;
|
||||
|
||||
/** 权限 ID */
|
||||
protected String permissionId;
|
||||
|
||||
/** 创建时间 */
|
||||
protected Long createdAt;
|
||||
|
||||
/** 删除时间 */
|
||||
@DeleteColumn
|
||||
protected Long deletedAt;
|
||||
|
||||
@Transient
|
||||
protected Role role;
|
||||
|
||||
@Transient
|
||||
protected Permission permission;
|
||||
|
||||
public boolean isProtected() {
|
||||
return BootstrapData.isProtectedRole(role) && BootstrapData.isProtectedPermissionCode(permission.getCode());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.imyeyu.api.modules.user.entity;
|
||||
|
||||
import com.imyeyu.spring.annotation.table.AutoUUID;
|
||||
import com.imyeyu.spring.annotation.table.DeleteColumn;
|
||||
import com.imyeyu.spring.annotation.table.Id;
|
||||
import com.imyeyu.spring.entity.Creatable;
|
||||
import com.imyeyu.spring.entity.Deletable;
|
||||
import com.imyeyu.spring.entity.IDEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 角色关联
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-13 14:40
|
||||
*/
|
||||
@Data
|
||||
public class RoleRelation implements IDEntity<String>, Creatable, Deletable {
|
||||
|
||||
/** 主键 */
|
||||
@Id
|
||||
@AutoUUID
|
||||
private String id;
|
||||
|
||||
/** 上级角色 ID */
|
||||
private String parentRoleId;
|
||||
|
||||
/** 子级角色 ID */
|
||||
private String childRoleId;
|
||||
|
||||
/** 创建时间 */
|
||||
private Long createdAt;
|
||||
|
||||
/** 删除时间 */
|
||||
@DeleteColumn
|
||||
private Long deletedAt;
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package com.imyeyu.api.modules.user.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.imyeyu.api.modules.common.bean.ImageType;
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.api.modules.common.entity.Setting;
|
||||
import com.imyeyu.api.modules.user.bean.Gender;
|
||||
import com.imyeyu.spring.annotation.table.Transient;
|
||||
import com.imyeyu.spring.entity.UUIDEntity;
|
||||
import com.imyeyu.spring.util.ResponseView;
|
||||
import com.imyeyu.utils.Time;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2021-03-01 17:11
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class User extends UUIDEntity {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2024-02-21 14:48
|
||||
*/
|
||||
public enum AttachType {
|
||||
|
||||
AVATAR,
|
||||
|
||||
WRAPPER,
|
||||
|
||||
LICENSE,
|
||||
|
||||
DEFAULT_AVATAR,
|
||||
|
||||
DEFAULT_WRAPPER
|
||||
}
|
||||
|
||||
/** 用户名 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected String name;
|
||||
|
||||
/** 昵称 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected String nick;
|
||||
|
||||
/** 密码 */
|
||||
@JsonView(ResponseView.Admin.class)
|
||||
protected String password;
|
||||
|
||||
/** 邮箱 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected String email;
|
||||
|
||||
/** 邮箱验证时间 */
|
||||
@JsonView(ResponseView.Admin.class)
|
||||
protected Long emailVerifyAt;
|
||||
|
||||
/** 手机号 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected String phoneNo;
|
||||
|
||||
/** 手机号验证时间 */
|
||||
@JsonView(ResponseView.Admin.class)
|
||||
protected Long phoneNoVerifyAt;
|
||||
|
||||
/** 背景图渲染算法 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected ImageType wrapperType;
|
||||
|
||||
/** 头像渲染算法 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected ImageType avatarType;
|
||||
|
||||
/** 经验值 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected Integer exp;
|
||||
|
||||
/** 性别 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected Gender gender;
|
||||
|
||||
/** 出生日期 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected Long birthdate;
|
||||
|
||||
/** QQ */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected String qq;
|
||||
|
||||
/** 说明 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected String description;
|
||||
|
||||
/** 上次登录 IP */
|
||||
@JsonView(ResponseView.Admin.class)
|
||||
protected String lastLoginIP;
|
||||
|
||||
/** 上次登录时间 */
|
||||
@JsonView(ResponseView.Admin.class)
|
||||
protected Long lastLoginAt;
|
||||
|
||||
/** 解除禁言时间 */
|
||||
@JsonView(ResponseView.Admin.class)
|
||||
protected Long unmuteAt;
|
||||
|
||||
/** 解除封禁时间 */
|
||||
@JsonView(ResponseView.Admin.class)
|
||||
protected Long unbanAt;
|
||||
|
||||
@Transient
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected List<String> roleList;
|
||||
|
||||
@Transient
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected List<String> permissionList;
|
||||
|
||||
@Transient
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected List<Attachment> attachmentList;
|
||||
|
||||
@Transient
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected List<Setting> settingList;
|
||||
|
||||
@Transient
|
||||
@JsonView(ResponseView.Public.class)
|
||||
protected List<String> tempFileIdList;
|
||||
|
||||
/** @return true 为禁言中 */
|
||||
public boolean isMuting() {
|
||||
return unmuteAt != null && Time.now() < unmuteAt;
|
||||
}
|
||||
|
||||
/** @return true 为封禁中 */
|
||||
public boolean isBanning() {
|
||||
return unbanAt != null && Time.now() < unbanAt;
|
||||
}
|
||||
|
||||
public boolean isEmailVerified() {
|
||||
return emailVerifyAt != null;
|
||||
}
|
||||
|
||||
/** @return true 为手机号已验证 */
|
||||
public boolean isPhoneNoVerified() {
|
||||
return phoneNoVerifyAt != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.imyeyu.api.modules.user.entity;
|
||||
|
||||
import com.imyeyu.api.modules.common.entity.Comment;
|
||||
import com.imyeyu.spring.annotation.table.AutoUUID;
|
||||
import com.imyeyu.spring.annotation.table.DeleteColumn;
|
||||
import com.imyeyu.spring.annotation.table.Id;
|
||||
import com.imyeyu.spring.annotation.table.Transient;
|
||||
import com.imyeyu.spring.entity.Creatable;
|
||||
import com.imyeyu.spring.entity.Deletable;
|
||||
import com.imyeyu.spring.entity.IDEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户行为记录
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-27 17:10
|
||||
*/
|
||||
@Data
|
||||
public class UserBehaviorRecord implements IDEntity<String>, Creatable, Deletable {
|
||||
|
||||
/** 主键 */
|
||||
@Id
|
||||
@AutoUUID
|
||||
private String id;
|
||||
|
||||
/** 业务类型 */
|
||||
private String bizType;
|
||||
|
||||
/** 用户 ID */
|
||||
private String userId;
|
||||
|
||||
/** 目标类型 */
|
||||
private String targetType;
|
||||
|
||||
/** 目标 ID */
|
||||
private String targetId;
|
||||
|
||||
/** 行为类型 */
|
||||
private String actionType;
|
||||
|
||||
/** 创建时间 */
|
||||
private Long createdAt;
|
||||
|
||||
/** 删除时间 */
|
||||
@DeleteColumn
|
||||
private Long deletedAt;
|
||||
|
||||
/** 用户信息 */
|
||||
@Transient
|
||||
private User user;
|
||||
|
||||
/** 评论信息 */
|
||||
@Transient
|
||||
private Comment comment;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.imyeyu.api.modules.user.entity;
|
||||
|
||||
import com.imyeyu.spring.annotation.table.AutoUUID;
|
||||
import com.imyeyu.spring.annotation.table.DeleteColumn;
|
||||
import com.imyeyu.spring.annotation.table.Id;
|
||||
import com.imyeyu.spring.entity.Creatable;
|
||||
import com.imyeyu.spring.entity.Deletable;
|
||||
import com.imyeyu.spring.entity.IDEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户角色
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-13 14:40
|
||||
*/
|
||||
@Data
|
||||
public class UserRole implements IDEntity<String>, Creatable, Deletable {
|
||||
|
||||
/** 主键 */
|
||||
@Id
|
||||
@AutoUUID
|
||||
private String id;
|
||||
|
||||
/** 用户 ID */
|
||||
private String userId;
|
||||
|
||||
/** 角色 ID */
|
||||
private String roleId;
|
||||
|
||||
/** 创建时间 */
|
||||
private Long createdAt;
|
||||
|
||||
/** 删除时间 */
|
||||
@DeleteColumn
|
||||
private Long deletedAt;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.imyeyu.api.modules.user.mapper;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.Permission;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 权限 Mapper
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-13 14:46
|
||||
*/
|
||||
public interface PermissionMapper extends BaseMapper<Permission, String> {
|
||||
|
||||
List<Permission> selectByIdList(List<String> list);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.imyeyu.api.modules.user.mapper;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.modules.user.entity.Role;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 角色 Mapper
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-13 14:46
|
||||
*/
|
||||
public interface RoleMapper extends BaseMapper<Role, String> {
|
||||
|
||||
List<Role> selectByIdList(List<String> idList);
|
||||
|
||||
List<Role> selectByModuleCodeAndCodeList(@Param("moduleCode") ModuleCode moduleCode, @Param("codeList") List<String> codeList);
|
||||
|
||||
List<Role> selectByModuleCode(@Param("moduleCode") ModuleCode moduleCode);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.imyeyu.api.modules.user.mapper;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.Permission;
|
||||
import com.imyeyu.api.modules.user.entity.RolePermission;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 角色权限 Mapper
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-13 14:46
|
||||
*/
|
||||
public interface RolePermissionMapper extends BaseMapper<RolePermission, String> {
|
||||
|
||||
default List<RolePermission> selectByRoleId(String roleId) {
|
||||
return selectByRoleIdList(List.of(roleId));
|
||||
}
|
||||
|
||||
List<RolePermission> selectByRoleIdList(List<String> roleIdList);
|
||||
|
||||
List<Permission> selectPermissionByRoleIdList(List<String> roleIdList);
|
||||
|
||||
void createBatch(List<RolePermission> rolePermissionList);
|
||||
|
||||
void deleteByPermissionIdList(String roleId, List<String> permissionIdList);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.imyeyu.api.modules.user.mapper;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.RoleRelation;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 角色关联 Mapper
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-13 14:46
|
||||
*/
|
||||
public interface RoleRelationMapper extends BaseMapper<RoleRelation, String> {
|
||||
|
||||
List<RoleRelation> selectByParentRoleId(String parentRoleId);
|
||||
|
||||
List<String> selectChildRoleIdListByParentRoleId(String parentRoleId);
|
||||
|
||||
List<String> selectChildRoleIdListByParentRoleIdList(List<String> parentRoleIdList);
|
||||
|
||||
void createBatch(List<RoleRelation> roleRelationList);
|
||||
|
||||
void deleteByChildRoleIdList(String parentRoleId, List<String> childRoleIdList);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.imyeyu.api.modules.user.mapper;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.UserBehaviorRecord;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户行为记录 Mapper
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-27 17:10
|
||||
*/
|
||||
public interface UserBehaviorRecordMapper extends BaseMapper<UserBehaviorRecord, String> {
|
||||
|
||||
/**
|
||||
* 查询有效行为记录
|
||||
*
|
||||
* @param bizType 业务类型
|
||||
* @param userId 用户 ID
|
||||
* @param targetType 目标类型
|
||||
* @param targetId 目标 ID
|
||||
* @param actionType 行为类型
|
||||
* @return 行为记录,不存在时返回 {@code null}
|
||||
*/
|
||||
UserBehaviorRecord selectActive(String bizType, String userId, String targetType, String targetId, String actionType);
|
||||
|
||||
/**
|
||||
* 查询用户有效行为目标 ID 列表
|
||||
*
|
||||
* @param bizType 业务类型
|
||||
* @param userId 用户 ID
|
||||
* @param targetType 目标类型
|
||||
* @param actionType 行为类型
|
||||
* @param targetIdList 目标 ID 列表
|
||||
* @return 目标 ID 列表
|
||||
*/
|
||||
List<String> selectActiveTargetIdList(String bizType, String userId, String targetType, String actionType, List<String> targetIdList);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.imyeyu.api.modules.user.mapper;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2021-02-23 21:33
|
||||
*/
|
||||
public interface UserMapper extends BaseMapper<User, String> {
|
||||
|
||||
@Select("SELECT * FROM `user` WHERE `email` = #{email} AND `email_verify_at` IS NULL" + NOT_DELETE + LIMIT_1)
|
||||
User selectByEmail(String email);
|
||||
|
||||
@Select("SELECT * FROM `user` WHERE `email` = #{email} AND `email_verify_at` < " + UNIX_TIME + NOT_DELETE + LIMIT_1)
|
||||
User selectByVerifiedEmail(String email);
|
||||
|
||||
@Select("SELECT * FROM `user` WHERE `phone_no` = #{phoneNo}" + NOT_DELETE + LIMIT_1)
|
||||
User selectByPhoneNo(String phoneNo);
|
||||
|
||||
@Select("SELECT * FROM `user` WHERE `phone_no` = #{phoneNo} AND `phone_no_verify_at` < " + UNIX_TIME + NOT_DELETE + LIMIT_1)
|
||||
User selectByVerifiedPhoneNo(String phoneNo);
|
||||
|
||||
/**
|
||||
* 根据 ID 列表查询用户
|
||||
*
|
||||
* @param idList 用户 ID 列表
|
||||
* @return 用户列表
|
||||
*/
|
||||
List<User> listByIdList(List<String> idList);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.imyeyu.api.modules.user.mapper;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.UserRole;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户角色 Mapper
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-13 14:46
|
||||
*/
|
||||
public interface UserRoleMapper extends BaseMapper<UserRole, String> {
|
||||
|
||||
void createBatch(List<UserRole> userRoleList);
|
||||
|
||||
void deleteByRoleIdList(String userId, List<String> roleIdList);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.imyeyu.api.modules.user.service;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 权限检查器
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-06-05 17:45
|
||||
*/
|
||||
public interface PermissionChecker {
|
||||
|
||||
/**
|
||||
* 查询当前用户权限码集合
|
||||
*
|
||||
* @return 权限码集合
|
||||
*/
|
||||
Set<String> codeSet();
|
||||
|
||||
/**
|
||||
* 查询指定用户权限码集合
|
||||
*
|
||||
* @param userId 用户 ID
|
||||
* @return 权限码集合
|
||||
*/
|
||||
Set<String> codeSet(String userId);
|
||||
|
||||
/// 判断当前用户是否拥有全部权限
|
||||
///
|
||||
/// @param moduleCode 模块代码
|
||||
/// @param codeList 权限代码列表
|
||||
/// @return 是否拥有
|
||||
boolean hasAll(ModuleCode moduleCode, String... codeList);
|
||||
|
||||
/// 判断当前用户是否拥有任一权限
|
||||
///
|
||||
/// @param moduleCode 模块代码
|
||||
/// @param codeList 权限代码列表
|
||||
/// @return 是否拥有
|
||||
boolean hasAny(ModuleCode moduleCode, String... codeList);
|
||||
|
||||
/// 校验当前用户拥有全部权限
|
||||
///
|
||||
/// @param moduleCode 模块代码
|
||||
/// @param codeList 权限代码列表
|
||||
void checkAll(ModuleCode moduleCode, String... codeList);
|
||||
|
||||
/// 校验当前用户拥有任一权限
|
||||
///
|
||||
/// @param moduleCode 模块代码
|
||||
/// @param codeList 权限代码列表
|
||||
void checkAny(ModuleCode moduleCode, String... codeList);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.imyeyu.api.modules.user.service;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.Permission;
|
||||
import com.imyeyu.api.modules.user.vo.permission.BatchCreateReq;
|
||||
import com.imyeyu.spring.service.BaseService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/// 权限服务
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-05-13 14:46
|
||||
public interface PermissionService extends BaseService<Permission, String> {
|
||||
|
||||
/// 批量创建权限
|
||||
///
|
||||
/// @param req 批量创建请求
|
||||
void create(BatchCreateReq req);
|
||||
|
||||
/// 查询角色权限
|
||||
///
|
||||
/// @param roleId 角色 ID
|
||||
/// @return 权限列表
|
||||
default List<Permission> listByRoleId(String roleId) {
|
||||
return listByRoleId(List.of(roleId));
|
||||
}
|
||||
|
||||
/// 查询多个角色的权限并集
|
||||
///
|
||||
/// @param roleIdList 角色 ID 列表
|
||||
/// @return 权限列表
|
||||
List<Permission> listByRoleId(List<String> roleIdList);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.imyeyu.api.modules.user.service;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
///
|
||||
/// 角色检查器
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-06-05 17:45
|
||||
public interface RoleChecker {
|
||||
|
||||
/// 查询当前用户角色代码集合
|
||||
///
|
||||
/// @return 角色代码集合,格式为 MODULE:ROLE
|
||||
Set<String> codeSet();
|
||||
|
||||
/// 判断当前用户是否拥有全部角色
|
||||
///
|
||||
/// @param moduleCode 模块代码
|
||||
/// @param roleCodeList 角色代码列表
|
||||
/// @return 是否拥有
|
||||
boolean hasAll(ModuleCode moduleCode, String... roleCodeList);
|
||||
|
||||
/// 判断当前用户是否拥有任一角色
|
||||
///
|
||||
/// @param moduleCode 模块代码
|
||||
/// @param roleCodeList 角色代码列表
|
||||
/// @return 是否拥有
|
||||
boolean hasAny(ModuleCode moduleCode, String... roleCodeList);
|
||||
|
||||
/// 校验当前用户拥有全部角色
|
||||
///
|
||||
/// @param moduleCode 模块代码
|
||||
/// @param roleCodeList 角色代码列表
|
||||
void checkAll(ModuleCode moduleCode, String... roleCodeList);
|
||||
|
||||
/// 校验当前用户拥有任一角色
|
||||
///
|
||||
/// @param moduleCode 模块代码
|
||||
/// @param roleCodeList 角色代码列表
|
||||
void checkAny(ModuleCode moduleCode, String... roleCodeList);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.imyeyu.api.modules.user.service;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.RoleRelation;
|
||||
import com.imyeyu.spring.service.BaseService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/// 角色继承关系服务
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-05-13 14:46
|
||||
public interface RoleRelationService extends BaseService<RoleRelation, String> {
|
||||
|
||||
/// 查询直属子角色关联
|
||||
///
|
||||
/// @param parentRoleId 父角色 ID
|
||||
/// @return 角色关联列表
|
||||
List<RoleRelation> listByParentRoleId(String parentRoleId);
|
||||
|
||||
/// 查询直属子角色 ID 列表
|
||||
///
|
||||
/// @param parentRoleId 父角色 ID
|
||||
/// @return 子角色 ID 列表
|
||||
List<String> listChildRoleIdByParentRoleId(String parentRoleId);
|
||||
|
||||
/// 递归展开全部子角色 ID
|
||||
///
|
||||
/// @param parentRoleIdList 父角色 ID 列表
|
||||
/// @return 全部子角色 ID 列表
|
||||
List<String> listAllChildRoleIdByParentRoleIdList(List<String> parentRoleIdList);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.imyeyu.api.modules.user.service;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.modules.user.entity.Permission;
|
||||
import com.imyeyu.api.modules.user.entity.Role;
|
||||
import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeReq;
|
||||
import com.imyeyu.spring.service.BaseService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/// 角色服务
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-05-13 14:46
|
||||
public interface RoleService extends BaseService<Role, String> {
|
||||
|
||||
/// 给用户授权角色
|
||||
///
|
||||
/// @param req 用户角色授权请求
|
||||
void authorizeUserRole(UserRoleAuthorizeReq req);
|
||||
|
||||
/// 查询用户直属角色
|
||||
///
|
||||
/// @param userId 用户 ID
|
||||
/// @return 角色列表
|
||||
List<Role> listByUserId(String userId);
|
||||
|
||||
/// 查询用户指定模块直属角色
|
||||
///
|
||||
/// @param userId 用户 ID
|
||||
/// @param moduleCode 模块代码
|
||||
/// @return 角色列表
|
||||
List<Role> listByUserId(String userId, ModuleCode moduleCode);
|
||||
|
||||
/// 查询模块角色
|
||||
///
|
||||
/// @param moduleCode 模块代码
|
||||
/// @return 角色列表
|
||||
List<Role> listByModuleCode(ModuleCode moduleCode);
|
||||
|
||||
/// 查询用户直属角色编码
|
||||
///
|
||||
/// @param userId 用户 ID
|
||||
/// @return 角色编码列表,格式为 MODULE:ROLE
|
||||
default List<String> listCodeByUserId(String userId) {
|
||||
return listByUserId(userId).stream().map(role -> "%s:%s".formatted(role.getModuleCode().name(), role.getCode())).toList();
|
||||
}
|
||||
|
||||
/// 查询用户全部角色编码
|
||||
///
|
||||
/// @param userId 用户 ID
|
||||
/// @return 包含子角色的角色编码列表,格式为 MODULE:ROLE
|
||||
List<String> listAllCodeByUserId(String userId);
|
||||
|
||||
/// 查询用户全部权限
|
||||
///
|
||||
/// @param userId 用户 ID
|
||||
/// @return 权限列表
|
||||
List<Permission> listAllPermissionByUserId(String userId);
|
||||
|
||||
/// 查询用户全部权限编码
|
||||
///
|
||||
/// @param userId 用户 ID
|
||||
/// @return 权限编码列表,格式为 MODULE:PERMISSION
|
||||
default List<String> listAllPermissionCodeByUserId(String userId) {
|
||||
return listAllPermissionByUserId(userId).stream()
|
||||
.map(permission -> "%s:%s".formatted(permission.getModuleCode().name(), permission.getCode()))
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// 查询直属子角色
|
||||
///
|
||||
/// @param parentRoleId 父角色 ID
|
||||
/// @return 子角色列表
|
||||
List<Role> listChildByParentRoleId(String parentRoleId);
|
||||
|
||||
/// 查询角色全部权限
|
||||
///
|
||||
/// @param roleId 角色 ID
|
||||
/// @return 权限列表
|
||||
List<Permission> listPermissionByRoleId(String roleId);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.imyeyu.api.modules.user.service;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.UserBehaviorRecord;
|
||||
import com.imyeyu.spring.service.BaseService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户行为记录服务
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-27 17:10
|
||||
*/
|
||||
public interface UserBehaviorRecordService extends BaseService<UserBehaviorRecord, String> {
|
||||
|
||||
/**
|
||||
* 记录用户行为
|
||||
*
|
||||
* @param entity 行为记录
|
||||
* @return true 为新增记录
|
||||
*/
|
||||
boolean record(UserBehaviorRecord entity);
|
||||
|
||||
/**
|
||||
* 取消用户行为
|
||||
*
|
||||
* @param bizType 业务类型
|
||||
* @param userId 用户 ID
|
||||
* @param targetType 目标类型
|
||||
* @param targetId 目标 ID
|
||||
* @param actionType 行为类型
|
||||
* @return true 为已取消记录
|
||||
*/
|
||||
boolean cancel(String bizType, String userId, String targetType, String targetId, String actionType);
|
||||
|
||||
/**
|
||||
* 查询用户有效行为目标 ID 集合
|
||||
*
|
||||
* @param bizType 业务类型
|
||||
* @param userId 用户 ID
|
||||
* @param targetType 目标类型
|
||||
* @param actionType 行为类型
|
||||
* @param targetIdList 目标 ID 列表
|
||||
* @return 目标 ID 集合
|
||||
*/
|
||||
Set<String> getActiveTargetIdSet(String bizType, String userId, String targetType, String actionType, List<String> targetIdList);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.imyeyu.api.modules.user.service;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.api.modules.user.vo.LoginRequest;
|
||||
import com.imyeyu.api.modules.user.vo.LoginResponse;
|
||||
|
||||
/**
|
||||
* 用户登录服务
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-06-09
|
||||
*/
|
||||
public interface UserLoginService {
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
*
|
||||
* @param req 登录请求
|
||||
* @return 登录响应
|
||||
*/
|
||||
LoginResponse login(LoginRequest req);
|
||||
|
||||
LoginResponse login(String token, String userId);
|
||||
|
||||
/**
|
||||
* 根据令牌获取用户
|
||||
*
|
||||
* @return 用户
|
||||
*/
|
||||
User getLoginUser();
|
||||
|
||||
/**
|
||||
* 根据令牌获取必须有效登录的用户,否则抛出错误
|
||||
*
|
||||
* @return 用户
|
||||
*/
|
||||
User getRequireLoginUser();
|
||||
|
||||
default String getRequireLoginUserId() {
|
||||
return getRequireLoginUser().getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登出
|
||||
*
|
||||
*/
|
||||
void logout();
|
||||
|
||||
/**
|
||||
* 更新当前用户密码
|
||||
*
|
||||
*/
|
||||
void updatePassword(String oldPassword, String newPassword);
|
||||
|
||||
/**
|
||||
* 发送手机号验证码
|
||||
*
|
||||
* @param phoneNo 手机号
|
||||
*/
|
||||
void sendPhoneVerifyCode(String phoneNo);
|
||||
|
||||
/**
|
||||
* 验证当前用户手机号
|
||||
*
|
||||
* @param phoneNo 手机号
|
||||
* @param verifyCode 验证码
|
||||
*/
|
||||
void verifyPhoneNo(String phoneNo, String verifyCode);
|
||||
|
||||
/**
|
||||
* 注销当前用户
|
||||
*
|
||||
* @param password 当前密码
|
||||
*/
|
||||
void deactivate(String password);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.imyeyu.api.modules.user.service;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.UserRole;
|
||||
import com.imyeyu.spring.service.BaseService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/// 用户角色绑定服务
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-05-13 14:46
|
||||
public interface UserRoleService extends BaseService<UserRole, String> {
|
||||
|
||||
/// 批量创建用户角色绑定
|
||||
///
|
||||
/// @param list 用户角色绑定列表
|
||||
void createBatch(List<UserRole> list);
|
||||
|
||||
/// 查询用户角色绑定
|
||||
///
|
||||
/// @param userId 用户 ID
|
||||
/// @return 用户角色绑定列表
|
||||
List<UserRole> listByUserId(String userId);
|
||||
|
||||
/// 查询用户直属角色 ID
|
||||
///
|
||||
/// @param userId 用户 ID
|
||||
/// @return 角色 ID 列表
|
||||
default List<String> listRoleIdByUserId(String userId) {
|
||||
List<UserRole> bindingList = listByUserId(userId);
|
||||
return bindingList.stream().map(UserRole::getRoleId).toList();
|
||||
}
|
||||
|
||||
/// 删除用户指定角色绑定
|
||||
///
|
||||
/// @param userId 用户 ID
|
||||
/// @param roleIdList 角色 ID 列表
|
||||
void deleteByRoleIdList(String userId, List<String> roleIdList);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.imyeyu.api.modules.user.service;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.spring.service.BaseService;
|
||||
|
||||
/**
|
||||
* 用户管理服务
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2021-02-23 21:32
|
||||
*/
|
||||
public interface UserService extends BaseService<User, String> {
|
||||
|
||||
User getByName(String name);
|
||||
|
||||
User getByEmail(String email);
|
||||
|
||||
User getByVerifiedEmail(String email);
|
||||
|
||||
User getByPhoneNo(String phoneNo);
|
||||
|
||||
User getByVerifiedPhoneNo(String phoneNo);
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.imyeyu.api.modules.user.service.implement;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.modules.user.service.PermissionChecker;
|
||||
import com.imyeyu.api.modules.user.service.RoleService;
|
||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||
import com.imyeyu.java.bean.timi.TimiCode;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 权限检查器实现
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-06-05 17:45
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PermissionCheckerImplement implements PermissionChecker {
|
||||
|
||||
private final RoleService roleService;
|
||||
private final UserLoginService userLoginService;
|
||||
|
||||
public Set<String> codeSet() {
|
||||
return codeSet(userLoginService.getRequireLoginUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> codeSet(String userId) {
|
||||
return new HashSet<>(roleService.listAllPermissionCodeByUserId(userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAll(ModuleCode moduleCode, String... permissionCodeList) {
|
||||
Set<String> codeSet = codeSet();
|
||||
return Arrays.stream(permissionCodeList).allMatch(permissionCode -> codeSet.contains(buildPermissionKey(moduleCode, permissionCode)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAny(ModuleCode moduleCode, String... permissionCodeList) {
|
||||
Set<String> codeSet = codeSet();
|
||||
return Arrays.stream(permissionCodeList).anyMatch(permissionCode -> codeSet.contains(buildPermissionKey(moduleCode, permissionCode)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAll(ModuleCode moduleCode, String... permissionCodeList) {
|
||||
if (!hasAll(moduleCode, permissionCodeList)) {
|
||||
String codeList = buildPermissionKeys(moduleCode, permissionCodeList).toString();
|
||||
throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("权限不足:%s".formatted(codeList));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAny(ModuleCode moduleCode, String... permissionCodeList) {
|
||||
if (!hasAny(moduleCode, permissionCodeList)) {
|
||||
String codeList = buildPermissionKeys(moduleCode, permissionCodeList).toString();
|
||||
throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("权限不足:%s".formatted(codeList));
|
||||
}
|
||||
}
|
||||
|
||||
private String buildPermissionKey(ModuleCode moduleCode, String permissionCode) {
|
||||
return "%s:%s".formatted(moduleCode.name(), permissionCode);
|
||||
}
|
||||
|
||||
private Set<String> buildPermissionKeys(ModuleCode moduleCode, String... permissionCodeList) {
|
||||
return Arrays.stream(permissionCodeList).map(permissionCode -> buildPermissionKey(moduleCode, permissionCode)).collect(java.util.stream.Collectors.toSet());
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package com.imyeyu.api.modules.user.service.implement;
|
||||
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.modules.common.mapper.MultilingualMapper;
|
||||
import com.imyeyu.api.modules.common.service.MultilingualService;
|
||||
import com.imyeyu.api.modules.user.entity.Permission;
|
||||
import com.imyeyu.api.modules.user.mapper.PermissionMapper;
|
||||
import com.imyeyu.api.modules.user.mapper.RolePermissionMapper;
|
||||
import com.imyeyu.api.modules.user.service.PermissionService;
|
||||
import com.imyeyu.api.modules.user.vo.permission.BatchCreateReq;
|
||||
import com.imyeyu.api.util.RedisMultilingual;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.spring.TimiSpring;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import com.imyeyu.spring.service.AbstractEntityService;
|
||||
import com.imyeyu.utils.Time;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/// 权限服务实现
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-05-13 14:46
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PermissionServiceImplement extends AbstractEntityService<Permission, String> implements PermissionService {
|
||||
|
||||
private final PermissionMapper mapper;
|
||||
private final RolePermissionMapper rolePermissionMapper;
|
||||
|
||||
private final MultilingualMapper multilingualMapper;
|
||||
private final MultilingualService multilingualService;
|
||||
private final RedisMultilingual multilingual;
|
||||
|
||||
@Override
|
||||
protected BaseMapper<Permission, String> mapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void create(Permission permission) {
|
||||
permission.setNameLangId(multilingualService.create(permission.getName()));
|
||||
super.create(permission);
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void create(BatchCreateReq req) {
|
||||
if (TimiJava.isEmpty(req.getTypes())) {
|
||||
return;
|
||||
}
|
||||
List<Permission> permissionList = new ArrayList<>();
|
||||
for (BatchCreateReq.Type type : req.getTypes()) {
|
||||
Permission permission = new Permission();
|
||||
permission.setId(UUID.randomUUID().toString());
|
||||
permission.setModuleCode(req.getModuleCode());
|
||||
permission.setCode(req.getPrefixCode() + "_" + type.name());
|
||||
permission.setName(req.getPrefixName() + multilingual.map(TimiSpring.getLanguage()).text(type.name().toLowerCase()));
|
||||
permission.setCreatedAt(Time.now());
|
||||
permissionList.add(permission);
|
||||
}
|
||||
for (Permission permission : permissionList) {
|
||||
super.create(permission);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void update(Permission permission) {
|
||||
permission.setNameLangId(multilingualService.createIfDifferent(permission.getNameLangId(), permission.getName()));
|
||||
mapper.updateSelective(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Permission> listByRoleId(List<String> roleIdList) {
|
||||
if (TimiJava.isEmpty(roleIdList)) {
|
||||
return List.of();
|
||||
}
|
||||
return rolePermissionMapper.selectPermissionByRoleIdList(roleIdList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.imyeyu.api.modules.user.service.implement;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.modules.user.service.RoleChecker;
|
||||
import com.imyeyu.api.modules.user.service.RoleService;
|
||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||
import com.imyeyu.java.bean.timi.TimiCode;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
///
|
||||
/// 角色检查器实现
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-06-05 17:45
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RoleCheckerImplement implements RoleChecker {
|
||||
|
||||
private final RoleService roleService;
|
||||
private final UserLoginService userLoginService;
|
||||
|
||||
@Override
|
||||
public Set<String> codeSet() {
|
||||
return new HashSet<>(roleService.listAllCodeByUserId(userLoginService.getRequireLoginUserId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAll(ModuleCode moduleCode, String... roleCodeList) {
|
||||
Set<String> codeSet = codeSet();
|
||||
return Arrays.stream(roleCodeList).allMatch(roleCode -> codeSet.contains(buildRoleKey(moduleCode, roleCode)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAny(ModuleCode moduleCode, String... roleCodeList) {
|
||||
Set<String> codeSet = codeSet();
|
||||
return Arrays.stream(roleCodeList).anyMatch(roleCode -> codeSet.contains(buildRoleKey(moduleCode, roleCode)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAll(ModuleCode moduleCode, String... roleCodeList) {
|
||||
if (!hasAll(moduleCode, roleCodeList)) {
|
||||
throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("require role: %s".formatted(buildRoleKeys(moduleCode, roleCodeList)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAny(ModuleCode moduleCode, String... roleCodeList) {
|
||||
if (!hasAny(moduleCode, roleCodeList)) {
|
||||
throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("require role: %s".formatted(buildRoleKeys(moduleCode, roleCodeList)));
|
||||
}
|
||||
}
|
||||
|
||||
private String buildRoleKey(ModuleCode moduleCode, String roleCode) {
|
||||
return "%s:%s".formatted(moduleCode.name(), roleCode);
|
||||
}
|
||||
|
||||
private Set<String> buildRoleKeys(ModuleCode moduleCode, String... roleCodeList) {
|
||||
return Arrays.stream(roleCodeList).map(roleCode -> buildRoleKey(moduleCode, roleCode)).collect(java.util.stream.Collectors.toSet());
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package com.imyeyu.api.modules.user.service.implement;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.RoleRelation;
|
||||
import com.imyeyu.api.modules.user.mapper.RoleRelationMapper;
|
||||
import com.imyeyu.api.modules.user.service.RoleRelationService;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import com.imyeyu.spring.service.AbstractEntityService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/// 角色关联服务实现
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-05-13 14:46
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RoleRelationServiceImplement extends AbstractEntityService<RoleRelation, String> implements RoleRelationService {
|
||||
|
||||
private final RoleRelationMapper mapper;
|
||||
|
||||
@Override
|
||||
protected BaseMapper<RoleRelation, String> mapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RoleRelation> listByParentRoleId(String parentRoleId) {
|
||||
if (TimiJava.isEmpty(parentRoleId)) {
|
||||
return List.of();
|
||||
}
|
||||
RoleRelation example = new RoleRelation();
|
||||
example.setParentRoleId(parentRoleId);
|
||||
return mapper.selectAllByExample(example);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listChildRoleIdByParentRoleId(String parentRoleId) {
|
||||
return listByParentRoleId(parentRoleId).stream().map(RoleRelation::getChildRoleId).distinct().toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listAllChildRoleIdByParentRoleIdList(List<String> parentRoleIdList) {
|
||||
if (TimiJava.isEmpty(parentRoleIdList)) {
|
||||
return List.of();
|
||||
}
|
||||
Set<String> result = new HashSet<>();
|
||||
List<String> currentRoleIdList = new ArrayList<>(parentRoleIdList);
|
||||
while (TimiJava.isNotEmpty(currentRoleIdList)) {
|
||||
List<String> childRoleIdList = currentRoleIdList.stream()
|
||||
.flatMap(roleId -> listChildRoleIdByParentRoleId(roleId).stream())
|
||||
.filter(childRoleId -> !result.contains(childRoleId))
|
||||
.distinct()
|
||||
.toList();
|
||||
if (TimiJava.isEmpty(childRoleIdList)) {
|
||||
break;
|
||||
}
|
||||
result.addAll(childRoleIdList);
|
||||
currentRoleIdList = childRoleIdList;
|
||||
}
|
||||
return new ArrayList<>(result);
|
||||
}
|
||||
}
|
||||
+294
@@ -0,0 +1,294 @@
|
||||
package com.imyeyu.api.modules.user.service.implement;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.modules.common.entity.Multilingual;
|
||||
import com.imyeyu.api.modules.common.mapper.MultilingualMapper;
|
||||
import com.imyeyu.api.modules.common.service.MultilingualService;
|
||||
import com.imyeyu.api.modules.user.entity.Permission;
|
||||
import com.imyeyu.api.modules.user.entity.Role;
|
||||
import com.imyeyu.api.modules.user.entity.RolePermission;
|
||||
import com.imyeyu.api.modules.user.entity.RoleRelation;
|
||||
import com.imyeyu.api.modules.user.entity.UserRole;
|
||||
import com.imyeyu.api.modules.user.mapper.RoleMapper;
|
||||
import com.imyeyu.api.modules.user.mapper.RolePermissionMapper;
|
||||
import com.imyeyu.api.modules.user.mapper.RoleRelationMapper;
|
||||
import com.imyeyu.api.modules.user.service.PermissionService;
|
||||
import com.imyeyu.api.modules.user.service.RoleService;
|
||||
import com.imyeyu.api.modules.user.service.UserRoleService;
|
||||
import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeReq;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.java.bean.timi.TimiCode;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import com.imyeyu.spring.service.AbstractEntityService;
|
||||
import com.imyeyu.utils.Time;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/// 角色服务实现
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-05-13 14:46
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RoleServiceImplement extends AbstractEntityService<Role, String> implements RoleService {
|
||||
|
||||
private final UserRoleService userRoleService;
|
||||
private final PermissionService permissionService;
|
||||
private final MultilingualMapper multilingualMapper;
|
||||
private final MultilingualService multilingualService;
|
||||
|
||||
private final RoleMapper mapper;
|
||||
private final RoleRelationMapper roleRelationMapper;
|
||||
private final RolePermissionMapper rolePermissionMapper;
|
||||
|
||||
@Override
|
||||
protected BaseMapper<Role, String> mapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void create(Role role) {
|
||||
role.setNameLangId(multilingualService.create(role.getName()));
|
||||
super.create(role);
|
||||
|
||||
if (TimiJava.isNotEmpty(role.getPermissionIdList())) {
|
||||
List<RolePermission> rolePermissionList = new ArrayList<>();
|
||||
long now = Time.now();
|
||||
for (String permissionId : role.getPermissionIdList()) {
|
||||
RolePermission rolePermission = new RolePermission();
|
||||
rolePermission.setId(UUID.randomUUID().toString());
|
||||
rolePermission.setRoleId(role.getId());
|
||||
rolePermission.setPermissionId(permissionId);
|
||||
rolePermission.setCreatedAt(now);
|
||||
rolePermissionList.add(rolePermission);
|
||||
}
|
||||
rolePermissionMapper.createBatch(rolePermissionList);
|
||||
}
|
||||
|
||||
if (TimiJava.isNotEmpty(role.getChildRoleIdList())) {
|
||||
List<RoleRelation> roleRelationList = new ArrayList<>();
|
||||
long now = Time.now();
|
||||
for (String childRoleId : role.getChildRoleIdList()) {
|
||||
RoleRelation roleRelation = new RoleRelation();
|
||||
roleRelation.setId(UUID.randomUUID().toString());
|
||||
roleRelation.setParentRoleId(role.getId());
|
||||
roleRelation.setChildRoleId(childRoleId);
|
||||
roleRelation.setCreatedAt(now);
|
||||
roleRelationList.add(roleRelation);
|
||||
}
|
||||
roleRelationMapper.createBatch(roleRelationList);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void update(Role role) {
|
||||
role.setNameLangId(multilingualService.createIfDifferent(role.getNameLangId(), role.getName()));
|
||||
mapper.updateSelective(role);
|
||||
{
|
||||
Set<String> dbIdSet = rolePermissionMapper.selectByRoleId(role.getId()).stream().map(RolePermission::getPermissionId).collect(Collectors.toSet());
|
||||
Set<String> newIdSet = TimiJava.defaultIfEmpty(new HashSet<>(role.getPermissionIdList()), new HashSet<>());
|
||||
|
||||
Set<String> deleteIdList = new HashSet<>(dbIdSet);
|
||||
deleteIdList.removeAll(newIdSet);
|
||||
|
||||
Set<String> addIdList = new HashSet<>(newIdSet);
|
||||
addIdList.removeAll(dbIdSet);
|
||||
|
||||
if (TimiJava.isNotEmpty(deleteIdList)) {
|
||||
rolePermissionMapper.deleteByPermissionIdList(role.getId(), new ArrayList<>(deleteIdList));
|
||||
}
|
||||
if (TimiJava.isNotEmpty(addIdList)) {
|
||||
List<RolePermission> rolePermissionList = new ArrayList<>();
|
||||
long now = Time.now();
|
||||
for (String permissionId : addIdList) {
|
||||
RolePermission rolePermission = new RolePermission();
|
||||
rolePermission.setId(UUID.randomUUID().toString());
|
||||
rolePermission.setRoleId(role.getId());
|
||||
rolePermission.setPermissionId(permissionId);
|
||||
rolePermission.setCreatedAt(now);
|
||||
rolePermissionList.add(rolePermission);
|
||||
}
|
||||
rolePermissionMapper.createBatch(rolePermissionList);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Set<String> dbIdSet = roleRelationMapper.selectByParentRoleId(role.getId()).stream().map(RoleRelation::getChildRoleId).collect(Collectors.toSet());
|
||||
Set<String> newIdSet = TimiJava.defaultIfEmpty(new HashSet<>(role.getChildRoleIdList()), new HashSet<>());
|
||||
|
||||
Set<String> deleteIdList = new HashSet<>(dbIdSet);
|
||||
deleteIdList.removeAll(newIdSet);
|
||||
|
||||
Set<String> addIdList = new HashSet<>(newIdSet);
|
||||
addIdList.removeAll(dbIdSet);
|
||||
|
||||
if (TimiJava.isNotEmpty(deleteIdList)) {
|
||||
roleRelationMapper.deleteByChildRoleIdList(role.getId(), new ArrayList<>(deleteIdList));
|
||||
}
|
||||
if (TimiJava.isNotEmpty(addIdList)) {
|
||||
List<RoleRelation> roleRelationList = new ArrayList<>();
|
||||
long now = Time.now();
|
||||
for (String childRoleId : addIdList) {
|
||||
RoleRelation roleRelation = new RoleRelation();
|
||||
roleRelation.setId(UUID.randomUUID().toString());
|
||||
roleRelation.setParentRoleId(role.getId());
|
||||
roleRelation.setChildRoleId(childRoleId);
|
||||
roleRelation.setCreatedAt(now);
|
||||
roleRelationList.add(roleRelation);
|
||||
}
|
||||
roleRelationMapper.createBatch(roleRelationList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void authorizeUserRole(UserRoleAuthorizeReq req) {
|
||||
TimiException.required(req, "not found req");
|
||||
TimiException.required(req.getUserId(), "not found req.userId");
|
||||
if (req.getModuleCode() == null) {
|
||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("moduleCode");
|
||||
}
|
||||
List<UserRole> bindingList = userRoleService.listByUserId(req.getUserId());
|
||||
List<String> bindingRoleIdList = bindingList.stream().map(UserRole::getRoleId).toList();
|
||||
Set<String> dbIdSet = mapper.selectByIdList(bindingRoleIdList).stream()
|
||||
.filter(role -> req.getModuleCode() == role.getModuleCode())
|
||||
.map(Role::getId)
|
||||
.collect(Collectors.toSet());
|
||||
Set<String> newIdSet = new HashSet<>();
|
||||
if (TimiJava.isNotEmpty(req.getRoleIdList())) {
|
||||
newIdSet.addAll(mapper.selectByIdList(req.getRoleIdList()).stream()
|
||||
.filter(role -> req.getModuleCode() == role.getModuleCode())
|
||||
.map(Role::getId)
|
||||
.toList());
|
||||
}
|
||||
if (TimiJava.isNotEmpty(req.getRoleCodeList())) {
|
||||
newIdSet.addAll(mapper.selectByModuleCodeAndCodeList(req.getModuleCode(), req.getRoleCodeList()).stream().map(Role::getId).toList());
|
||||
}
|
||||
Set<String> deleteIdList = new HashSet<>(dbIdSet);
|
||||
deleteIdList.removeAll(newIdSet);
|
||||
|
||||
Set<String> addIdList = new HashSet<>(newIdSet);
|
||||
addIdList.removeAll(dbIdSet);
|
||||
|
||||
if (TimiJava.isNotEmpty(deleteIdList)) {
|
||||
userRoleService.deleteByRoleIdList(req.getUserId(), new ArrayList<>(deleteIdList));
|
||||
}
|
||||
if (TimiJava.isNotEmpty(addIdList)) {
|
||||
List<UserRole> roleBindingList = new ArrayList<>();
|
||||
long now = Time.now();
|
||||
for (String roleId : addIdList) {
|
||||
UserRole roleBinding = new UserRole();
|
||||
roleBinding.setId(UUID.randomUUID().toString());
|
||||
roleBinding.setUserId(req.getUserId());
|
||||
roleBinding.setRoleId(roleId);
|
||||
roleBinding.setCreatedAt(now);
|
||||
roleBindingList.add(roleBinding);
|
||||
}
|
||||
userRoleService.createBatch(roleBindingList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Role> listByUserId(String userId) {
|
||||
return mapper.selectByIdList(userRoleService.listRoleIdByUserId(userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Role> listByUserId(String userId, ModuleCode moduleCode) {
|
||||
TimiException.required(moduleCode, "not found moduleCode");
|
||||
return listByUserId(userId).stream()
|
||||
.filter(role -> moduleCode == role.getModuleCode())
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Role> listByModuleCode(ModuleCode moduleCode) {
|
||||
TimiException.required(moduleCode, "not found moduleCode");
|
||||
return mapper.selectByModuleCode(moduleCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> listAllCodeByUserId(String userId) {
|
||||
List<String> roleIdList = listByUserId(userId).stream().map(Role::getId).toList();
|
||||
List<String> allRoleIdList = getAllRoleIdsIncludingChildren(roleIdList);
|
||||
if (TimiJava.isEmpty(allRoleIdList)) {
|
||||
return List.of();
|
||||
}
|
||||
return mapper.selectByIdList(allRoleIdList).stream().map(role -> "%s:%s".formatted(role.getModuleCode().name(), role.getCode())).distinct().toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Permission> listAllPermissionByUserId(String userId) {
|
||||
List<String> roleIdList = listByUserId(userId).stream().map(Role::getId).toList();
|
||||
List<String> allRoleIdList = getAllRoleIdsIncludingChildren(roleIdList);
|
||||
return permissionService.listByRoleId(allRoleIdList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Role> listChildByParentRoleId(String parentRoleId) {
|
||||
List<String> childRoleIdList = roleRelationMapper.selectChildRoleIdListByParentRoleId(parentRoleId);
|
||||
if (TimiJava.isEmpty(childRoleIdList)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return mapper.selectByIdList(childRoleIdList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Permission> listPermissionByRoleId(String roleId) {
|
||||
List<String> allRoleIdList = getAllRoleIdsIncludingChildren(List.of(roleId));
|
||||
return permissionService.listByRoleId(allRoleIdList);
|
||||
}
|
||||
|
||||
/// 递归获取角色及其所有子角色的 ID 列表
|
||||
///
|
||||
/// @param roleIdList 角色 ID 列表
|
||||
/// @return 包含所有子角色的 ID 列表
|
||||
private List<String> getAllRoleIdsIncludingChildren(List<String> roleIdList) {
|
||||
if (TimiJava.isEmpty(roleIdList)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Set<String> allRoleIdSet = new HashSet<>(roleIdList);
|
||||
List<String> currentLevelRoleIdList = new ArrayList<>(roleIdList);
|
||||
|
||||
while (TimiJava.isNotEmpty(currentLevelRoleIdList)) {
|
||||
List<String> childRoleIdList = roleRelationMapper.selectChildRoleIdListByParentRoleIdList(currentLevelRoleIdList);
|
||||
if (TimiJava.isEmpty(childRoleIdList)) {
|
||||
break;
|
||||
}
|
||||
List<String> newChildRoleIdList = childRoleIdList.stream().filter(id -> !allRoleIdSet.contains(id)).toList();
|
||||
if (TimiJava.isEmpty(newChildRoleIdList)) {
|
||||
break;
|
||||
}
|
||||
allRoleIdSet.addAll(newChildRoleIdList);
|
||||
currentLevelRoleIdList = newChildRoleIdList;
|
||||
}
|
||||
return new ArrayList<>(allRoleIdSet);
|
||||
}
|
||||
|
||||
private String saveNameMultilingual(String langId, String name) {
|
||||
if (TimiJava.isEmpty(name)) {
|
||||
return langId;
|
||||
}
|
||||
if (TimiJava.isEmpty(langId)) {
|
||||
return multilingualService.create(name);
|
||||
}
|
||||
Multilingual multilingual = new Multilingual();
|
||||
multilingual.setId(langId);
|
||||
multilingual.setZhCN(name);
|
||||
multilingualMapper.updateSelective(multilingual);
|
||||
return langId;
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package com.imyeyu.api.modules.user.service.implement;
|
||||
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.modules.user.entity.UserBehaviorRecord;
|
||||
import com.imyeyu.api.modules.user.mapper.UserBehaviorRecordMapper;
|
||||
import com.imyeyu.api.modules.user.service.UserBehaviorRecordService;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import com.imyeyu.spring.service.AbstractEntityService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户行为记录服务实现
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-05-27 17:10
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserBehaviorRecordServiceImplement extends AbstractEntityService<UserBehaviorRecord, String> implements UserBehaviorRecordService {
|
||||
|
||||
private final UserBehaviorRecordMapper mapper;
|
||||
|
||||
@Override
|
||||
protected BaseMapper<UserBehaviorRecord, String> mapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void create(UserBehaviorRecord entity) {
|
||||
record(entity);
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public boolean record(UserBehaviorRecord entity) {
|
||||
TimiException.required(entity, "not found entity");
|
||||
TimiException.required(entity.getBizType(), "not found entity.bizType");
|
||||
TimiException.required(entity.getUserId(), "not found entity.userId");
|
||||
TimiException.required(entity.getTargetType(), "not found entity.targetType");
|
||||
TimiException.required(entity.getTargetId(), "not found entity.targetId");
|
||||
TimiException.required(entity.getActionType(), "not found entity.actionType");
|
||||
|
||||
UserBehaviorRecord dbRecord = mapper.selectActive(entity.getBizType(), entity.getUserId(), entity.getTargetType(), entity.getTargetId(), entity.getActionType());
|
||||
if (dbRecord != null) {
|
||||
return false;
|
||||
}
|
||||
super.create(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public boolean cancel(String bizType, String userId, String targetType, String targetId, String actionType) {
|
||||
if (TimiJava.isEmpty(bizType) || TimiJava.isEmpty(userId) || TimiJava.isEmpty(targetType) || TimiJava.isEmpty(targetId) || TimiJava.isEmpty(actionType)) {
|
||||
return false;
|
||||
}
|
||||
UserBehaviorRecord dbRecord = mapper.selectActive(bizType, userId, targetType, targetId, actionType);
|
||||
if (dbRecord == null) {
|
||||
return false;
|
||||
}
|
||||
super.delete(dbRecord.getId());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getActiveTargetIdSet(String bizType, String userId, String targetType, String actionType, List<String> targetIdList) {
|
||||
if (TimiJava.isEmpty(bizType) || TimiJava.isEmpty(userId) || TimiJava.isEmpty(targetType) || TimiJava.isEmpty(actionType) || TimiJava.isEmpty(targetIdList)) {
|
||||
return Set.of();
|
||||
}
|
||||
return new HashSet<>(mapper.selectActiveTargetIdList(bizType, userId, targetType, actionType, targetIdList));
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
package com.imyeyu.api.modules.user.service.implement;
|
||||
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.api.modules.common.entity.Setting;
|
||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||
import com.imyeyu.api.modules.common.service.SettingService;
|
||||
import com.imyeyu.api.modules.user.bean.BootstrapData;
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.api.modules.user.service.RoleService;
|
||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||
import com.imyeyu.api.modules.user.service.UserService;
|
||||
import com.imyeyu.api.modules.user.vo.LoginRequest;
|
||||
import com.imyeyu.api.modules.user.vo.LoginResponse;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import com.imyeyu.spring.TimiSpring;
|
||||
import com.imyeyu.spring.util.Redis;
|
||||
import com.imyeyu.utils.Digest;
|
||||
import com.imyeyu.utils.Time;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.UUID;
|
||||
|
||||
/// 用户登录服务实现
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-06-09
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
|
||||
public class UserLoginServiceImplement implements UserLoginService, TimiJava {
|
||||
|
||||
private static final String REGEX_PHONE_NO = "^1\\d{10}$";
|
||||
private static final String USER_TOKEN_KEY_PREFIX = "USER:TOKEN:";
|
||||
private static final String PHONE_VERIFY_KEY_PREFIX = "USER:PHONE:VERIFY:";
|
||||
private static final long PHONE_VERIFY_CODE_TTL = Time.M * 5;
|
||||
|
||||
private final UserService userService;
|
||||
private final RoleService roleService;
|
||||
private final SettingService settingService;
|
||||
private final AttachmentService attachmentService;
|
||||
|
||||
private final Redis<String, String> redisUserToken;
|
||||
|
||||
@Qualifier("redisUserPhoneVerify")
|
||||
private final Redis<String, String> redisUserPhoneVerify;
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public LoginResponse login(LoginRequest req) {
|
||||
// 获取
|
||||
User dbUser = userService.get(req.getUser());
|
||||
if (dbUser == null && req.getUser().contains("@")) {
|
||||
dbUser = userService.getByVerifiedEmail(req.getUser());
|
||||
} else if (dbUser == null && isPhoneNo(req.getUser())) {
|
||||
dbUser = userService.getByVerifiedPhoneNo(req.getUser());
|
||||
} else if (dbUser == null) {
|
||||
dbUser = userService.getByName(req.getUser());
|
||||
}
|
||||
TimiException.required(dbUser, "not found user");
|
||||
// 校验
|
||||
boolean isValid = Digest.argon2idVerify(dbUser.getPassword(), req.getPassword());
|
||||
TimiException.requiredTrue(isValid, "invalid password");
|
||||
TimiException.requiredTrue(!dbUser.isBanning(), "banned user");
|
||||
// 登录
|
||||
return login(UUID.randomUUID().toString(), dbUser.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginResponse login(String token, String userId) {
|
||||
Long time = settingService.getSystem(Setting.Module.User.TOKEN_TTL).asTime();
|
||||
long now = Time.now();
|
||||
long expireAt = now + time;
|
||||
redisUserToken.set(getUserTokenKey(token), userId, expireAt - now);
|
||||
|
||||
LoginResponse result = new LoginResponse();
|
||||
result.setToken(token);
|
||||
result.setExpireAt(expireAt);
|
||||
result.setUser(userService.get(userId));
|
||||
|
||||
User user = result.getUser();
|
||||
user.setPermissionList(roleService.listAllPermissionCodeByUserId(user.getId()));
|
||||
user.setRoleList(roleService.listAllCodeByUserId(user.getId()));
|
||||
user.setAttachmentList(attachmentService.listByBizId(Attachment.BizType.USER, user.getId()));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getLoginUser() {
|
||||
String token = TimiSpring.getToken();
|
||||
TimiException.required(token, "not found token");
|
||||
String userId = redisUserToken.get(getUserTokenKey(token));
|
||||
if (TimiJava.isEmpty(userId)) {
|
||||
return null;
|
||||
}
|
||||
return userService.get(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getRequireLoginUser() {
|
||||
String token = TimiSpring.getToken();
|
||||
TimiException.required(token, "not found token");
|
||||
String userId = redisUserToken.get(getUserTokenKey(token));
|
||||
TimiException.required(userId, "invalid token");
|
||||
return userService.get(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
redisUserToken.destroy(getUserTokenKey(TimiSpring.getToken()));
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void updatePassword(String oldPassword, String newPassword) {
|
||||
TimiException.requiredTrue(!oldPassword.equals(newPassword), "new password cannot be same as old password");
|
||||
User user = getRequireLoginUser();
|
||||
// 校验
|
||||
boolean isValid = Digest.argon2idVerify(user.getPassword(), oldPassword);
|
||||
TimiException.requiredTrue(isValid, "invalid old password");
|
||||
// 更新
|
||||
User update = new User();
|
||||
update.setId(user.getId());
|
||||
update.setPassword(Digest.argon2id(newPassword));
|
||||
userService.update(update);
|
||||
logout();
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void sendPhoneVerifyCode(String phoneNo) {
|
||||
TimiException.requiredTrue(isPhoneNo(phoneNo), "invalid phone number");
|
||||
User verifiedUser = userService.getByVerifiedPhoneNo(phoneNo);
|
||||
User loginUser = getRequireLoginUser();
|
||||
TimiException.requiredTrue(verifiedUser == null || verifiedUser.getId().equals(loginUser.getId()), "existed phone number");
|
||||
|
||||
String verifyCode = "%06d".formatted(ThreadLocalRandom.current().nextInt(1000000));
|
||||
redisUserPhoneVerify.set(getPhoneVerifyKey(phoneNo), verifyCode, PHONE_VERIFY_CODE_TTL);
|
||||
log.info("手机号验证码 phoneNo={}, code={}", phoneNo, verifyCode);
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void verifyPhoneNo(String phoneNo, String verifyCode) {
|
||||
TimiException.requiredTrue(isPhoneNo(phoneNo), "invalid phone number");
|
||||
TimiException.required(verifyCode, "not found verify code");
|
||||
|
||||
User user = getRequireLoginUser();
|
||||
User verifiedUser = userService.getByVerifiedPhoneNo(phoneNo);
|
||||
TimiException.requiredTrue(verifiedUser == null || verifiedUser.getId().equals(user.getId()), "existed phone number");
|
||||
|
||||
String cacheCode = redisUserPhoneVerify.get(getPhoneVerifyKey(phoneNo));
|
||||
TimiException.required(cacheCode, "invalid verify code");
|
||||
TimiException.requiredTrue(cacheCode.equals(verifyCode), "invalid verify code");
|
||||
|
||||
User update = new User();
|
||||
update.setId(user.getId());
|
||||
update.setPhoneNo(phoneNo);
|
||||
update.setPhoneNoVerifyAt(Time.now());
|
||||
userService.update(update);
|
||||
redisUserPhoneVerify.destroy(getPhoneVerifyKey(phoneNo));
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void deactivate(String password) {
|
||||
User user = getRequireLoginUser();
|
||||
TimiException.requiredTrue(!BootstrapData.SYS_USER_NAME.equals(user.getName()), "can not deactivate System user");
|
||||
|
||||
boolean isValid = Digest.argon2idVerify(user.getPassword(), password);
|
||||
TimiException.requiredTrue(isValid, "invalid password");
|
||||
|
||||
logout();
|
||||
userService.delete(user.getId());
|
||||
}
|
||||
|
||||
private boolean isPhoneNo(String value) {
|
||||
return TimiJava.isNotEmpty(value) && value.matches(REGEX_PHONE_NO);
|
||||
}
|
||||
|
||||
private String getPhoneVerifyKey(String phoneNo) {
|
||||
return "%s%s".formatted(PHONE_VERIFY_KEY_PREFIX, phoneNo);
|
||||
}
|
||||
|
||||
private String getUserTokenKey(String token) {
|
||||
return "%s%s".formatted(USER_TOKEN_KEY_PREFIX, token);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.imyeyu.api.modules.user.service.implement;
|
||||
|
||||
import com.imyeyu.api.modules.user.entity.UserRole;
|
||||
import com.imyeyu.api.modules.user.mapper.UserRoleMapper;
|
||||
import com.imyeyu.api.modules.user.service.UserRoleService;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import com.imyeyu.spring.service.AbstractEntityService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/// 用户角色服务实现
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-05-13 14:46
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserRoleServiceImplement extends AbstractEntityService<UserRole, String> implements UserRoleService {
|
||||
|
||||
private final UserRoleMapper mapper;
|
||||
|
||||
@Override
|
||||
protected BaseMapper<UserRole, String> mapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createBatch(List<UserRole> list) {
|
||||
mapper.createBatch(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserRole> listByUserId(String userId) {
|
||||
UserRole example = new UserRole();
|
||||
example.setUserId(userId);
|
||||
return mapper.selectAllByExample(example);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByRoleIdList(String userId, List<String> roleIdList) {
|
||||
mapper.deleteByRoleIdList(userId, roleIdList);
|
||||
}
|
||||
}
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
package com.imyeyu.api.modules.user.service.implement;
|
||||
|
||||
import com.imyeyu.api.modules.common.bean.ImageType;
|
||||
import com.imyeyu.api.modules.user.bean.BootstrapData;
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.api.modules.user.mapper.UserMapper;
|
||||
import com.imyeyu.api.modules.user.service.UserService;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import com.imyeyu.spring.service.AbstractEntityService;
|
||||
import com.imyeyu.utils.Digest;
|
||||
import com.imyeyu.utils.Regex;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 用户管理服务实现
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2021-02-23 21:43
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
|
||||
public class UserServiceImplement extends AbstractEntityService<User, String> implements UserService, TimiJava {
|
||||
|
||||
private static final String REGEX_PHONE_NO = "^1\\d{10}$";
|
||||
|
||||
private final UserMapper mapper;
|
||||
|
||||
@Override
|
||||
protected BaseMapper<User, String> mapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create(User user) {
|
||||
TimiException.requiredTrue(Regex.isMatch(Regex.PASSWORD, user.getPassword()), "invalid password");
|
||||
{
|
||||
User byName = getByName(user.getName());
|
||||
TimiException.requiredNull(byName, "existed user name");
|
||||
}
|
||||
{
|
||||
if (TimiJava.isNotEmpty(user.getEmail())) {
|
||||
User byEmail = getByVerifiedEmail(user.getEmail());
|
||||
TimiException.requiredNull(byEmail, "existed email");
|
||||
}
|
||||
}
|
||||
{
|
||||
if (TimiJava.isNotEmpty(user.getPhoneNo())) {
|
||||
validatePhoneNo(user.getPhoneNo());
|
||||
User byPhoneNo = getByVerifiedPhoneNo(user.getPhoneNo());
|
||||
TimiException.requiredNull(byPhoneNo, "existed phone number");
|
||||
}
|
||||
}
|
||||
|
||||
User dbUser = new User();
|
||||
dbUser.setName(user.getName());
|
||||
dbUser.setNick(TimiJava.defaultIfEmpty(user.getNick(), user.getName()));
|
||||
dbUser.setWrapperType(TimiJava.defaultIfNull(user.getWrapperType(), ImageType.PIXELATED));
|
||||
dbUser.setAvatarType(TimiJava.defaultIfNull(user.getAvatarType(), ImageType.PIXELATED));
|
||||
dbUser.setPassword(Digest.argon2id(user.getPassword()));
|
||||
dbUser.setEmail(user.getEmail());
|
||||
dbUser.setPhoneNo(user.getPhoneNo());
|
||||
dbUser.setExp(TimiJava.defaultIfNull(user.getExp(), 0));
|
||||
super.create(dbUser);
|
||||
user.setId(dbUser.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(User user) {
|
||||
User dbUser = get(user.getId());
|
||||
String name = TimiJava.defaultIfEmpty(user.getName(), dbUser.getName());
|
||||
String email = TimiJava.defaultIfEmpty(user.getEmail(), dbUser.getEmail());
|
||||
String phoneNo = TimiJava.defaultIfEmpty(user.getPhoneNo(), dbUser.getPhoneNo());
|
||||
if (!dbUser.getName().equals(name)) {
|
||||
// 修改名称
|
||||
User byName = getByName(name);
|
||||
TimiException.requiredTrue(byName == null || byName.getId().equals(dbUser.getId()), "existed user name");
|
||||
TimiException.requiredTrue(!dbUser.getName().equals(BootstrapData.SYS_USER_NAME), "invalid action");
|
||||
}
|
||||
if (TimiJava.isNotEmpty(email) && !email.equals(dbUser.getEmail())) {
|
||||
User byEmail = getByVerifiedEmail(email);
|
||||
TimiException.requiredTrue(byEmail == null || byEmail.getId().equals(dbUser.getId()), "existed email");
|
||||
}
|
||||
if (TimiJava.isNotEmpty(phoneNo)) {
|
||||
validatePhoneNo(phoneNo);
|
||||
if (!phoneNo.equals(dbUser.getPhoneNo())) {
|
||||
User byPhoneNo = getByVerifiedPhoneNo(phoneNo);
|
||||
TimiException.requiredTrue(byPhoneNo == null || byPhoneNo.getId().equals(dbUser.getId()), "existed phone number");
|
||||
}
|
||||
}
|
||||
super.update(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
User user = get(id);
|
||||
TimiException.requiredTrue(!user.getName().equals(BootstrapData.SYS_USER_NAME), "invalid action");
|
||||
super.delete(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(String id) {
|
||||
User user = get(id);
|
||||
TimiException.requiredTrue(!user.getName().equals(BootstrapData.SYS_USER_NAME), "invalid action");
|
||||
super.destroy(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByName(String name) {
|
||||
User example = new User();
|
||||
example.setName(name);
|
||||
return mapper.selectByExample(example);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByEmail(String email) {
|
||||
return mapper.selectByEmail(email);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByVerifiedEmail(String email) {
|
||||
return mapper.selectByVerifiedEmail(email);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByPhoneNo(String phoneNo) {
|
||||
return mapper.selectByPhoneNo(phoneNo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getByVerifiedPhoneNo(String phoneNo) {
|
||||
return mapper.selectByVerifiedPhoneNo(phoneNo);
|
||||
}
|
||||
|
||||
private void validatePhoneNo(String phoneNo) {
|
||||
TimiException.requiredTrue(Regex.isMatch(REGEX_PHONE_NO, phoneNo), "invalid phone number");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.imyeyu.api.modules.user.validation;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
import com.imyeyu.api.modules.user.validation.validtor.UserNameValidator;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.CONSTRUCTOR;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2023-05-06 18:01
|
||||
*/
|
||||
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@Constraint(validatedBy = UserNameValidator.class)
|
||||
public @interface UserName {
|
||||
|
||||
String message() default "";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.imyeyu.api.modules.user.validation;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
import com.imyeyu.api.modules.user.validation.validtor.UserPasswordValidator;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||
import static java.lang.annotation.ElementType.CONSTRUCTOR;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.ElementType.PARAMETER;
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* @author 夜雨
|
||||
* @since 2023-05-07 00:05
|
||||
*/
|
||||
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
@Constraint(validatedBy = UserPasswordValidator.class)
|
||||
public @interface UserPassword {
|
||||
|
||||
String message() default "";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.imyeyu.api.modules.user.validation.validtor;
|
||||
|
||||
import com.imyeyu.api.modules.user.validation.UserName;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.spring.util.AbstractValidator;
|
||||
import com.imyeyu.utils.Regex;
|
||||
|
||||
/**
|
||||
* 用户名基本验证
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2023-05-06 18:01
|
||||
*/
|
||||
public class UserNameValidator extends AbstractValidator<UserName, String> {
|
||||
|
||||
@Override
|
||||
protected String inspector(String userName) {
|
||||
if (TimiJava.isEmpty(userName)) {
|
||||
return "user.name.empty";
|
||||
}
|
||||
if (32 < userName.length()) {
|
||||
return "user.name.too_long";
|
||||
}
|
||||
if (userName.contains("@")) {
|
||||
return "user.name.contains_at";
|
||||
}
|
||||
if (Regex.isMatch("^[0-9]+.?[0-9]*$", userName)) {
|
||||
return "user.name.only_number";
|
||||
}
|
||||
if (Regex.isNotMatch("^[A-Za-z0-9_一-龥]+$", userName)) {
|
||||
return "user.name.not_match_regex";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.imyeyu.api.modules.user.validation.validtor;
|
||||
|
||||
import com.imyeyu.api.modules.user.validation.UserPassword;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.spring.util.AbstractValidator;
|
||||
import com.imyeyu.utils.Regex;
|
||||
|
||||
/**
|
||||
* 用户密码基本验证
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2023-05-06 18:01
|
||||
*/
|
||||
public class UserPasswordValidator extends AbstractValidator<UserPassword, String> {
|
||||
|
||||
@Override
|
||||
protected String inspector(String password) {
|
||||
if (TimiJava.isEmpty(password)) {
|
||||
return "user.password.empty";
|
||||
}
|
||||
if (password.length() < 6) {
|
||||
return "user.password.too_short";
|
||||
}
|
||||
if (32 < password.length()) {
|
||||
return "user.password.too_long";
|
||||
}
|
||||
if (Regex.isNotMatch(Regex.PASSWORD, password)) {
|
||||
return "user.password.not_match_regex";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.imyeyu.api.modules.user.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import com.imyeyu.api.modules.user.validation.UserPassword;
|
||||
|
||||
/**
|
||||
* 注销请求
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2026-06-05 22:50
|
||||
*/
|
||||
@Data
|
||||
public class CancelRequest {
|
||||
|
||||
/** 当前密码 */
|
||||
@UserPassword
|
||||
private String password;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.imyeyu.api.modules.user.vo;
|
||||
|
||||
import com.imyeyu.api.modules.user.validation.UserPassword;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 登录请求对象
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2023-04-25 17:26
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LoginRequest {
|
||||
|
||||
/** 用户(可能是 UID、邮箱或用户名) */
|
||||
@NotBlank(message = "not found user")
|
||||
private String user;
|
||||
|
||||
/** 明文密码 */
|
||||
@UserPassword
|
||||
private String password;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.imyeyu.api.modules.user.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.spring.util.ResponseView;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 登录返回对象
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2023-05-05 17:57
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class LoginResponse {
|
||||
|
||||
/** 令牌 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
private String token;
|
||||
|
||||
/** 过期时间 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
private Long expireAt;
|
||||
|
||||
/** 登录用户 */
|
||||
@JsonView(ResponseView.Public.class)
|
||||
private User user;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.imyeyu.api.modules.user.vo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
|
||||
/// 手机号验证码发送请求
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-07-27
|
||||
@Data
|
||||
public class PhoneVerifyCodeSendRequest {
|
||||
|
||||
/// 手机号
|
||||
@NotBlank(message = "not found phone number")
|
||||
@Pattern(regexp = "^1\\d{10}$", message = "invalid phone number")
|
||||
private String phoneNo;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.imyeyu.api.modules.user.vo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
|
||||
/// 手机号验证请求
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-07-27
|
||||
@Data
|
||||
public class PhoneVerifyRequest {
|
||||
|
||||
/// 手机号
|
||||
@NotBlank(message = "not found phone number")
|
||||
@Pattern(regexp = "^1\\d{10}$", message = "invalid phone number")
|
||||
private String phoneNo;
|
||||
|
||||
/// 验证码
|
||||
@NotBlank(message = "not found verify code")
|
||||
@Pattern(regexp = "^\\d{6}$", message = "invalid verify code")
|
||||
private String verifyCode;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.imyeyu.api.modules.user.vo;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import com.imyeyu.api.modules.user.validation.UserPassword;
|
||||
|
||||
/**
|
||||
* @author 夜雨
|
||||
* @since 2023-07-15 11:23
|
||||
*/
|
||||
@Data
|
||||
public class UpdatePasswordByKeyRequest {
|
||||
|
||||
@NotBlank
|
||||
private String key;
|
||||
|
||||
@UserPassword
|
||||
private String newPassword;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.imyeyu.api.modules.user.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import com.imyeyu.api.modules.user.validation.UserPassword;
|
||||
|
||||
/**
|
||||
* @author 夜雨
|
||||
* @since 2023-07-15 11:23
|
||||
*/
|
||||
@Data
|
||||
public class UpdatePasswordRequest {
|
||||
|
||||
@UserPassword
|
||||
private String oldValue;
|
||||
|
||||
@UserPassword
|
||||
private String newValue;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.imyeyu.api.modules.user.vo.permission;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 批量创建权限请求
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2025-11-18 16:49
|
||||
*/
|
||||
@Data
|
||||
public class BatchCreateReq {
|
||||
|
||||
private ModuleCode moduleCode;
|
||||
|
||||
/**
|
||||
* 权限类型枚举
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2025-11-18 16:50
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
CREATE,
|
||||
|
||||
READ,
|
||||
|
||||
UPDATE,
|
||||
|
||||
DELETE
|
||||
}
|
||||
|
||||
private String prefixCode;
|
||||
|
||||
private String prefixName;
|
||||
|
||||
private Type[] types;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.imyeyu.api.modules.user.vo.role;
|
||||
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
///
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-07-17 14:16
|
||||
@Data
|
||||
public class UserRoleAuthorizeReq {
|
||||
|
||||
private String userId;
|
||||
|
||||
private ModuleCode moduleCode;
|
||||
|
||||
private List<String> roleIdList;
|
||||
|
||||
private List<String> roleCodeList;
|
||||
}
|
||||
Reference in New Issue
Block a user