当前位置: 首页 > news >正文

Day26:角色管理 API 完整教程(CRUD + 分配菜单 + 事务)

一、今日学习内容

  1. 角色CRUD接口
  2. 给角色分配菜单(事务 + 多对多)
  3. 查询角色已关联的菜单列表
  4. Service + Controller 完整实现
  5. 权限关联逻辑

二、先给你 DTO(必须新建)

Application/Dtos/RoleDtos.cs

public class RoleCreateDto { public string RoleName { get; set; } public string RoleCode { get; set; } public int Sort { get; set; } public int Status { get; set; } } public class RoleUpdateDto { public long Id { get; set; } public string RoleName { get; set; } public string RoleCode { get; set; } public int Sort { get; set; } public int Status { get; set; } } // 角色分配菜单 DTO public class AssignMenuDto { public long RoleId { get; set; } public List<long> MenuIds { get; set; } }

Application/Vos/RoleVo.cs

public class RoleVo { public long Id { get; set; } public string Name { get; set; } public string Code { get; set; } public int Sort { get; set; } public int Status { get; set; } public DateTime CreateTime { get; set; } }

三、AutoMapper 映射(加到你的 Profile)

CreateMap<RoleCreateDto, Role>(); CreateMap<RoleUpdateDto, Role>(); CreateMap<Role, RoleVo>();

四、IRoleService 接口

public interface IRoleService { Task<R<List<RoleVo>>> GetListAsync(); Task<R<RoleVo>> GetByIdAsync(long id); Task<R<string>> AddAsync(RoleCreateDto dto); Task<R<string>> UpdateAsync(RoleUpdateDto dto); Task<R<string>> DeleteAsync(long id); Task<R<string>> AssignMenuAsync(AssignMenuDto dto); }

五、RoleService 完整实现(核心业务)

