Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
custom-server
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lizhonghong
custom-server
Commits
d043ba58
Commit
d043ba58
authored
Jul 15, 2026
by
Lizh
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
调整用户登录,用户添加等功能
parent
d0367d25
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
604 additions
and
144 deletions
+604
-144
.gitignore
+1
-0
custom-server-app/src/main/java/com/jomalls/custom/app/constant/RoleConstants.java
+19
-0
custom-server-app/src/main/java/com/jomalls/custom/app/constant/UserConstants.java
+21
-0
custom-server-app/src/main/java/com/jomalls/custom/app/enums/SysUserStatusEnums.java
+1
-0
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/SysUserService.java
+13
-3
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysDeptServiceImpl.java
+92
-1
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysLoginServiceImpl.java
+52
-43
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysMenuServiceImpl.java
+50
-2
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysPasswordService.java
+1
-1
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysPostServiceImpl.java
+39
-1
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysRoleServiceImpl.java
+53
-5
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysUserServiceImpl.java
+151
-42
custom-server-app/src/main/java/com/jomalls/custom/app/utils/CharsetKit.java
+22
-0
custom-server-app/src/main/java/com/jomalls/custom/app/utils/UniqueId.java
+21
-0
custom-server-app/src/main/java/com/jomalls/custom/app/vo/system/SysRoleVO.java
+4
-0
custom-server-core/src/main/java/com/jomalls/custom/security/TokenHandle.java
+14
-17
custom-server-domain/src/main/resources/mapper/SysMenuMapper.xml
+8
-7
custom-server-starter/src/main/java/com/jomalls/custom/config/CommonExceptionHandlerAdvice.java
+4
-5
custom-server-webapp/src/main/java/com/jomalls/custom/webapp/controller/system/SysRoleController.java
+18
-5
custom-server-webapp/src/main/java/com/jomalls/custom/webapp/controller/system/SysUserController.java
+20
-12
No files found.
.gitignore
View file @
d043ba58
...
...
@@ -15,4 +15,5 @@
CLAUDE.md
docs
plans
logs
custom-server-app/src/main/java/com/jomalls/custom/app/constant/RoleConstants.java
0 → 100644
View file @
d043ba58
package
com
.
jomalls
.
custom
.
app
.
constant
;
/**
* @Author: Lizh
* @Date: 2026/7/15 15:27
* @Description: 角色常量
* @Version: 1.0
*/
public
class
RoleConstants
{
/**
* 超级管理员admin 名称
*/
public
static
final
String
ADMIN_USER
=
"admin"
;
/**
* 角色状态
*/
public
static
final
String
STATUS_NORMAL
=
"0"
;
}
custom-server-app/src/main/java/com/jomalls/custom/app/constant/UserConstants.java
View file @
d043ba58
...
...
@@ -111,4 +111,25 @@ public class UserConstants {
*/
public
static
final
int
PASSWORD_MIN_LENGTH
=
5
;
public
static
final
int
PASSWORD_MAX_LENGTH
=
20
;
/**
* 初始化密码长度
*/
public
static
final
int
INIT_PASSWORD_LENGTH
=
8
;
/**
* 黑名单key
*/
public
static
final
String
BLACK_IP_KEY
=
"sys.login.blackIPList"
;
/**
* 是否修改过初始化密码
*/
public
static
final
String
INIT_PWD_MODIFY_KEY
=
"sys.account.initPasswordModify"
;
/**
* 密码过期
*/
public
static
final
String
PWD_VALIDATE_KEY
=
"sys.account.passwordValidateDays"
;
}
custom-server-app/src/main/java/com/jomalls/custom/app/enums/SysUserStatusEnums.java
View file @
d043ba58
...
...
@@ -10,6 +10,7 @@ import lombok.Getter;
*/
@Getter
public
enum
SysUserStatusEnums
{
NORMAL
(
"0"
,
"正常"
),
DELETED
(
"2"
,
"已被删除"
),
DISABLED
(
"1"
,
"已被停用"
);
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/SysUserService.java
View file @
d043ba58
...
...
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.jomalls.custom.app.dto.system.*
;
import
com.jomalls.custom.app.vo.system.SysDeptVO
;
import
com.jomalls.custom.app.vo.system.SysRoleVO
;
import
com.jomalls.custom.app.vo.system.SysUserVO
;
import
java.util.List
;
...
...
@@ -112,12 +113,21 @@ public interface SysUserService {
void
updatePwd
(
SysUserUpdatePwdDTO
dto
);
/**
* 查询用户
已分配的角色ID列表
* 查询用户
详情(仅返回用户 VO,不含角色/岗位)
*
* @param userId 用户ID
* @return
角色ID列表
* @return
用户 VO
*/
List
<
Long
>
getAuthRoleList
(
Long
userId
);
SysUserVO
getById
(
Long
userId
);
/**
* 查询用户已分配的角色列表(与 custom-back selectRolesByUserId + selectRoleAll 对齐)
* <p>返回全部角色,已分配给用户的角色设置 flag=true
*
* @param userId 用户ID
* @return 角色 VO 列表(含 flag 标识)
*/
List
<
SysRoleVO
>
getAuthRoleList
(
Long
userId
);
/**
* 批量插入用户角色关联
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysDeptServiceImpl.java
View file @
d043ba58
...
...
@@ -9,10 +9,13 @@ import com.jomalls.custom.app.utils.BeanMapper;
import
com.jomalls.custom.app.vo.system.SysDeptVO
;
import
com.jomalls.custom.dal.entity.SysDeptEntity
;
import
com.jomalls.custom.domain.service.system.SysDeptDomainService
;
import
com.jomalls.custom.security.SecurityUtils
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.time.LocalDateTime
;
import
java.util.List
;
/**
...
...
@@ -69,8 +72,18 @@ public class SysDeptServiceImpl implements SysDeptService {
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
add
(
SysDeptSaveDTO
dto
)
{
SysDeptEntity
dept
=
BeanMapper
.
mapper
().
convert
(
dto
,
SysDeptEntity
.
class
);
// 检查部门名称唯一性
long
count
=
sysDeptDomainService
.
count
(
new
LambdaQueryWrapper
<
SysDeptEntity
>()
.
eq
(
SysDeptEntity:
:
getDeptName
,
dept
.
getDeptName
())
.
eq
(
SysDeptEntity:
:
getParentId
,
dept
.
getParentId
()
!=
null
?
dept
.
getParentId
()
:
0L
)
.
ne
(
dept
.
getDeptId
()
!=
null
,
SysDeptEntity:
:
getDeptId
,
dept
.
getDeptId
()
!=
null
?
dept
.
getDeptId
()
:
-
1L
));
if
(
count
>
0
)
{
throw
new
ServiceException
(
"新增部门'"
+
dept
.
getDeptName
()
+
"'失败,部门名称已存在"
);
}
// 设置祖级列表
if
(
dept
.
getParentId
()
==
null
||
dept
.
getParentId
()
==
0L
)
{
dept
.
setAncestors
(
"0"
);
...
...
@@ -79,8 +92,14 @@ public class SysDeptServiceImpl implements SysDeptService {
if
(
parentDept
==
null
)
{
throw
new
ServiceException
(
"父部门不存在"
);
}
dept
.
setAncestors
(
parentDept
.
getAncestors
()
+
","
+
dept
.
getParentId
());
if
(
"1"
.
equals
(
parentDept
.
getStatus
()))
{
throw
new
ServiceException
(
"父部门已停用,不允许新增子部门"
);
}
dept
.
setAncestors
(
parentDept
.
getAncestors
()
!=
null
?
parentDept
.
getAncestors
()
+
","
+
parentDept
.
getDeptId
()
:
String
.
valueOf
(
parentDept
.
getDeptId
()));
}
// 设置审计字段
dept
.
setCreateBy
(
SecurityUtils
.
getUsername
());
dept
.
setCreateTime
(
LocalDateTime
.
now
());
boolean
saved
=
sysDeptDomainService
.
save
(
dept
);
if
(
saved
)
{
log
.
info
(
"新增部门成功: deptName={}"
,
dept
.
getDeptName
());
...
...
@@ -88,13 +107,85 @@ public class SysDeptServiceImpl implements SysDeptService {
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
edit
(
SysDeptUpdateDTO
dto
)
{
SysDeptEntity
dept
=
BeanMapper
.
mapper
().
convert
(
dto
,
SysDeptEntity
.
class
);
// 检查部门名称唯一性(排除自身)
long
count
=
sysDeptDomainService
.
count
(
new
LambdaQueryWrapper
<
SysDeptEntity
>()
.
eq
(
SysDeptEntity:
:
getDeptName
,
dept
.
getDeptName
())
.
eq
(
SysDeptEntity:
:
getParentId
,
dept
.
getParentId
()
!=
null
?
dept
.
getParentId
()
:
0L
)
.
ne
(
dept
.
getDeptId
()
!=
null
,
SysDeptEntity:
:
getDeptId
,
dept
.
getDeptId
()
!=
null
?
dept
.
getDeptId
()
:
-
1L
));
if
(
count
>
0
)
{
throw
new
ServiceException
(
"修改部门'"
+
dept
.
getDeptName
()
+
"'失败,部门名称已存在"
);
}
// 获取旧部门信息
SysDeptEntity
oldDept
=
sysDeptDomainService
.
getById
(
dept
.
getDeptId
());
if
(
oldDept
==
null
)
{
throw
new
ServiceException
(
"部门不存在"
);
}
String
oldAncestors
=
oldDept
.
getAncestors
();
// 计算新的祖级列表
boolean
parentChanged
=
dept
.
getParentId
()
!=
null
&&
!
dept
.
getParentId
().
equals
(
oldDept
.
getParentId
());
if
(
parentChanged
)
{
String
newAncestors
;
if
(
dept
.
getParentId
()
==
0L
)
{
newAncestors
=
"0"
;
}
else
{
SysDeptEntity
newParent
=
sysDeptDomainService
.
getById
(
dept
.
getParentId
());
if
(
newParent
==
null
)
{
throw
new
ServiceException
(
"父部门不存在"
);
}
if
(
"1"
.
equals
(
newParent
.
getStatus
()))
{
throw
new
ServiceException
(
"父部门已停用,不允许移动子部门"
);
}
newAncestors
=
newParent
.
getAncestors
()
+
","
+
newParent
.
getDeptId
();
}
dept
.
setAncestors
(
newAncestors
);
}
else
{
// 父部门未变更,保持原有祖级列表
dept
.
setAncestors
(
oldAncestors
);
}
// 设置审计字段
dept
.
setUpdateBy
(
SecurityUtils
.
getUsername
());
dept
.
setUpdateTime
(
LocalDateTime
.
now
());
// 更新部门
sysDeptDomainService
.
updateById
(
dept
);
// 更新子部门 ancestors(仅父部门变更时)
if
(
parentChanged
)
{
String
oldPrefix
=
oldAncestors
+
","
+
dept
.
getDeptId
();
String
newPrefix
=
dept
.
getAncestors
()
+
","
+
dept
.
getDeptId
();
List
<
SysDeptEntity
>
descendants
=
sysDeptDomainService
.
list
(
new
LambdaQueryWrapper
<
SysDeptEntity
>()
.
likeRight
(
SysDeptEntity:
:
getAncestors
,
oldPrefix
));
for
(
SysDeptEntity
descendant
:
descendants
)
{
descendant
.
setAncestors
(
descendant
.
getAncestors
().
replace
(
oldPrefix
,
newPrefix
));
sysDeptDomainService
.
updateById
(
descendant
);
}
}
// 如果部门状态启用,更新父部门链状态为正常
if
(
"0"
.
equals
(
dept
.
getStatus
())
&&
dept
.
getAncestors
()
!=
null
)
{
String
[]
ancestorIds
=
dept
.
getAncestors
().
split
(
","
);
for
(
String
ancestorId
:
ancestorIds
)
{
if
(
ancestorId
.
isEmpty
()
||
"0"
.
equals
(
ancestorId
))
continue
;
SysDeptEntity
ancestor
=
new
SysDeptEntity
();
ancestor
.
setDeptId
(
Long
.
parseLong
(
ancestorId
));
ancestor
.
setStatus
(
"0"
);
sysDeptDomainService
.
updateById
(
ancestor
);
}
}
log
.
info
(
"修改部门成功: deptId={}"
,
dept
.
getDeptId
());
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
remove
(
Long
deptId
)
{
// 检查是否有子部门
if
(
sysDeptDomainService
.
hasChildByDeptId
(
deptId
))
{
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysLoginServiceImpl.java
View file @
d043ba58
...
...
@@ -21,12 +21,15 @@ import com.jomalls.custom.domain.service.system.SysUserDomainService;
import
com.jomalls.custom.security.LoginUser
;
import
com.jomalls.custom.security.SecurityUtils
;
import
com.jomalls.custom.security.TokenHandle
;
import
jakarta.servlet.http.HttpServletRequest
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.jspecify.annotations.Nullable
;
import
org.springframework.data.redis.core.StringRedisTemplate
;
import
org.springframework.security.crypto.password.PasswordEncoder
;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.StringUtils
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
java.util.*
;
import
java.util.stream.Collectors
;
...
...
@@ -52,7 +55,7 @@ public class SysLoginServiceImpl implements SysLoginService {
private
final
StringRedisTemplate
stringRedisTemplate
;
/**
* 校验验证码
(与 custom-back SysLoginService.validateCaptcha 对齐)
* 校验验证码
*
* @param username 用户名
* @param code 用户输入的验证码
...
...
@@ -66,7 +69,7 @@ public class SysLoginServiceImpl implements SysLoginService {
}
// 验证码未开启则不校验
if
(!
StringUtils
.
hasText
(
uuid
))
{
sysLogininforService
.
recordLogininfor
(
username
,
"1"
,
"验证码参数缺失"
);
sysLogininforService
.
recordLogininfor
(
username
,
UserConstants
.
EXCEPTION
,
"验证码参数缺失"
);
throw
new
ServiceException
(
"验证码参数缺失"
);
}
if
(
stringRedisTemplate
==
null
)
{
...
...
@@ -75,44 +78,44 @@ public class SysLoginServiceImpl implements SysLoginService {
String
verifyKey
=
"captcha_codes:"
+
uuid
;
String
captcha
=
stringRedisTemplate
.
opsForValue
().
get
(
verifyKey
);
if
(
captcha
==
null
)
{
sysLogininforService
.
recordLogininfor
(
username
,
"1"
,
"验证码已失效"
);
sysLogininforService
.
recordLogininfor
(
username
,
UserConstants
.
EXCEPTION
,
"验证码已失效"
);
throw
new
ServiceException
(
"验证码已失效"
);
}
// 删除 Redis 中的验证码(一次性使用)
stringRedisTemplate
.
delete
(
verifyKey
);
if
(!
captcha
.
equalsIgnoreCase
(
code
))
{
sysLogininforService
.
recordLogininfor
(
username
,
"1"
,
"验证码错误"
);
sysLogininforService
.
recordLogininfor
(
username
,
UserConstants
.
EXCEPTION
,
"验证码错误"
);
throw
new
ServiceException
(
"验证码错误"
);
}
}
/**
* 登录前置校验
(与 custom-back SysLoginService.loginPreCheck 对齐)
* 登录前置校验
* <p>
* 校验项:用户名/密码长度、IP 黑名单
*/
private
void
loginPreCheck
(
String
username
,
String
password
)
{
// 用户名或密码为空
if
(!
StringUtils
.
hasText
(
username
)
||
!
StringUtils
.
hasText
(
password
))
{
sysLogininforService
.
recordLogininfor
(
username
,
"1"
,
"用户名或密码不能为空"
);
sysLogininforService
.
recordLogininfor
(
username
,
UserConstants
.
EXCEPTION
,
"用户名或密码不能为空"
);
throw
new
ServiceException
(
"用户名或密码不能为空"
);
}
// 密码长度校验
(与 custom-back PASSWORD_MIN_LENGTH=5, PASSWORD_MAX_LENGTH=20 对齐)
// 密码长度校验
if
(
password
.
length
()
<
UserConstants
.
PASSWORD_MIN_LENGTH
||
password
.
length
()
>
UserConstants
.
PASSWORD_MAX_LENGTH
)
{
sysLogininforService
.
recordLogininfor
(
username
,
"1"
,
"密码长度不在允许范围内"
);
sysLogininforService
.
recordLogininfor
(
username
,
UserConstants
.
EXCEPTION
,
"密码长度不在允许范围内"
);
throw
new
ServiceException
(
"密码长度不正确"
);
}
// 用户名长度校验
(与 custom-back USERNAME_MIN_LENGTH=2, USERNAME_MAX_LENGTH=20 对齐)
// 用户名长度校验
if
(
username
.
length
()
<
UserConstants
.
USERNAME_MIN_LENGTH
||
username
.
length
()
>
UserConstants
.
USERNAME_MAX_LENGTH
)
{
sysLogininforService
.
recordLogininfor
(
username
,
"1"
,
"用户名长度不在允许范围内"
);
sysLogininforService
.
recordLogininfor
(
username
,
UserConstants
.
EXCEPTION
,
"用户名长度不在允许范围内"
);
throw
new
ServiceException
(
"用户名长度不正确"
);
}
// IP 黑名单校验(与 custom-back 对齐)
String
blackIpList
=
sysConfigService
.
selectConfigByKey
(
"sys.login.blackIPList"
);
String
blackIpList
=
sysConfigService
.
selectConfigByKey
(
UserConstants
.
BLACK_IP_KEY
);
if
(
StringUtils
.
hasText
(
blackIpList
))
{
String
currentIp
=
getCurrentIp
();
if
(
isIpMatched
(
blackIpList
,
currentIp
))
{
sysLogininforService
.
recordLogininfor
(
username
,
"1"
,
"IP 已被列入黑名单"
);
sysLogininforService
.
recordLogininfor
(
username
,
UserConstants
.
EXCEPTION
,
"IP 已被列入黑名单"
);
throw
new
ServiceException
(
"IP 已被列入黑名单,请联系管理员"
);
}
}
...
...
@@ -120,7 +123,7 @@ public class SysLoginServiceImpl implements SysLoginService {
@Override
public
String
login
(
String
username
,
String
password
,
String
code
,
String
uuid
)
{
// 验证码校验
(与 custom-back validateCaptcha 对齐)
// 验证码校验
validateCaptcha
(
username
,
code
,
uuid
);
// 登录前置校验
...
...
@@ -130,10 +133,8 @@ public class SysLoginServiceImpl implements SysLoginService {
sysPasswordService
.
checkLocked
(
username
);
// 1. 查询用户
SysUserEntity
user
=
sysUserDomainService
.
getOne
(
new
LambdaQueryWrapper
<
SysUserEntity
>()
.
eq
(
SysUserEntity:
:
getUserName
,
username
)
);
SysUserEntity
user
=
sysUserDomainService
.
getOne
(
new
LambdaQueryWrapper
<
SysUserEntity
>()
.
eq
(
SysUserEntity:
:
getUserName
,
username
));
if
(
user
==
null
)
{
log
.
warn
(
"登录失败:用户[{}]不存在"
,
username
);
throw
new
ServiceException
(
"用户不存在"
);
...
...
@@ -147,13 +148,13 @@ public class SysLoginServiceImpl implements SysLoginService {
throw
new
ServiceException
(
"用户已被停用"
);
}
// 2. 验证密码(MD5
,与 custom-back 兼容
)
// 2. 验证密码(MD5)
if
(!
passwordEncoder
.
matches
(
password
,
user
.
getPassword
()))
{
log
.
warn
(
"用户[{}]密码验证失败"
,
username
);
// 记录登录失败重试次数
sysPasswordService
.
recordLoginFailure
(
username
);
// 记录登录日志
sysLogininforService
.
recordLogininfor
(
username
,
"1"
,
"密码错误"
);
sysLogininforService
.
recordLogininfor
(
username
,
UserConstants
.
EXCEPTION
,
"密码错误"
);
throw
new
ServiceException
(
"密码错误"
);
}
...
...
@@ -162,7 +163,7 @@ public class SysLoginServiceImpl implements SysLoginService {
// 4. 密码正确,清除重试计数并记录登录日志
sysPasswordService
.
clearLoginRecord
(
username
);
sysLogininforService
.
recordLogininfor
(
username
,
"0"
,
"登录成功"
);
sysLogininforService
.
recordLogininfor
(
username
,
UserConstants
.
NORMAL
,
"登录成功"
);
// 5. 构建 LoginUser
LoginUser
loginUser
=
new
LoginUser
(
user
.
getUserId
(),
user
.
getDeptId
(),
username
);
...
...
@@ -185,7 +186,7 @@ public class SysLoginServiceImpl implements SysLoginService {
}
/**
* 记录登录信息(登录IP和登录时间
,与 custom-back recordLoginInfo 对齐
)
* 记录登录信息(登录IP和登录时间)
*/
private
void
recordLoginInfo
(
SysUserEntity
user
)
{
try
{
...
...
@@ -239,15 +240,15 @@ public class SysLoginServiceImpl implements SysLoginService {
}
result
.
setPermissions
(
dbPermissions
);
// 初始密码修改状态
(与 custom-back SysLoginController.getInfo 对齐)
// 初始密码修改状态
// 与 custom-back initPasswordIsModify 对齐:initPasswordModify == 1 且 pwdUpdateDate == null
String
initPwdModify
=
sysConfigService
.
selectConfigByKey
(
"sys.account.initPasswordModify"
);
String
initPwdModify
=
sysConfigService
.
selectConfigByKey
(
UserConstants
.
INIT_PWD_MODIFY_KEY
);
result
.
setIsDefaultModifyPwd
(
"1"
.
equals
(
initPwdModify
)
&&
user
.
getPwdUpdateDate
()
==
null
);
// 密码过期状态
// 读取 sys.account.passwordValidateDays 配置,大于 0 时检查是否超期
boolean
passwordExpired
=
false
;
Integer
passwordValidateDays
=
Convert
.
toInt
(
sysConfigService
.
selectConfigByKey
(
"sys.account.passwordValidateDays"
));
Integer
passwordValidateDays
=
Convert
.
toInt
(
sysConfigService
.
selectConfigByKey
(
UserConstants
.
PWD_VALIDATE_KEY
));
if
(
passwordValidateDays
!=
null
&&
passwordValidateDays
>
0
)
{
if
(
user
.
getPwdUpdateDate
()
==
null
)
{
// 如果从未修改过初始密码,直接提醒过期
...
...
@@ -280,14 +281,14 @@ public class SysLoginServiceImpl implements SysLoginService {
}
/**
* 构建前端路由菜单
(与 custom-back SysMenuService.buildMenus 完全对齐)
* 构建前端路由菜单
*/
private
List
<
RouterVO
>
buildRouterTree
(
Long
parentId
,
List
<
SysMenuEntity
>
allMenus
)
{
List
<
SysMenuEntity
>
menus
=
allMenus
.
stream
()
.
filter
(
menu
->
!
"F"
.
equals
(
menu
.
getMenuType
()))
.
filter
(
menu
->
menu
.
getParentId
().
equals
(
parentId
))
.
sorted
(
Comparator
.
comparingInt
(
m
->
m
.
getOrderNum
()
!=
null
?
m
.
getOrderNum
()
:
0
))
.
collect
(
Collectors
.
toList
()
);
.
toList
(
);
List
<
RouterVO
>
routers
=
new
ArrayList
<>();
for
(
SysMenuEntity
menu
:
menus
)
{
...
...
@@ -337,16 +338,18 @@ public class SysLoginServiceImpl implements SysLoginService {
return
routers
;
}
// ========== 路由构建辅助方法(与 custom-back SysMenuService 对齐) ==========
private
String
getRouteName
(
SysMenuEntity
menu
)
{
if
(
isMenuFrame
(
menu
))
return
""
;
if
(
isMenuFrame
(
menu
))
{
return
""
;
}
return
getRouteName
(
menu
.
getRouteName
(),
menu
.
getPath
());
}
private
String
getRouteName
(
String
name
,
String
path
)
{
String
routerName
=
StringUtils
.
hasText
(
name
)
?
name
:
path
;
if
(!
StringUtils
.
hasText
(
routerName
))
return
""
;
if
(!
StringUtils
.
hasText
(
routerName
))
{
return
""
;
}
return
routerName
.
substring
(
0
,
1
).
toUpperCase
()
+
(
routerName
.
length
()
>
1
?
routerName
.
substring
(
1
)
:
""
);
}
...
...
@@ -392,7 +395,9 @@ public class SysLoginServiceImpl implements SysLoginService {
}
private
String
innerLinkReplaceEach
(
String
path
)
{
if
(
path
==
null
)
return
""
;
if
(
path
==
null
)
{
return
""
;
}
return
path
.
replace
(
"http://"
,
""
).
replace
(
"https://"
,
""
)
.
replace
(
"www."
,
""
).
replace
(
"."
,
"/"
).
replace
(
":"
,
"/"
);
}
...
...
@@ -415,18 +420,7 @@ public class SysLoginServiceImpl implements SysLoginService {
org
.
springframework
.
web
.
context
.
request
.
ServletRequestAttributes
attributes
=
(
org
.
springframework
.
web
.
context
.
request
.
ServletRequestAttributes
)
org
.
springframework
.
web
.
context
.
request
.
RequestContextHolder
.
getRequestAttributes
();
if
(
attributes
!=
null
)
{
jakarta
.
servlet
.
http
.
HttpServletRequest
request
=
attributes
.
getRequest
();
String
ip
=
request
.
getHeader
(
"X-Forwarded-For"
);
if
(
ip
==
null
||
ip
.
isEmpty
()
||
"unknown"
.
equalsIgnoreCase
(
ip
))
{
ip
=
request
.
getHeader
(
"X-Real-IP"
);
}
if
(
ip
==
null
||
ip
.
isEmpty
()
||
"unknown"
.
equalsIgnoreCase
(
ip
))
{
ip
=
request
.
getRemoteAddr
();
}
if
(
ip
!=
null
&&
ip
.
contains
(
","
))
{
ip
=
ip
.
split
(
","
)[
0
].
trim
();
}
return
ip
;
return
getString
(
attributes
);
}
}
catch
(
Exception
e
)
{
log
.
debug
(
"获取客户端 IP 失败: {}"
,
e
.
getMessage
());
...
...
@@ -434,6 +428,21 @@ public class SysLoginServiceImpl implements SysLoginService {
return
""
;
}
private
static
String
getString
(
ServletRequestAttributes
attributes
)
{
HttpServletRequest
request
=
attributes
.
getRequest
();
String
ip
=
request
.
getHeader
(
"X-Forwarded-For"
);
if
(
ip
==
null
||
ip
.
isEmpty
()
||
"unknown"
.
equalsIgnoreCase
(
ip
))
{
ip
=
request
.
getHeader
(
"X-Real-IP"
);
}
if
(
ip
==
null
||
ip
.
isEmpty
()
||
"unknown"
.
equalsIgnoreCase
(
ip
))
{
ip
=
request
.
getRemoteAddr
();
}
if
(
ip
!=
null
&&
ip
.
contains
(
","
))
{
ip
=
ip
.
split
(
","
)[
0
].
trim
();
}
return
ip
;
}
/**
* 检查 IP 是否匹配黑名单(与 custom-back IpUtils.isMatchedIp 对齐)
* <p>
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysMenuServiceImpl.java
View file @
d043ba58
...
...
@@ -9,12 +9,16 @@ import com.jomalls.custom.app.utils.BeanMapper;
import
com.jomalls.custom.app.vo.system.SysMenuVO
;
import
com.jomalls.custom.app.vo.system.TreeSelectVO
;
import
com.jomalls.custom.dal.entity.SysMenuEntity
;
import
com.jomalls.custom.dal.entity.SysRoleEntity
;
import
com.jomalls.custom.dal.entity.SysRoleMenuEntity
;
import
com.jomalls.custom.domain.service.system.SysMenuDomainService
;
import
com.jomalls.custom.domain.service.system.SysRoleDomainService
;
import
com.jomalls.custom.domain.service.system.SysRoleMenuDomainService
;
import
com.jomalls.custom.security.SecurityUtils
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.util.StringUtils
;
import
java.util.*
;
...
...
@@ -32,6 +36,7 @@ public class SysMenuServiceImpl implements SysMenuService {
private
final
SysMenuDomainService
sysMenuDomainService
;
private
final
SysRoleMenuDomainService
sysRoleMenuDomainService
;
private
final
SysRoleDomainService
sysRoleDomainService
;
@Override
public
List
<
SysMenuVO
>
selectMenuList
(
SysMenuVO
menu
)
{
...
...
@@ -70,23 +75,67 @@ public class SysMenuServiceImpl implements SysMenuService {
List
<
Long
>
checkedKeys
=
roleMenus
.
stream
()
.
map
(
SysRoleMenuEntity:
:
getMenuId
)
.
collect
(
Collectors
.
toList
());
// 如果菜单树选择项不关联显示(menuCheckStrictly=false),
// 则包含直接分配的菜单及其所有子菜单的ID
SysRoleEntity
role
=
sysRoleDomainService
.
getById
(
roleId
);
if
(
role
!=
null
&&
role
.
getMenuCheckStrictly
()
!=
null
&&
role
.
getMenuCheckStrictly
()
==
0
)
{
Set
<
Long
>
allCheckedKeys
=
new
HashSet
<>(
checkedKeys
);
List
<
SysMenuEntity
>
allMenus
=
sysMenuDomainService
.
list
();
for
(
Long
menuId
:
checkedKeys
)
{
addAllDescendantIds
(
menuId
,
allMenus
,
allCheckedKeys
);
}
checkedKeys
=
new
ArrayList
<>(
allCheckedKeys
);
}
Map
<
String
,
Object
>
result
=
new
HashMap
<>();
result
.
put
(
"menus"
,
menus
);
result
.
put
(
"checkedKeys"
,
checkedKeys
);
return
result
;
}
/**
* 递归添加所有子菜单ID
*/
private
void
addAllDescendantIds
(
Long
parentId
,
List
<
SysMenuEntity
>
allMenus
,
Set
<
Long
>
result
)
{
for
(
SysMenuEntity
menu
:
allMenus
)
{
if
(
parentId
.
equals
(
menu
.
getParentId
()))
{
result
.
add
(
menu
.
getMenuId
());
addAllDescendantIds
(
menu
.
getMenuId
(),
allMenus
,
result
);
}
}
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
add
(
SysMenuSaveDTO
dto
)
{
SysMenuEntity
menu
=
BeanMapper
.
mapper
().
convert
(
dto
,
SysMenuEntity
.
class
);
// 检查菜单名称唯一性(同级菜单下名称不能重复)
long
nameCount
=
sysMenuDomainService
.
count
(
new
LambdaQueryWrapper
<
SysMenuEntity
>()
.
eq
(
SysMenuEntity:
:
getMenuName
,
menu
.
getMenuName
())
.
eq
(
menu
.
getParentId
()
!=
null
,
SysMenuEntity:
:
getParentId
,
menu
.
getParentId
()));
if
(
nameCount
>
0
)
{
throw
new
ServiceException
(
"新增菜单'"
+
menu
.
getMenuName
()
+
"'失败,菜单名称已存在"
);
}
menu
.
setCreateBy
(
SecurityUtils
.
getUsername
());
menu
.
setCreateTime
(
new
Date
());
sysMenuDomainService
.
save
(
menu
);
log
.
info
(
"新增菜单成功: menuName={}"
,
menu
.
getMenuName
());
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
edit
(
SysMenuUpdateDTO
dto
)
{
SysMenuEntity
menu
=
BeanMapper
.
mapper
().
convert
(
dto
,
SysMenuEntity
.
class
);
// 检查菜单名称唯一性(排除自身)
long
nameCount
=
sysMenuDomainService
.
count
(
new
LambdaQueryWrapper
<
SysMenuEntity
>()
.
eq
(
SysMenuEntity:
:
getMenuName
,
menu
.
getMenuName
())
.
eq
(
menu
.
getParentId
()
!=
null
,
SysMenuEntity:
:
getParentId
,
menu
.
getParentId
())
.
ne
(
SysMenuEntity:
:
getMenuId
,
menu
.
getMenuId
()));
if
(
nameCount
>
0
)
{
throw
new
ServiceException
(
"修改菜单'"
+
menu
.
getMenuName
()
+
"'失败,菜单名称已存在"
);
}
menu
.
setUpdateBy
(
SecurityUtils
.
getUsername
());
menu
.
setUpdateTime
(
new
Date
());
sysMenuDomainService
.
updateById
(
menu
);
log
.
info
(
"修改菜单成功: menuId={}"
,
menu
.
getMenuId
());
...
...
@@ -107,6 +156,7 @@ public class SysMenuServiceImpl implements SysMenuService {
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
remove
(
Long
menuId
)
{
// 检查是否有子菜单(controller 层已做检查,此处双重保障)
long
childCount
=
sysMenuDomainService
.
count
(
...
...
@@ -121,8 +171,6 @@ public class SysMenuServiceImpl implements SysMenuService {
log
.
info
(
"删除菜单成功: menuId={}"
,
menuId
);
}
// ==================== 私有辅助方法 ====================
/**
* 构建菜单树选择列表
*/
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysPasswordService.java
View file @
d043ba58
...
...
@@ -11,7 +11,7 @@ import org.springframework.stereotype.Component;
import
java.util.concurrent.TimeUnit
;
/**
* 密码服务(密码重试锁定
,与 custom-back SysPasswordService 对齐
)
* 密码服务(密码重试锁定)
*
* @author Lizh
*/
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysPostServiceImpl.java
View file @
d043ba58
...
...
@@ -10,12 +10,18 @@ import com.jomalls.custom.app.service.system.SysPostService;
import
com.jomalls.custom.app.utils.BeanMapper
;
import
com.jomalls.custom.app.vo.system.SysPostVO
;
import
com.jomalls.custom.dal.entity.SysPostEntity
;
import
com.jomalls.custom.dal.entity.SysUserPostEntity
;
import
com.jomalls.custom.domain.service.system.SysPostDomainService
;
import
com.jomalls.custom.domain.service.system.SysUserPostDomainService
;
import
com.jomalls.custom.security.SecurityUtils
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.util.StringUtils
;
import
java.time.LocalDateTime
;
import
java.util.Arrays
;
import
java.util.List
;
/**
...
...
@@ -29,10 +35,14 @@ import java.util.List;
public
class
SysPostServiceImpl
implements
SysPostService
{
private
final
SysPostDomainService
sysPostDomainService
;
private
final
SysUserPostDomainService
sysUserPostDomainService
;
@Override
public
List
<
SysPostVO
>
listAllPosts
()
{
List
<
SysPostEntity
>
entities
=
sysPostDomainService
.
list
();
// 与 custom-back selectPostAll 对齐:返回全部岗位(无过滤),按 postSort 排序
List
<
SysPostEntity
>
entities
=
sysPostDomainService
.
list
(
new
LambdaQueryWrapper
<
SysPostEntity
>()
.
orderByAsc
(
SysPostEntity:
:
getPostSort
));
return
BeanMapper
.
mapper
().
convertList
(
entities
,
SysPostVO
.
class
);
}
...
...
@@ -61,6 +71,7 @@ public class SysPostServiceImpl implements SysPostService {
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
add
(
SysPostSaveDTO
dto
)
{
SysPostEntity
post
=
BeanMapper
.
mapper
().
convert
(
dto
,
SysPostEntity
.
class
);
// 检查岗位编码唯一性
...
...
@@ -69,6 +80,14 @@ public class SysPostServiceImpl implements SysPostService {
if
(
count
>
0
)
{
throw
new
ServiceException
(
"岗位编码已存在"
);
}
// 检查岗位名称唯一性
long
nameCount
=
sysPostDomainService
.
count
(
new
LambdaQueryWrapper
<
SysPostEntity
>().
eq
(
SysPostEntity:
:
getPostName
,
post
.
getPostName
()));
if
(
nameCount
>
0
)
{
throw
new
ServiceException
(
"新增岗位'"
+
post
.
getPostName
()
+
"'失败,岗位名称已存在"
);
}
post
.
setCreateBy
(
SecurityUtils
.
getUsername
());
post
.
setCreateTime
(
LocalDateTime
.
now
());
boolean
saved
=
sysPostDomainService
.
save
(
post
);
if
(
saved
)
{
log
.
info
(
"新增岗位成功: postName={}"
,
post
.
getPostName
());
...
...
@@ -76,6 +95,7 @@ public class SysPostServiceImpl implements SysPostService {
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
edit
(
SysPostUpdateDTO
dto
)
{
SysPostEntity
post
=
BeanMapper
.
mapper
().
convert
(
dto
,
SysPostEntity
.
class
);
// 检查岗位编码唯一性(排除自身)
...
...
@@ -86,13 +106,31 @@ public class SysPostServiceImpl implements SysPostService {
if
(
count
>
0
)
{
throw
new
ServiceException
(
"岗位编码已存在"
);
}
// 检查岗位名称唯一性(排除自身)
long
nameCount
=
sysPostDomainService
.
count
(
new
LambdaQueryWrapper
<
SysPostEntity
>()
.
eq
(
SysPostEntity:
:
getPostName
,
post
.
getPostName
())
.
ne
(
post
.
getPostId
()
!=
null
,
SysPostEntity:
:
getPostId
,
post
.
getPostId
()
!=
null
?
post
.
getPostId
()
:
-
1L
));
if
(
nameCount
>
0
)
{
throw
new
ServiceException
(
"修改岗位'"
+
post
.
getPostName
()
+
"'失败,岗位名称已存在"
);
}
post
.
setUpdateBy
(
SecurityUtils
.
getUsername
());
post
.
setUpdateTime
(
LocalDateTime
.
now
());
sysPostDomainService
.
updateById
(
post
);
log
.
info
(
"修改岗位成功: postId={}"
,
post
.
getPostId
());
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
remove
(
Long
[]
postIds
)
{
for
(
Long
postId
:
postIds
)
{
// 检查岗位下是否有用户关联(有用户关联则不允许删除)
long
userCount
=
sysUserPostDomainService
.
count
(
new
LambdaQueryWrapper
<
SysUserPostEntity
>().
eq
(
SysUserPostEntity:
:
getPostId
,
postId
));
if
(
userCount
>
0
)
{
SysPostEntity
post
=
sysPostDomainService
.
getById
(
postId
);
throw
new
ServiceException
(
"岗位'"
+
(
post
!=
null
?
post
.
getPostName
()
:
postId
)
+
"'已分配用户,不能删除"
);
}
sysPostDomainService
.
removeById
(
postId
);
}
log
.
info
(
"批量删除岗位成功: count={}"
,
postIds
.
length
);
...
...
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysRoleServiceImpl.java
View file @
d043ba58
...
...
@@ -3,6 +3,7 @@ package com.jomalls.custom.app.service.system.impl;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.metadata.IPage
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.jomalls.custom.app.constant.RoleConstants
;
import
com.jomalls.custom.app.dto.system.SysRoleDataScopeDTO
;
import
com.jomalls.custom.app.dto.system.SysRoleSaveDTO
;
import
com.jomalls.custom.app.dto.system.SysRoleStatusDTO
;
...
...
@@ -15,9 +16,11 @@ import com.jomalls.custom.app.vo.system.SysRoleVO;
import
com.jomalls.custom.app.vo.system.SysUserVO
;
import
com.jomalls.custom.dal.entity.*
;
import
com.jomalls.custom.domain.service.system.*
;
import
com.jomalls.custom.security.SecurityUtils
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.util.StringUtils
;
import
java.util.*
;
...
...
@@ -42,7 +45,11 @@ public class SysRoleServiceImpl implements SysRoleService {
@Override
public
List
<
SysRoleVO
>
listAllRoles
()
{
List
<
SysRoleEntity
>
entities
=
sysRoleDomainService
.
list
();
// 过滤 delFlag='0',按 roleSort 排序
List
<
SysRoleEntity
>
entities
=
sysRoleDomainService
.
list
(
new
LambdaQueryWrapper
<
SysRoleEntity
>()
.
eq
(
SysRoleEntity:
:
getDelFlag
,
RoleConstants
.
STATUS_NORMAL
)
.
orderByAsc
(
SysRoleEntity:
:
getRoleSort
));
return
BeanMapper
.
mapper
().
convertList
(
entities
,
SysRoleVO
.
class
);
}
...
...
@@ -58,7 +65,7 @@ public class SysRoleServiceImpl implements SysRoleService {
if
(
StringUtils
.
hasText
(
role
.
getStatus
()))
{
wrapper
.
eq
(
SysRoleEntity:
:
getStatus
,
role
.
getStatus
());
}
wrapper
.
eq
(
SysRoleEntity:
:
getDelFlag
,
"0"
);
wrapper
.
eq
(
SysRoleEntity:
:
getDelFlag
,
RoleConstants
.
STATUS_NORMAL
);
wrapper
.
orderByAsc
(
SysRoleEntity:
:
getRoleSort
);
IPage
<
SysRoleEntity
>
entityPage
=
sysRoleDomainService
.
page
(
new
Page
<>(
page
.
getCurrent
(),
page
.
getSize
()),
wrapper
);
...
...
@@ -72,6 +79,7 @@ public class SysRoleServiceImpl implements SysRoleService {
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
add
(
SysRoleSaveDTO
dto
)
{
SysRoleEntity
role
=
BeanMapper
.
mapper
().
convert
(
dto
,
SysRoleEntity
.
class
);
// 检查角色名称唯一性
...
...
@@ -86,10 +94,14 @@ public class SysRoleServiceImpl implements SysRoleService {
if
(
countByKey
>
0
)
{
throw
new
ServiceException
(
"角色权限字符串已存在"
);
}
role
.
setCreateBy
(
SecurityUtils
.
getUsername
());
role
.
setCreateTime
(
new
Date
());
// 保存角色
sysRoleDomainService
.
save
(
role
);
Long
roleId
=
role
.
getRoleId
();
// 更新角色权限字符串为包含角色ID的格式(始终覆盖)
role
.
setRoleKey
(
"role_"
+
roleId
);
sysRoleDomainService
.
updateById
(
role
);
// 保存角色菜单关联
if
(
dto
.
getMenuIds
()
!=
null
)
{
for
(
Long
menuId
:
dto
.
getMenuIds
())
{
...
...
@@ -103,8 +115,14 @@ public class SysRoleServiceImpl implements SysRoleService {
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
edit
(
SysRoleUpdateDTO
dto
)
{
SysRoleEntity
role
=
BeanMapper
.
mapper
().
convert
(
dto
,
SysRoleEntity
.
class
);
// 检查是否允许操作超级管理员角色
SysRoleEntity
existingRole
=
sysRoleDomainService
.
getById
(
role
.
getRoleId
());
if
(
existingRole
!=
null
)
{
checkRoleAllowed
(
existingRole
);
}
// 检查角色名称唯一性(排除自身)
long
countByName
=
sysRoleDomainService
.
count
(
new
LambdaQueryWrapper
<
SysRoleEntity
>()
...
...
@@ -121,6 +139,7 @@ public class SysRoleServiceImpl implements SysRoleService {
if
(
countByKey
>
0
)
{
throw
new
ServiceException
(
"角色权限字符串已存在"
);
}
role
.
setUpdateBy
(
SecurityUtils
.
getUsername
());
role
.
setUpdateTime
(
new
Date
());
// 更新角色
sysRoleDomainService
.
updateById
(
role
);
...
...
@@ -139,10 +158,18 @@ public class SysRoleServiceImpl implements SysRoleService {
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
dataScope
(
SysRoleDataScopeDTO
dto
)
{
SysRoleEntity
role
=
new
SysRoleEntity
();
role
.
setRoleId
(
dto
.
getRoleId
());
// 检查是否允许操作超级管理员角色
SysRoleEntity
existingRole
=
sysRoleDomainService
.
getById
(
dto
.
getRoleId
());
if
(
existingRole
!=
null
)
{
checkRoleAllowed
(
existingRole
);
}
role
.
setDataScope
(
dto
.
getDataScope
());
role
.
setUpdateBy
(
SecurityUtils
.
getUsername
());
role
.
setUpdateTime
(
new
Date
());
// 更新角色信息
sysRoleDomainService
.
updateById
(
role
);
// 删除旧的部门关联
...
...
@@ -166,23 +193,35 @@ public class SysRoleServiceImpl implements SysRoleService {
if
(
role
==
null
)
{
throw
new
ServiceException
(
"角色不存在"
);
}
checkRoleAllowed
(
role
);
role
.
setStatus
(
dto
.
getStatus
());
role
.
setUpdateBy
(
SecurityUtils
.
getUsername
());
role
.
setUpdateTime
(
new
Date
());
sysRoleDomainService
.
updateById
(
role
);
log
.
info
(
"角色状态已修改: roleId={}, status={}"
,
dto
.
getRoleId
(),
dto
.
getStatus
());
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
remove
(
Long
[]
roleIds
)
{
for
(
Long
roleId
:
roleIds
)
{
// 检查是否允许操作超级管理员角色
SysRoleEntity
role
=
sysRoleDomainService
.
getById
(
roleId
);
if
(
role
!=
null
)
{
checkRoleAllowed
(
role
);
}
// 检查是否有用户关联(有用户关联则不允许删除)
long
userCount
=
sysUserRoleDomainService
.
count
(
new
LambdaQueryWrapper
<
SysUserRoleEntity
>().
eq
(
SysUserRoleEntity:
:
getRoleId
,
roleId
));
if
(
userCount
>
0
)
{
throw
new
ServiceException
(
"角色'"
+
(
role
!=
null
?
role
.
getRoleName
()
:
roleId
)
+
"'已分配用户,不能删除"
);
}
// 删除角色菜单关联
sysRoleMenuDomainService
.
remove
(
new
LambdaQueryWrapper
<
SysRoleMenuEntity
>().
eq
(
SysRoleMenuEntity:
:
getRoleId
,
roleId
));
// 删除角色部门关联
sysRoleDeptDomainService
.
remove
(
new
LambdaQueryWrapper
<
SysRoleDeptEntity
>().
eq
(
SysRoleDeptEntity:
:
getRoleId
,
roleId
));
// 删除用户角色关联
sysUserRoleDomainService
.
remove
(
new
LambdaQueryWrapper
<
SysUserRoleEntity
>().
eq
(
SysUserRoleEntity:
:
getRoleId
,
roleId
));
// 删除角色
sysRoleDomainService
.
removeById
(
roleId
);
}
...
...
@@ -274,4 +313,13 @@ public class SysRoleServiceImpl implements SysRoleService {
List
<
SysDeptEntity
>
tree
=
sysDeptDomainService
.
buildDeptTree
(
allDepts
);
return
BeanMapper
.
mapper
().
convertList
(
tree
,
SysDeptVO
.
class
);
}
/**
* 检查是否允许操作超级管理员角色
*/
private
void
checkRoleAllowed
(
SysRoleEntity
role
)
{
if
(
role
.
getRoleId
()
!=
null
&&
(
role
.
getRoleId
()
==
1L
||
"admin"
.
equals
(
role
.
getRoleKey
())))
{
throw
new
ServiceException
(
"不允许操作超级管理员角色"
);
}
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/service/system/impl/SysUserServiceImpl.java
View file @
d043ba58
...
...
@@ -3,11 +3,19 @@ package com.jomalls.custom.app.service.system.impl;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.core.metadata.IPage
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.jomalls.custom.app.constant.RoleConstants
;
import
com.jomalls.custom.app.constant.SecurityConstants
;
import
com.jomalls.custom.app.constant.UserConstants
;
import
com.jomalls.custom.app.dto.system.*
;
import
com.jomalls.custom.app.enums.SysUserStatusEnums
;
import
com.jomalls.custom.app.exception.ServiceException
;
import
com.jomalls.custom.app.service.system.SysRoleService
;
import
com.jomalls.custom.app.service.system.SysUserService
;
import
com.jomalls.custom.app.utils.BeanMapper
;
import
com.jomalls.custom.app.utils.CharsetKit
;
import
com.jomalls.custom.app.utils.UniqueId
;
import
com.jomalls.custom.app.vo.system.SysDeptVO
;
import
com.jomalls.custom.app.vo.system.SysRoleVO
;
import
com.jomalls.custom.app.vo.system.SysUserVO
;
import
com.jomalls.custom.dal.entity.*
;
import
com.jomalls.custom.domain.service.system.*
;
...
...
@@ -15,8 +23,10 @@ import com.jomalls.custom.security.LoginUser;
import
com.jomalls.custom.security.SecurityUtils
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.collections.CollectionUtils
;
import
org.springframework.security.crypto.password.PasswordEncoder
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.util.StringUtils
;
import
java.util.*
;
...
...
@@ -36,6 +46,7 @@ public class SysUserServiceImpl implements SysUserService {
private
final
SysUserRoleDomainService
sysUserRoleDomainService
;
private
final
SysUserPostDomainService
sysUserPostDomainService
;
private
final
SysRoleDomainService
sysRoleDomainService
;
private
final
SysRoleService
sysRoleService
;
private
final
SysDeptDomainService
sysDeptDomainService
;
private
final
SysPostDomainService
sysPostDomainService
;
private
final
PasswordEncoder
passwordEncoder
;
...
...
@@ -55,7 +66,7 @@ public class SysUserServiceImpl implements SysUserService {
if
(
user
.
getDeptId
()
!=
null
)
{
wrapper
.
eq
(
SysUserEntity:
:
getDeptId
,
user
.
getDeptId
());
}
wrapper
.
eq
(
SysUserEntity:
:
getDelFlag
,
"0"
);
wrapper
.
eq
(
SysUserEntity:
:
getDelFlag
,
SysUserStatusEnums
.
NORMAL
.
getCode
()
);
wrapper
.
orderByAsc
(
SysUserEntity:
:
getUserId
);
IPage
<
SysUserEntity
>
entityPage
=
sysUserDomainService
.
page
(
new
Page
<>(
page
.
getCurrent
(),
page
.
getSize
()),
wrapper
);
...
...
@@ -70,76 +81,139 @@ public class SysUserServiceImpl implements SysUserService {
}
// Entity → VO
SysUserVO
userVO
=
BeanMapper
.
mapper
().
convert
(
user
,
SysUserVO
.
class
);
// 查询角色列表
List
<
SysRoleEntity
>
roles
=
sysRoleDomainService
.
selectRoleListByUserId
(
userId
);
// 查询角色ID列表
List
<
SysUserRoleEntity
>
userRoles
=
sysUserRoleDomainService
.
list
(
new
LambdaQueryWrapper
<
SysUserRoleEntity
>().
eq
(
SysUserRoleEntity:
:
getUserId
,
userId
));
List
<
Long
>
roleIds
=
userRoles
.
stream
().
map
(
SysUserRoleEntity:
:
getRoleId
).
toList
();
// 查询岗位ID列表
List
<
SysUserPostEntity
>
userPosts
=
sysUserPostDomainService
.
list
(
new
LambdaQueryWrapper
<
SysUserPostEntity
>().
eq
(
SysUserPostEntity:
:
getUserId
,
userId
));
List
<
Long
>
postIds
=
userPosts
.
stream
()
.
map
(
SysUserPostEntity:
:
getPostId
)
.
collect
(
Collectors
.
toList
());
List
<
Long
>
postIds
=
userPosts
.
stream
().
map
(
SysUserPostEntity:
:
getPostId
).
toList
();
Map
<
String
,
Object
>
result
=
new
HashMap
<>();
result
.
put
(
"user"
,
userVO
);
result
.
put
(
"role
s"
,
roles
!=
null
?
roles
:
Collections
.
emptyList
()
);
result
.
put
(
"role
Ids"
,
roleIds
);
result
.
put
(
"postIds"
,
postIds
);
return
result
;
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
String
add
(
SysUserSaveDTO
dto
)
{
// DTO → Entity
SysUserEntity
user
=
BeanMapper
.
mapper
().
convert
(
dto
,
SysUserEntity
.
class
);
// 检查用户名唯一性
if
(!
StringUtils
.
hasText
(
user
.
getUserName
()))
{
throw
new
ServiceException
(
"新增用户'"
+
user
.
getUserName
()
+
"'失败,登录账号不能为空"
);
}
if
(
CharsetKit
.
containsChinese
(
user
.
getUserName
()))
{
throw
new
ServiceException
(
"新增用户'"
+
user
.
getUserName
()
+
"'失败,登录账号请使用英文字符"
);
}
// 用户名校验
long
count
=
sysUserDomainService
.
count
(
new
LambdaQueryWrapper
<
SysUserEntity
>().
eq
(
SysUserEntity:
:
getUserName
,
user
.
getUserName
()));
if
(
count
>
0
)
{
throw
new
ServiceException
(
"用户账号已存在"
);
throw
new
ServiceException
(
"新增用户'"
+
user
.
getUserName
()
+
"'失败,登录账号已存在"
);
}
// 手机号唯一性校验
if
(
StringUtils
.
hasText
(
user
.
getPhonenumber
()))
{
long
phoneCount
=
sysUserDomainService
.
count
(
new
LambdaQueryWrapper
<
SysUserEntity
>().
eq
(
SysUserEntity:
:
getPhonenumber
,
user
.
getPhonenumber
()));
if
(
phoneCount
>
0
)
{
throw
new
ServiceException
(
"新增用户'"
+
user
.
getUserName
()
+
"'失败,手机号码已存在"
);
}
}
// 邮箱唯一性校验
if
(
StringUtils
.
hasText
(
user
.
getEmail
()))
{
long
emailCount
=
sysUserDomainService
.
count
(
new
LambdaQueryWrapper
<
SysUserEntity
>().
eq
(
SysUserEntity:
:
getEmail
,
user
.
getEmail
()));
if
(
emailCount
>
0
)
{
throw
new
ServiceException
(
"新增用户'"
+
user
.
getUserName
()
+
"'失败,邮箱账号已存在"
);
}
}
// 如果未提供密码,设置默认密码
// 生成随机密码
String
originalPassword
=
user
.
getPassword
();
if
(!
StringUtils
.
hasText
(
originalPassword
))
{
originalPassword
=
"123456"
;
user
.
setPassword
(
originalPassword
);
originalPassword
=
UniqueId
.
generateUniqueId
(
UserConstants
.
INIT_PASSWORD_LENGTH
);
}
//
密码
加密
user
.
setPassword
(
passwordEncoder
.
encode
(
user
.
getPassword
()
));
//
MD5
加密
user
.
setPassword
(
passwordEncoder
.
encode
(
originalPassword
));
user
.
setCreateTime
(
new
Date
());
user
.
setCreateBy
(
SecurityUtils
.
getUsername
());
// 保存用户
sysUserDomainService
.
save
(
user
);
Long
userId
=
user
.
getUserId
();
// 保存用户角色关联
if
(
dto
.
getRoleIds
()
!=
null
)
{
// 批量插入用户角色关联
if
(
dto
.
getRoleIds
()
!=
null
&&
dto
.
getRoleIds
().
length
>
0
)
{
List
<
SysUserRoleEntity
>
roleList
=
new
ArrayList
<>(
dto
.
getRoleIds
().
length
);
for
(
Long
roleId
:
dto
.
getRoleIds
())
{
SysUserRoleEntity
u
serRole
=
new
SysUserRoleEntity
();
u
serRole
.
setUserId
(
userId
);
u
serRole
.
setRoleId
(
roleId
);
sysUserRoleDomainService
.
save
(
userRole
);
SysUserRoleEntity
u
r
=
new
SysUserRoleEntity
();
u
r
.
setUserId
(
userId
);
u
r
.
setRoleId
(
roleId
);
roleList
.
add
(
ur
);
}
sysUserRoleDomainService
.
saveBatch
(
roleList
);
}
// 保存用户岗位关联
if
(
dto
.
getPostIds
()
!=
null
)
{
// 批量插入用户岗位关联
if
(
dto
.
getPostIds
()
!=
null
&&
dto
.
getPostIds
().
length
>
0
)
{
List
<
SysUserPostEntity
>
postList
=
new
ArrayList
<>(
dto
.
getPostIds
().
length
);
for
(
Long
postId
:
dto
.
getPostIds
())
{
SysUserPostEntity
u
serPost
=
new
SysUserPostEntity
();
u
serPost
.
setUserId
(
userId
);
u
serPost
.
setPostId
(
postId
);
sysUserPostDomainService
.
save
(
userPost
);
SysUserPostEntity
u
p
=
new
SysUserPostEntity
();
u
p
.
setUserId
(
userId
);
u
p
.
setPostId
(
postId
);
postList
.
add
(
up
);
}
sysUserPostDomainService
.
saveBatch
(
postList
);
}
log
.
info
(
"新增用户成功: userName={}"
,
user
.
getUserName
());
return
originalPassword
;
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
edit
(
SysUserUpdateDTO
dto
)
{
// 检查用户是否存在
SysUserEntity
existing
=
sysUserDomainService
.
getById
(
dto
.
getUserId
());
if
(
existing
==
null
)
{
throw
new
ServiceException
(
"用户不存在"
);
}
checkUserAllowed
(
existing
);
// DTO → Entity
SysUserEntity
user
=
BeanMapper
.
mapper
().
convert
(
dto
,
SysUserEntity
.
class
);
// 用户名校验(排除自身)
if
(
StringUtils
.
hasText
(
user
.
getUserName
()))
{
long
nameCount
=
sysUserDomainService
.
count
(
new
LambdaQueryWrapper
<
SysUserEntity
>()
.
eq
(
SysUserEntity:
:
getUserName
,
user
.
getUserName
())
.
ne
(
SysUserEntity:
:
getUserId
,
existing
.
getUserId
()));
if
(
nameCount
>
0
)
{
throw
new
ServiceException
(
"修改用户'"
+
user
.
getUserName
()
+
"'失败,登录账号已存在"
);
}
}
// 手机号唯一性校验(排除自身)
if
(
StringUtils
.
hasText
(
user
.
getPhonenumber
()))
{
long
phoneCount
=
sysUserDomainService
.
count
(
new
LambdaQueryWrapper
<
SysUserEntity
>()
.
eq
(
SysUserEntity:
:
getPhonenumber
,
user
.
getPhonenumber
())
.
ne
(
SysUserEntity:
:
getUserId
,
existing
.
getUserId
()));
if
(
phoneCount
>
0
)
{
throw
new
ServiceException
(
"修改用户'"
+
user
.
getUserName
()
+
"'失败,手机号码已存在"
);
}
}
// 邮箱唯一性校验(排除自身)
if
(
StringUtils
.
hasText
(
user
.
getEmail
()))
{
long
emailCount
=
sysUserDomainService
.
count
(
new
LambdaQueryWrapper
<
SysUserEntity
>()
.
eq
(
SysUserEntity:
:
getEmail
,
user
.
getEmail
())
.
ne
(
SysUserEntity:
:
getUserId
,
existing
.
getUserId
()));
if
(
emailCount
>
0
)
{
throw
new
ServiceException
(
"修改用户'"
+
user
.
getUserName
()
+
"'失败,邮箱账号已存在"
);
}
}
// 更新用户信息
user
.
setUpdateBy
(
SecurityUtils
.
getUsername
());
user
.
setUpdateTime
(
new
Date
());
...
...
@@ -170,15 +244,27 @@ public class SysUserServiceImpl implements SysUserService {
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
remove
(
Long
[]
userIds
)
{
for
(
Long
userId
:
userIds
)
{
SysUserEntity
user
=
sysUserDomainService
.
getById
(
userId
);
if
(
user
!=
null
)
{
// 逻辑删除
user
.
setDelFlag
(
"1"
);
sysUserDomainService
.
updateById
(
user
);
checkUserAllowed
(
user
);
}
}
// 批量删除用户-角色关联
sysUserRoleDomainService
.
remove
(
new
LambdaQueryWrapper
<
SysUserRoleEntity
>().
in
(
SysUserRoleEntity:
:
getUserId
,
Arrays
.
asList
(
userIds
)));
// 批量删除用户-岗位关联
sysUserPostDomainService
.
remove
(
new
LambdaQueryWrapper
<
SysUserPostEntity
>().
in
(
SysUserPostEntity:
:
getUserId
,
Arrays
.
asList
(
userIds
)));
// 逻辑删除用户
for
(
Long
userId
:
userIds
)
{
SysUserEntity
user
=
new
SysUserEntity
();
user
.
setUserId
(
userId
);
user
.
setDelFlag
(
"1"
);
sysUserDomainService
.
updateById
(
user
);
}
log
.
info
(
"批量删除用户成功: count={}"
,
userIds
.
length
);
}
...
...
@@ -188,6 +274,7 @@ public class SysUserServiceImpl implements SysUserService {
if
(
user
==
null
)
{
throw
new
ServiceException
(
"用户不存在"
);
}
checkUserAllowed
(
user
);
user
.
setPassword
(
passwordEncoder
.
encode
(
dto
.
getPassword
()));
sysUserDomainService
.
updateById
(
user
);
log
.
info
(
"用户密码已重置: userId={}"
,
dto
.
getUserId
());
...
...
@@ -199,6 +286,7 @@ public class SysUserServiceImpl implements SysUserService {
if
(
user
==
null
)
{
throw
new
ServiceException
(
"用户不存在"
);
}
checkUserAllowed
(
user
);
user
.
setStatus
(
dto
.
getStatus
());
sysUserDomainService
.
updateById
(
user
);
log
.
info
(
"用户状态已修改: userId={}, status={}"
,
dto
.
getUserId
(),
dto
.
getStatus
());
...
...
@@ -238,20 +326,16 @@ public class SysUserServiceImpl implements SysUserService {
}
List
<
SysUserPostEntity
>
userPosts
=
sysUserPostDomainService
.
list
(
new
LambdaQueryWrapper
<
SysUserPostEntity
>().
eq
(
SysUserPostEntity:
:
getUserId
,
loginUser
.
getUserId
()));
if
(
userPosts
==
null
||
userPosts
.
isEmpty
(
))
{
if
(
CollectionUtils
.
isEmpty
(
userPosts
))
{
return
""
;
}
List
<
Long
>
postIds
=
userPosts
.
stream
()
.
map
(
SysUserPostEntity:
:
getPostId
)
.
collect
(
Collectors
.
toList
());
List
<
Long
>
postIds
=
userPosts
.
stream
().
map
(
SysUserPostEntity:
:
getPostId
).
toList
();
List
<
SysPostEntity
>
posts
=
sysPostDomainService
.
listByIds
(
postIds
);
if
(
posts
==
null
||
posts
.
isEmpty
(
))
{
if
(
CollectionUtils
.
isEmpty
(
posts
))
{
return
""
;
}
return
posts
.
stream
()
.
map
(
SysPostEntity:
:
getPostName
)
.
filter
(
Objects:
:
nonNull
)
.
collect
(
Collectors
.
joining
(
", "
));
return
posts
.
stream
().
map
(
SysPostEntity:
:
getPostName
)
.
filter
(
Objects:
:
nonNull
).
collect
(
Collectors
.
joining
(
", "
));
}
@Override
...
...
@@ -307,12 +391,28 @@ public class SysUserServiceImpl implements SysUserService {
}
@Override
public
List
<
Long
>
getAuthRoleList
(
Long
userId
)
{
public
SysUserVO
getById
(
Long
userId
)
{
SysUserEntity
entity
=
sysUserDomainService
.
getById
(
userId
);
return
BeanMapper
.
mapper
().
convert
(
entity
,
SysUserVO
.
class
);
}
@Override
public
List
<
SysRoleVO
>
getAuthRoleList
(
Long
userId
)
{
// 返回全部角色,已分配的角色设置 flag=true
List
<
SysRoleVO
>
allRoles
=
sysRoleService
.
listAllRoles
();
// 查询用户已分配的角色ID
List
<
SysUserRoleEntity
>
userRoles
=
sysUserRoleDomainService
.
list
(
new
LambdaQueryWrapper
<
SysUserRoleEntity
>().
eq
(
SysUserRoleEntity:
:
getUserId
,
userId
));
return
userRoles
.
stream
()
.
map
(
SysUserRoleEntity:
:
getRoleId
)
.
collect
(
Collectors
.
toList
());
Set
<
Long
>
assignedRoleIds
=
userRoles
.
stream
().
map
(
SysUserRoleEntity:
:
getRoleId
).
collect
(
Collectors
.
toSet
());
// 设置 flag:已分配的角色标记为 true
for
(
SysRoleVO
role
:
allRoles
)
{
role
.
setFlag
(
assignedRoleIds
.
contains
(
role
.
getRoleId
()));
}
// admin 用户看到全部角色,非 admin 不显示 admin 角色
if
(!
SecurityConstants
.
ADMIN_USER_ID
.
equals
(
userId
))
{
allRoles
=
allRoles
.
stream
().
filter
(
r
->
!
RoleConstants
.
ADMIN_USER
.
equals
(
r
.
getRoleKey
())).
collect
(
Collectors
.
toList
());
}
return
allRoles
;
}
@Override
...
...
@@ -336,4 +436,13 @@ public class SysUserServiceImpl implements SysUserService {
List
<
SysDeptEntity
>
tree
=
sysDeptDomainService
.
buildDeptTree
(
allDepts
);
return
BeanMapper
.
mapper
().
convertList
(
tree
,
SysDeptVO
.
class
);
}
/**
* 检查是否允许操作超级管理员用户
*/
private
void
checkUserAllowed
(
SysUserEntity
user
)
{
if
(
user
.
getUserId
()
!=
null
&&
SecurityConstants
.
ADMIN_USER_ID
.
equals
(
user
.
getUserId
()))
{
throw
new
ServiceException
(
"不允许操作超级管理员用户"
);
}
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/utils/CharsetKit.java
View file @
d043ba58
...
...
@@ -86,4 +86,26 @@ public class CharsetKit {
public
static
String
systemCharset
()
{
return
Charset
.
defaultCharset
().
name
();
}
public
static
boolean
containsChinese
(
String
str
)
{
if
(
str
==
null
||
str
.
isEmpty
())
{
return
false
;
}
// 中文字符的 Unicode 范围
// 基本汉字:4E00-9FA5
// 扩展A:3400-4DBF
// 扩展B-F:20000-2EBEF
for
(
char
c
:
str
.
toCharArray
())
{
// 最常用的汉字范围
if
(
c
>=
0x4E00
&&
c
<=
0x9FA5
)
{
return
true
;
}
// 如果需要包含扩展汉字,加上下面的判断
//if ((c >= 0x3400 && c <= 0x4DBF) || (c >= 0x20000 && c <= 0x2EBEF)) {
// return true;
//}
}
return
false
;
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/utils/UniqueId.java
0 → 100644
View file @
d043ba58
package
com
.
jomalls
.
custom
.
app
.
utils
;
import
java.util.UUID
;
/**
* @Author: Lizh
* @Date: 2026/7/15 14:36
* @Description: 唯一ID
* @Version: 1.0
*/
public
class
UniqueId
{
private
static
final
int
START_INDEX
=
1
;
/**
* 生成UUID
* @param length
* @return
*/
public
static
String
generateUniqueId
(
int
length
)
{
return
UUID
.
randomUUID
().
toString
().
replace
(
"-"
,
""
).
substring
(
START_INDEX
,
length
);
}
}
custom-server-app/src/main/java/com/jomalls/custom/app/vo/system/SysRoleVO.java
View file @
d043ba58
...
...
@@ -73,4 +73,8 @@ public class SysRoleVO implements Serializable {
@JsonProperty
(
"deptIds"
)
@Schema
(
description
=
"部门ID列表"
)
private
Long
[]
deptIds
;
@JsonProperty
(
"flag"
)
@Schema
(
description
=
"用户是否已分配该角色"
)
private
Boolean
flag
;
}
custom-server-core/src/main/java/com/jomalls/custom/security/TokenHandle.java
View file @
d043ba58
...
...
@@ -15,10 +15,9 @@ import org.springframework.stereotype.Component;
import
org.springframework.util.StringUtils
;
import
javax.crypto.SecretKey
;
import
java.util.Date
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Set
;
import
java.nio.charset.StandardCharsets
;
import
java.util.*
;
import
java.util.concurrent.TimeUnit
;
/**
* Token 验证处理服务
...
...
@@ -252,7 +251,7 @@ public class TokenHandle {
redisKey
,
JSON
.
toJSONString
(
loginUser
),
expireTime
*
60L
,
java
.
util
.
concurrent
.
TimeUnit
.
SECONDS
TimeUnit
.
SECONDS
);
}
...
...
@@ -269,19 +268,21 @@ public class TokenHandle {
*/
private
String
buildJwtCompatibly
(
String
uuid
,
LoginUser
loginUser
)
{
try
{
java
.
util
.
Base64
.
Encoder
encoder
=
java
.
util
.
Base64
.
getUrlEncoder
().
withoutPadding
();
Base64
.
Encoder
encoder
=
Base64
.
getUrlEncoder
().
withoutPadding
();
log
.
info
(
JSON
.
toJSONString
(
loginUser
));
// Header: {"alg":"HS512"}
String
header
=
"{\"alg\":\"HS512\"}"
;
String
headerBase64
=
encoder
.
encodeToString
(
header
.
getBytes
(
java
.
nio
.
charset
.
StandardCharsets
.
UTF_8
));
header
.
getBytes
(
StandardCharsets
.
UTF_8
));
// Payload
: 仅含 UUID + 基本标识,不含 permissions/deptId(全量信息在 Redis
)
java
.
util
.
LinkedHashMap
<
String
,
Object
>
claims
=
new
java
.
util
.
LinkedHashMap
<>();
// Payload
:基本标识 + deptId + permissions(前端从 JWT 解析 sysUser 信息
)
LinkedHashMap
<
String
,
Object
>
claims
=
new
LinkedHashMap
<>();
claims
.
put
(
"login_user_key"
,
uuid
);
claims
.
put
(
"sub"
,
loginUser
.
getUsername
());
claims
.
put
(
"account"
,
loginUser
.
getUsername
());
claims
.
put
(
"id"
,
loginUser
.
getUserId
());
claims
.
put
(
"deptId"
,
loginUser
.
getDeptId
());
claims
.
put
(
"permissions"
,
loginUser
.
getPermissions
());
// JWT 24 小时硬过期(与 custom-back TOKEN_TIMEOUT = 86400000L 一致)
claims
.
put
(
"exp"
,
(
System
.
currentTimeMillis
()
+
86400000L
)
/
1000
);
...
...
@@ -343,16 +344,12 @@ public class TokenHandle {
*/
public
void
refreshToken
(
LoginUser
loginUser
)
{
if
(
stringRedisTemplate
!=
null
&&
loginUser
!=
null
&&
org
.
springframework
.
util
.
StringUtils
.
hasText
(
loginUser
.
getToken
()))
{
&&
StringUtils
.
hasText
(
loginUser
.
getToken
()))
{
String
redisKey
=
REDIS_TOKEN_PREFIX
+
loginUser
.
getToken
();
loginUser
.
setLoginTime
(
System
.
currentTimeMillis
());
loginUser
.
setExpireTime
(
System
.
currentTimeMillis
()
+
expireTime
*
60
*
1000L
);
stringRedisTemplate
.
opsForValue
().
set
(
redisKey
,
JSON
.
toJSONString
(
loginUser
),
expireTime
*
60L
,
java
.
util
.
concurrent
.
TimeUnit
.
SECONDS
);
stringRedisTemplate
.
opsForValue
().
set
(
redisKey
,
JSON
.
toJSONString
(
loginUser
),
expireTime
*
60L
,
java
.
util
.
concurrent
.
TimeUnit
.
SECONDS
);
}
}
...
...
custom-server-domain/src/main/resources/mapper/SysMenuMapper.xml
View file @
d043ba58
...
...
@@ -62,18 +62,19 @@
AND ur.user_id = #{userId}
</select>
<!-- 根据用户ID查询菜单树 -->
<!-- 根据用户ID查询菜单树
(与 custom-back 完全对齐:JOIN 方式,含 role.status 过滤)
-->
<select
id=
"selectMenuTreeByUserId"
resultType=
"com.jomalls.custom.dal.entity.SysMenuEntity"
>
SELECT DISTINCT m.* FROM sys_menu m
<if
test=
"userId != 1"
>
LEFT JOIN sys_role_menu rm ON m.menu_id = rm.menu_id
LEFT JOIN sys_user_role ur ON rm.role_id = ur.role_id
LEFT JOIN sys_role ro ON ur.role_id = ro.role_id
</if>
WHERE m.menu_type IN ('M', 'C')
AND m.status = '0'
<if
test=
"userId != 1"
>
AND m.menu_id IN (
SELECT rm.menu_id FROM sys_role_menu rm
WHERE rm.role_id IN (
SELECT ur.role_id FROM sys_user_role ur WHERE ur.user_id = #{userId}
)
)
AND ur.user_id = #{userId}
AND ro.status = '0'
</if>
ORDER BY m.parent_id, m.order_num
</select>
...
...
custom-server-starter/src/main/java/com/jomalls/custom/config/CommonExceptionHandlerAdvice.java
View file @
d043ba58
...
...
@@ -91,8 +91,7 @@ public class CommonExceptionHandlerAdvice {
@ExceptionHandler
(
ServiceException
.
class
)
public
ResponseEntity
<
R
<
Object
>>
handleServiceException
(
ServiceException
e
)
{
log
.
debug
(
"[ 业务异常 ] code={}, {}"
,
e
.
getCode
(),
e
.
getMessage
(),
e
);
HttpStatus
httpStatus
=
CodeEnum
.
MAP
.
getOrDefault
(
e
.
getCode
(),
HttpStatus
.
OK
);
return
ResponseEntity
.
status
(
httpStatus
).
body
(
R
.
fail
(
e
.
getCode
(),
e
.
getMessage
()));
return
ResponseEntity
.
status
(
HttpStatus
.
OK
).
body
(
R
.
fail
(
e
.
getCode
(),
e
.
getMessage
()));
}
/**
...
...
@@ -101,7 +100,7 @@ public class CommonExceptionHandlerAdvice {
@ExceptionHandler
(
RemoteServiceException
.
class
)
public
ResponseEntity
<
R
<
Object
>>
handleRemoteServiceException
(
RemoteServiceException
e
)
{
log
.
debug
(
"[ 远程服务异常 ] status={}, {}"
,
e
.
getStatusCode
(),
e
.
getMessage
(),
e
);
return
ResponseEntity
.
status
(
HttpStatus
.
INTERNAL_SERVER_ERROR
)
return
ResponseEntity
.
status
(
HttpStatus
.
OK
)
.
body
(
R
.
fail
(
e
.
getStatusCode
(),
e
.
getMessage
()));
}
...
...
@@ -111,7 +110,7 @@ public class CommonExceptionHandlerAdvice {
@ExceptionHandler
(
RuntimeException
.
class
)
public
ResponseEntity
<
R
<
Object
>>
handleRuntimeException
(
Exception
e
)
{
log
.
debug
(
"[ 运行时异常 ] {}"
,
e
.
getMessage
(),
e
);
return
ResponseEntity
.
status
(
HttpStatus
.
INTERNAL_SERVER_ERROR
)
return
ResponseEntity
.
status
(
HttpStatus
.
OK
)
.
body
(
R
.
fail
(
e
.
getMessage
()));
}
...
...
@@ -121,7 +120,7 @@ public class CommonExceptionHandlerAdvice {
@ExceptionHandler
(
Exception
.
class
)
public
ResponseEntity
<
R
<
Object
>>
handleException
(
Exception
e
)
{
log
.
debug
(
"[ 未捕获异常 ] {}"
,
e
.
getMessage
(),
e
);
return
ResponseEntity
.
status
(
HttpStatus
.
INTERNAL_SERVER_ERROR
)
return
ResponseEntity
.
status
(
HttpStatus
.
OK
)
.
body
(
R
.
fail
(
CodeEnum
.
FAIL
.
getCode
(),
e
.
getMessage
()));
}
}
custom-server-webapp/src/main/java/com/jomalls/custom/webapp/controller/system/SysRoleController.java
View file @
d043ba58
...
...
@@ -3,12 +3,17 @@ package com.jomalls.custom.webapp.controller.system;
import
com.baomidou.mybatisplus.core.metadata.IPage
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.jomalls.custom.app.annotation.RequiresPermissions
;
import
com.jomalls.custom.app.constant.SecurityConstants
;
import
com.jomalls.custom.app.dto.system.*
;
import
com.jomalls.custom.app.service.system.SysRoleService
;
import
com.jomalls.custom.app.vo.system.SysDeptVO
;
import
com.jomalls.custom.app.vo.system.SysRoleVO
;
import
com.jomalls.custom.app.vo.system.SysUserVO
;
import
com.jomalls.custom.dal.entity.SysMenuEntity
;
import
com.jomalls.custom.domain.service.system.SysMenuDomainService
;
import
com.jomalls.custom.security.LoginUser
;
import
com.jomalls.custom.security.SecurityUtils
;
import
com.jomalls.custom.security.TokenHandle
;
import
com.jomalls.custom.app.exception.ServiceException
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.tags.Tag
;
...
...
@@ -16,8 +21,10 @@ import lombok.RequiredArgsConstructor;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.HashSet
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
/**
* 角色管理 Controller
...
...
@@ -32,6 +39,8 @@ import java.util.Map;
public
class
SysRoleController
{
private
final
SysRoleService
sysRoleService
;
private
final
SysMenuDomainService
sysMenuDomainService
;
private
final
TokenHandle
tokenHandle
;
@Operation
(
summary
=
"查询角色列表(无权限要求,用于下拉框)"
)
@GetMapping
(
"/optionselect"
)
...
...
@@ -69,11 +78,15 @@ public class SysRoleController {
@PutMapping
public
void
edit
(
@RequestBody
SysRoleUpdateDTO
dto
)
{
sysRoleService
.
edit
(
dto
);
// 刷新 LoginUser 缓存(非管理员用户的权限可能发生变化)
if
(
SecurityUtils
.
getUserId
()
!=
null
&&
!
SecurityUtils
.
getUserId
().
equals
(
1L
))
{
// TODO: 如果当前用户所属角色被修改,需要刷新 token 缓存中的 permissions
// 在 Redis TokenStore 场景下,应清除或刷新对应用户的缓存权限
log
.
debug
(
"角色更新完成,需要刷新相关用户的LoginUser缓存: roleId={}"
,
dto
.
getRoleId
());
// 角色修改后,刷新缓存用户权限
LoginUser
loginUser
=
SecurityUtils
.
getLoginUser
();
if
(
loginUser
!=
null
&&
loginUser
.
getUserId
()
!=
null
&&
SecurityConstants
.
ADMIN_USER_ID
.
equals
(
loginUser
.
getUserId
()))
{
// 重新查询权限
Set
<
String
>
perms
=
new
HashSet
<>();
List
<
String
>
permList
=
sysMenuDomainService
.
selectMenuPermsByUserId
(
loginUser
.
getUserId
());
if
(
permList
!=
null
)
perms
.
addAll
(
permList
);
loginUser
.
setPermissions
(
perms
);
tokenHandle
.
refreshToken
(
loginUser
);
}
}
...
...
custom-server-webapp/src/main/java/com/jomalls/custom/webapp/controller/system/SysUserController.java
View file @
d043ba58
...
...
@@ -3,11 +3,14 @@ package com.jomalls.custom.webapp.controller.system;
import
com.baomidou.mybatisplus.core.metadata.IPage
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.jomalls.custom.app.annotation.RequiresPermissions
;
import
com.jomalls.custom.app.constant.RoleConstants
;
import
com.jomalls.custom.app.constant.SecurityConstants
;
import
com.jomalls.custom.app.dto.system.*
;
import
com.jomalls.custom.app.service.system.SysPostService
;
import
com.jomalls.custom.app.service.system.SysRoleService
;
import
com.jomalls.custom.app.service.system.SysUserService
;
import
com.jomalls.custom.app.vo.system.SysDeptVO
;
import
com.jomalls.custom.app.vo.system.SysRoleVO
;
import
com.jomalls.custom.app.vo.system.SysUserVO
;
import
com.jomalls.custom.security.SecurityUtils
;
import
com.jomalls.custom.app.exception.ServiceException
;
...
...
@@ -19,10 +22,7 @@ import lombok.extern.slf4j.Slf4j;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.multipart.MultipartFile
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.*
;
/**
* 用户管理 Controller
...
...
@@ -55,15 +55,18 @@ public class SysUserController {
@Operation
(
summary
=
"查询用户详情(含角色、岗位)"
)
@RequiresPermissions
(
"system:user:query"
)
@GetMapping
(
value
=
{
"/"
,
"/{userId}"
})
public
R
<
Object
>
getInfo
(
@PathVariable
(
value
=
"userId"
,
required
=
false
)
Long
userId
)
{
public
R
<
Object
>
getInfo
(
@PathVariable
(
required
=
false
)
Long
userId
)
{
R
<
Object
>
result
=
R
.
ok
();
if
(
userId
!=
null
)
{
Map
<
String
,
Object
>
info
=
sysUserService
.
getInfo
(
userId
);
result
.
put
(
"data"
,
info
.
get
(
"user"
));
result
.
put
(
"postIds"
,
info
.
get
(
"postIds"
));
result
.
put
(
"roleIds"
,
info
.
get
(
"roleIds"
)
!=
null
?
info
.
get
(
"roleIds"
)
:
info
.
get
(
"roles"
)
);
result
.
put
(
"roleIds"
,
info
.
get
(
"roleIds"
));
}
result
.
put
(
"roles"
,
sysRoleService
.
listAllRoles
());
// admin 用户看到全部角色,非 admin 不显示 admin 角色
List
<
SysRoleVO
>
roles
=
sysRoleService
.
listAllRoles
();
result
.
put
(
"roles"
,
(
SecurityConstants
.
ADMIN_USER_ID
.
equals
(
userId
))
?
roles
:
roles
.
stream
().
filter
(
r
->
!
RoleConstants
.
ADMIN_USER
.
equals
(
r
.
getRoleKey
())).
toList
());
result
.
put
(
"posts"
,
sysPostService
.
listAllPosts
());
return
result
;
}
...
...
@@ -124,21 +127,26 @@ public class SysUserController {
@Operation
(
summary
=
"更新当前用户头像"
)
@PostMapping
(
"/profile/avatar"
)
public
R
<
Object
>
updateAvatar
(
@RequestParam
(
"avatarfile"
)
MultipartFile
file
)
{
public
Map
<
String
,
String
>
updateAvatar
(
@RequestParam
(
"avatarfile"
)
MultipartFile
file
)
{
// TODO: 实际头像上传处理(保存文件到服务器/OSS),此处模拟返回
log
.
info
(
"上传头像文件: {}"
,
file
.
getOriginalFilename
());
String
avatarUrl
=
"/profile/avatar/"
+
file
.
getOriginalFilename
();
sysUserService
.
updateAvatar
(
avatarUrl
);
return
R
.
ok
().
put
(
"imgUrl"
,
avatarUrl
);
Map
<
String
,
String
>
result
=
new
HashMap
<>();
result
.
put
(
"avatarUrl"
,
avatarUrl
);
return
result
;
}
@Operation
(
summary
=
"查询用户已分配的角色
ID列表
"
)
@Operation
(
summary
=
"查询用户已分配的角色
(含 user 对象和角色列表)
"
)
@RequiresPermissions
(
"system:user:query"
)
@GetMapping
(
"/authRole/{userId}"
)
public
Map
<
String
,
Object
>
authRole
(
@PathVariable
Long
userId
)
{
// 返回 user + 全部角色列表(含 flag 标识已分配)
Map
<
String
,
Object
>
result
=
new
java
.
util
.
HashMap
<>();
result
.
put
(
"userId"
,
userId
);
result
.
put
(
"roleIds"
,
sysUserService
.
getAuthRoleList
(
userId
));
SysUserVO
user
=
sysUserService
.
getById
(
userId
);
result
.
put
(
"user"
,
user
);
// admin 用户看到全部角色,非 admin 不显示 admin 角色
result
.
put
(
"roles"
,
sysUserService
.
getAuthRoleList
(
userId
));
return
result
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment