feat: 用户管理 CRUD 接口 (Phase 6)

- 新增 SysUserController: query/detail/save/update/remove/reset-password/role-options
- 扩展 ISysUserService + SysUserServiceImpl: 分页查询、详情、增删改、重置密码
- 新增 SysUserSaveReq 请求类
- 用户角色关联同步维护(增删改时自动更新 sys_user_role)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
chenjy 2026-05-25 09:11:57 +08:00
parent f4f8470dfe
commit 5540107aa1
4 changed files with 287 additions and 12 deletions

View File

@ -0,0 +1,82 @@
package com.chinaweal.youfool.prj.modules.system.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chinaweal.youfool.framework.springboot.rest.RestResult;
import com.chinaweal.youfool.prj.modules.system.entity.query.SysUserQuery;
import com.chinaweal.youfool.prj.modules.system.entity.req.SysUserSaveReq;
import com.chinaweal.youfool.prj.modules.system.entity.vo.SysUserVO;
import com.chinaweal.youfool.prj.modules.system.service.ISysRoleService;
import com.chinaweal.youfool.prj.modules.system.service.ISysUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
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;
import java.util.Map;
/**
* 用户管理 Controller
*
* @author chenjy
* @since 2026/05/25
*/
@Slf4j
@RestController
@RequestMapping("/api/sys-user")
@AllArgsConstructor
@Tag(name = "用户管理")
public class SysUserController {
private final ISysUserService sysUserService;
private final ISysRoleService sysRoleService;
@PostMapping("query")
@Operation(summary = "分页查询用户列表")
public RestResult<Page<SysUserVO>> queryList(@RequestBody SysUserQuery query) {
return sysUserService.queryList(query);
}
@GetMapping("detail")
@Operation(summary = "获取用户详情")
public RestResult<SysUserVO> getDetail(@RequestParam String id) {
return sysUserService.getDetail(id);
}
@PostMapping("save")
@Operation(summary = "新增用户")
public RestResult<String> save(@RequestBody SysUserSaveReq req) {
return sysUserService.save(req);
}
@PostMapping("update")
@Operation(summary = "编辑用户")
public RestResult<?> update(@RequestBody SysUserSaveReq req) {
return sysUserService.update(req);
}
@PostMapping("remove")
@Operation(summary = "删除用户")
public RestResult<?> remove(@RequestBody Map<String, String> params) {
return sysUserService.remove(params.get("id"));
}
@PostMapping("reset-password")
@Operation(summary = "重置密码")
public RestResult<?> resetPassword(@RequestBody Map<String, String> params) {
return sysUserService.resetPassword(params.get("id"), params.get("newPassword"));
}
@GetMapping("role-options")
@Operation(summary = "角色选项列表")
public RestResult<List<Map<String, Object>>> getRoleOptions() {
return sysRoleService.getRoleOptions();
}
}

View File

@ -0,0 +1,35 @@
package com.chinaweal.youfool.prj.modules.system.entity.req;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* 用户保存请求
*
* @author chenjy
* @since 2026/05/25
*/
@Data
@Accessors(chain = true)
public class SysUserSaveReq {
private String id;
private String username;
private String password;
private String realName;
private String phone;
private String orgName;
private String districtCode;
private Integer status;
private List<String> roleIds;
}

View File

@ -1,7 +1,13 @@
package com.chinaweal.youfool.prj.modules.system.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chinaweal.youfool.framework.springboot.rest.RestResult;
import com.chinaweal.youfool.prj.modules.system.entity.query.SysUserQuery;
import com.chinaweal.youfool.prj.modules.system.entity.req.SysUserSaveReq;
import com.chinaweal.youfool.prj.modules.system.entity.vo.LoginUserVO;
import com.chinaweal.youfool.prj.modules.system.entity.vo.SysUserVO;
import java.util.Map;
/**
* 系统用户 Service 接口
@ -11,19 +17,19 @@ import com.chinaweal.youfool.prj.modules.system.entity.vo.LoginUserVO;
*/
public interface ISysUserService {
/**
* 根据用户名查询用户登录用
*
* @param username 用户名
* @return 登录用户信息
*/
RestResult<LoginUserVO> findByUsername(String username);
/**
* 构建登录用户信息角色+权限
*
* @param userId 用户ID
* @return 登录用户信息
*/
LoginUserVO buildLoginUserVO(String userId);
RestResult<Page<SysUserVO>> queryList(SysUserQuery query);
RestResult<SysUserVO> getDetail(String id);
RestResult<String> save(SysUserSaveReq req);
RestResult<?> update(SysUserSaveReq req);
RestResult<?> remove(String id);
RestResult<?> resetPassword(String id, String newPassword);
}

View File