public class RoleService : IRoleService { private readonly IUnitOfWork _uow; private readonly IMapper _mapper; public RoleService(IUnitOfWork uow, IMapper mapper) { _uow = uow; _mapper = mapper; } // 列表 public async Task<R<List<RoleVo>>> GetListAsync() { var list = await _uow.RoleRepository.GetAllAsync(); var voList = _mapper.Map<List<RoleVo>>(list); return R<List<RoleVo>>.Success(voList); } // 详情 public async Task<R<RoleVo>> GetByIdAsync(long id) { var role = await _uow.RoleRepository.FirstOrDefaultAsync(x => x.Id == id); if (role == null) return R<RoleVo>.Fail("角色不存在"); return R<RoleVo>>.Success(_mapper.Map<RoleVo>(role)); } // 新增 public async Task<R<string>> AddAsync(RoleCreateDto dto) { var isExist = await _uow.RoleRepository.AnyAsync(x => x.Code == dto.Code); if (isExist) return R<string>.Fail("角色编码已存在"); var role = _mapper.Map<Role>(dto); await _uow.RoleRepository.AddAsync(role); await _uow.SaveChangesAsync(); return R<string>.Success("新增成功"); } // 修改 public async Task<R<string>> UpdateAsync(RoleUpdateDto dto) { var role = await _uow.RoleRepository.FirstOrDefaultAsync(x => x.Id == dto.Id); if (role == null) return R<string>.Fail("角色不存在"); _mapper.Map(dto, role); await _uow.SaveChangesAsync(); return R<string>.Success("修改成功"); } // 删除 public async Task<R<string>> DeleteAsync(long id) { // 检查是否有用户在使用 var hasUser = await _uow.UserRole.AnyAsync(x => x.RoleId == id); if (hasUser) return R<string>.Fail("该角色已分配用户,无法删除"); await _uow.RoleMenu.DeleteAsync(x => x.RoleId == id); await _uow.RoleRepository.DeleteAsync(id); await _uow.SaveChangesAsync(); return R<string>.Success("删除成功"); } // ====================== // 核心:角色分配菜单(事务) // ====================== public async Task<R<string>> AssignMenuAsync(AssignMenuDto dto) { using (await _uow.BeginTransactionAsync()) { try { // 1. 删除原有权限 await _uow.RoleMenuRepository.DeleteBatchAsync(x => x.RoleId == dto.RoleId); // 2. 添加新权限 foreach (var menuId in dto.MenuIds) { await _uow.RoleMenuRepository.AddAsync(new RoleMenu { RoleId = dto.RoleId, MenuId = menuId }); } await _uow.SaveChangesAsync(); return R<string>.Sucess("分配成功"); } catch (Exception ex) { await _uow.RollbackAsync(); throw new Exception("Transaction failed", ex); } } } }

六、RoleController 接口

[ApiController] [Route("api/[controller]")] [Authorize] public class RoleController : ControllerBase { private readonly IRoleService _roleService; public RoleController(IRoleService roleService) { _roleService = roleService; } [HttpGet("list")] public async Task<ActionResult<R<List<RoleVo>>>> List() { return await _roleService.GetListAsync(); } [HttpGet("{id}")] public async Task<ActionResult<R<RoleVo>>> Get(long id) { return await _roleService.GetByIdAsync(id); } [HttpPost("add")] public async Task<ActionResult<R<string>>> Add(RoleCreateDto dto) { return await _roleService.AddAsync(dto); } [HttpPut("update")] public async Task<ActionResult<R<string>>> Update(RoleUpdateDto dto) { return await _roleService.UpdateAsync(dto); } [HttpDelete("{id}")] public async Task<ActionResult<R<string>>> Delete(long id) { return await _roleService.DeleteAsync(id); } // 分配菜单 [HttpPost("assignMenu")] public async Task<ActionResult<R<string>>> AssignMenu(AssignMenuDto dto) { return await _roleService.AssignMenuAsync(dto); } }

七、必须注册服务

builder.Services.AddScoped<IRoleService, RoleService>();

八、今日练习完成标准

✅ 角色 CRUD 接口全部完成
✅ 角色分配菜单(先删后增,事务保证)
✅ 角色不能重复编码
✅ 删除角色前检查是否被用户使用
✅ 全部使用 DTO/VO
✅ AutoMapper 映射
✅ 接口需要登录[Authorize]

http://www.jsqmd.com/news/795777/

相关文章:

  • 如何快速掌握LeagueAkari:面向新手的英雄联盟本地自动化工具完整使用指南
  • STM32新手避坑指南:正点原子、野火、慧净、小马飞控的Systick延时代码到底差在哪?
  • 解锁B站缓存视频:m4s转MP4工具完全指南
  • 报错 SQLite Error 5 database is locked 生产环境怎么排查
  • 小小调度器:轻量任务调度的应用
  • 从 performWorkOnRoot 到 workInProgress tree:React 真正开始 render 的地方
  • C语言指针:从零掌握指针(4)
  • 千问 LeetCode 2227. 加密解密字符串 Python3实现
  • Unitree GO2 ROS2 SDK完整指南:5步实现四足机器人智能控制与自主导航
  • 2026年中石化加油卡回收靠谱平台最新深度测评 - 京顺回收
  • [具身智能-622]:高速图像传感器接口(视觉 / 摄像头)与数据格式
  • 别再只加contentDescription了!Android无障碍适配TalkBack的7个实战避坑点(含完整代码)
  • 根据用户主动关注用户和用户朋友圈以及其他关系层面平台注入的用户 系统推荐程序返回用户推荐列表
  • 第四章 数字孪生制作完整流程
  • 无人机通信安全渗透测试:从信号拦截到GPS欺骗的完整攻防框架
  • 茅台自动预约系统:告别手动抢购,实现智能预约的完整解决方案
  • 从零到精通:手把手教你用BusHound分析SCSI Sense错误码(附完整排查流程)
  • 终极指南:如何通过Typora插件实现高效文件管理与快速切换
  • 洛谷比赛分级
  • 如何用FanControl在5分钟内解决Windows风扇噪音问题?
  • mkcert进阶玩法:一键生成局域网HTTPS证书,让内网测试告别“不安全”警告(含Windows/Linux/Mac多平台指南)
  • WebGLM:基于检索增强生成(RAG)的实时联网智能问答系统实战解析
  • 金仓数据库 V9R4C19 安全加固实战:禁用 root 部署 + hashbytes 单向哈希
  • 大模型中转哪个技术机构靠谱
  • 2026年论文AI率爆表?掌握这2招快速去AI痕迹,导师挑不出毛病! - 降AI实验室
  • 如何彻底卸载Windows Defender:2025完整移除工具使用指南
  • PDPI Spec:规格驱动开发如何提升AI时代软件工程效率
  • 不只是Target选错:深挖Metasploit中‘Exploit completed, but no session’的3个隐蔽原因与对策
  • 基于Claude的智能代码质量监控工具设计与实践
  • 别再死记硬背三段式状态机了!用HDLbits的Simple FSM题,带你搞懂Verilog状态机设计的核心差异