@ -1,20 +1,31 @@
package com.chinaweal.youfool.prj.modules.system.service.impl;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chinaweal.youfool.framework.springboot.common.util.AssertUtils;
import com.chinaweal.youfool.framework.springboot.common.util.StringUtils;
import com.chinaweal.youfool.framework.springboot.rest.RestResult;
import com.chinaweal.youfool.prj.modules.system.entity.SysUserEntity;
import com.chinaweal.youfool.prj.modules.system.entity.SysUserRoleEntity;
import com.chinaweal.youfool.prj.modules.system.entity.query.SysUserQuery;
import com.chinaweal.youfool.prj.modules.system.entity.req.SysUserSaveReq;
import com.chinaweal.youfool.prj.modules.system.entity.vo.LoginUserVO;
import com.chinaweal.youfool.prj.modules.system.entity.vo.SysUserVO;
import com.chinaweal.youfool.prj.modules.system.mapper.SysPermissionMapper;
import com.chinaweal.youfool.prj.modules.system.mapper.SysRoleMapper;
import com.chinaweal.youfool.prj.modules.system.mapper.SysUserMapper;
import com.chinaweal.youfool.prj.modules.system.mapper.SysUserRoleMapper;
import com.chinaweal.youfool.prj.modules.system.service.ISysUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* 系统用户 Service 实现
@ -29,6 +40,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserEntity
private final SysRoleMapper sysRoleMapper;
private final SysPermissionMapper sysPermissionMapper;
private final SysUserRoleMapper sysUserRoleMapper;
private final BCryptPasswordEncoder passwordEncoder;
@Override
public RestResult<LoginUserVO> findByUsername(String username) {
@ -65,4 +78,143 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserEntity
vo.setPermissions(permissions);
return vo;
}
@Override
public RestResult<Page<SysUserVO>> queryList(SysUserQuery query) {
Page<SysUserEntity> page = new Page<>(query.getPageNum(), query.getPageSize());
LambdaQueryWrapper<SysUserEntity> wrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(query.getKeyword())) {
wrapper.and(w -> w
.like(SysUserEntity::getUsername, query.getKeyword())
.or()
.like(SysUserEntity::getRealName, query.getKeyword())
.or()
.like(SysUserEntity::getOrgName, query.getKeyword())
);
}
if (query.getStatus() != null) {
wrapper.eq(SysUserEntity::getStatus, query.getStatus());
}
wrapper.orderByDesc(SysUserEntity::getCreateTime);
Page<SysUserEntity> entityPage = this.page(page, wrapper);
Page<SysUserVO> voPage = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
List<SysUserVO> voList = entityPage.getRecords().stream().map(entity -> {
SysUserVO vo = new SysUserVO();
BeanUtils.copyProperties(entity, vo);
vo.setRoles(sysRoleMapper.selectRoleCodesByUserId(entity.getId()));
vo.setRoleNames(sysRoleMapper.selectRoleNamesByUserId(entity.getId()));
return vo;
}).collect(Collectors.toList());
voPage.setRecords(voList);
return RestResult.ok(voPage);
}
@Override
public RestResult<SysUserVO> getDetail(String id) {
AssertUtils.isNotBlank(id);
SysUserEntity entity = this.getById(id);
if (entity == null) {
return RestResult.ok(null);
}
SysUserVO vo = new SysUserVO();
BeanUtils.copyProperties(entity, vo);
vo.setRoles(sysRoleMapper.selectRoleCodesByUserId(id));
vo.setRoleNames(sysRoleMapper.selectRoleNamesByUserId(id));
return RestResult.ok(vo);
}
@Override
@DSTransactional
public RestResult<String> save(SysUserSaveReq req) {
AssertUtils.isNotBlank(req.getUsername());
AssertUtils.isNotBlank(req.getPassword());
SysUserEntity entity = new SysUserEntity();
BeanUtils.copyProperties(req, entity);
entity.setPassword(passwordEncoder.encode(req.getPassword()));
entity.setStatus(req.getStatus() != null ? req.getStatus() : 1);
this.save(entity);
// 保存用户角色关联
saveUserRoles(entity.getId(), req.getRoleIds());
log.info("[OK] 新增用户: username={}", req.getUsername());
return RestResult.ok(entity.getId());
}
@Override
@DSTransactional
public RestResult<?> update(SysUserSaveReq req) {
AssertUtils.isNotBlank(req.getId());
SysUserEntity entity = this.getById(req.getId());
AssertUtils.isNotNull(entity);
if (req.getRealName() != null) {
entity.setRealName(req.getRealName());
}
if (req.getPhone() != null) {
entity.setPhone(req.getPhone());
}
if (req.getOrgName() != null) {
entity.setOrgName(req.getOrgName());
}
if (req.getDistrictCode() != null) {
entity.setDistrictCode(req.getDistrictCode());
}
if (req.getStatus() != null) {
entity.setStatus(req.getStatus());
}
this.updateById(entity);
// 更新用户角色关联
if (req.getRoleIds() != null) {
LambdaQueryWrapper<SysUserRoleEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUserRoleEntity::getUserId, req.getId());
sysUserRoleMapper.delete(wrapper);
saveUserRoles(req.getId(), req.getRoleIds());
}
log.info("[OK] 更新用户: id={}", req.getId());
return RestResult.ok();
}
@Override
@DSTransactional
public RestResult<?> remove(String id) {
AssertUtils.isNotBlank(id);
// 删除用户角色关联
LambdaQueryWrapper<SysUserRoleEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUserRoleEntity::getUserId, id);
sysUserRoleMapper.delete(wrapper);
this.removeById(id);
log.info("[OK] 删除用户: id={}", id);
return RestResult.ok();
}
@Override
@DSTransactional
public RestResult<?> resetPassword(String id, String newPassword) {
AssertUtils.isNotBlank(id);
AssertUtils.isNotBlank(newPassword);
SysUserEntity entity = this.getById(id);
AssertUtils.isNotNull(entity);
entity.setPassword(passwordEncoder.encode(newPassword));
this.updateById(entity);
log.info("[OK] 重置密码: id={}", id);
return RestResult.ok();
}
private void saveUserRoles(String userId, List<String> roleIds) {
if (roleIds == null || roleIds.isEmpty()) {
return;
}
for (String roleId : roleIds) {
SysUserRoleEntity userRole = new SysUserRoleEntity();
userRole.setUserId(userId);
userRole.setRoleId(roleId);
userRole.setCreateBy("system");
sysUserRoleMapper.insert(userRole);
}
}
}