25.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--用户服务接口

用户管理是任何系统的基础功能之一,本篇介绍了如何实现一个完整的用户管理模块,包括用户信息的增删改查、用户状态管理、分页查询、数据验证和权限控制。核心代码实现部分涵盖了控制器(UserController)、服务接口(IUserService)、请求/响应模型以及服务实现(UserServiceImpl),并详细说明了各接口的功能,如获取用户信息、分页获取用户列表、删除用户、禁用/启用用户和更新用户信息。最佳实践建议包括数据验证、性能优化、安全性和代码组织等方面,强调了使用数据注解、异步方法、依赖注入、权限控制和统一响应格式等措施。使用示例展示了如何通过HTTP请求获取用户列表、更新用户信息和禁用用户。注意事项提醒用户删除操作建议采用软删除、敏感操作需记录日志、用户状态变更应通知相关系统、响应中不返回敏感信息以及并发操作的处理。该用户管理模块为基本的CRUD操作提供了实现基础,并可根据实际需求扩展更多功能,如增加查询条件、导入导出、操作日志等。

Tip:由于大部分内容跟单体应用中的知识点一样,因此我们只讲解核心设计要点和高级特性实现。

一、核心设计要点

1.1 用户状态管理
/// <summary>
/// 禁用/启用用户
/// </summary>
/// <param name="id"></param>
/// <param name="isDisabled"></param>
/// <returns></returns>
public async Task DisableUser(long id, bool isDisabled)
{var user = await _userManager.FindByIdAsync(id.ToString());if (user == null){throw new NotFoundException($"用户不存在");}if (isDisabled){user.LockoutEnd = DateTimeOffset.UtcNow.AddYears(100); // 设置一个很远的未来时间}else{user.LockoutEnd = null; // 解除锁定}user.LockoutEnabled = isDisabled;var result = await _userManager.UpdateAsync(user);if (!result.Succeeded){throw new BadRequestException($"禁用/启用用户失败");}
}

这段代码是一个用于“禁用/启用用户”的服务方法,常见于基于ASP.NET Core Identity的用户管理系统。下面我们详细讲解代码和设计思路。

代码接收接收用户ID和一个布尔值,表示是否禁用用户。如果禁用,则将用户的锁定时间设置为100年后;如果启用,则将锁定时间设置为null,表示解除锁定。其中LockoutEnd属性用于控制用户锁定时间,LockoutEnabled属性用于启用或禁用锁定功能。代码中使用了_userManager来管理用户对象,FindByIdAsync方法用于查找用户,UpdateAsync方法用于更新用户信息。在查找用户时,如果找不到用户,则抛出“用户不存在”异常;在更新用户信息时,如果更新失败,则抛出“禁用/启用用户失败”异常。

代码的设计思路很简单,我们采用ASP.NET Core Identity的锁定机制,通过设置LockoutEndLockoutEnabled属性来控制用户的登录权限,而不是直接删除或修改用户的敏感信息,从而提升系统的安全性。其次,方法中通过抛出异常的方式处理各种错误情况,便于上层统一捕获和处理,提高了代码的可维护性。此外,该实现方式具有良好的扩展性,只需调整锁定时间或相关条件,即可满足临时禁用、永久禁用等不同业务场景的需求。

在实际开发过程中,需要注意以下几点。第一,只有当 LockoutEnabled 属性设置为 true 时,LockoutEnd 的锁定机制才会生效。其次,将锁定时间设置为100年后虽然不能算作真正的“永久禁用”,但对于大多数业务场景来说已经足够使用。此外,如果用户已经处于禁用状态,再次执行禁用操作不会引发错误,但建议在业务逻辑层面实现幂等性处理,以避免重复操作带来的潜在问题。

Tip:通过Identity的锁定机制实现了用户的禁用和启用,既安全又易于维护,是.NET项目中常见的用户状态管理方式。

1.2 分页查询优化
/// <summary>
/// 获取用户列表
/// </summary>
/// <param name="page"></param>
/// <returns></returns>
public async Task<PagedResponse<UserResponse>> GetUserList(UserPageRequest page)
{var query = _userManager.Users.AsQueryable();if (!string.IsNullOrEmpty(page.UserName)){query = query.Where(x => x.UserName.Contains(page.UserName));}if (!string.IsNullOrEmpty(page.Email)){query = query.Where(x => x.Email.Contains(page.Email));}// 使用单次查询获取总数和分页数据var totalQuery = query;var pagedQuery = query.OrderByDescending(o => o.Id).Skip((page.Page - 1) * page.PageSize).Take(page.PageSize);// 并行执行两个查询var countTask = totalQuery.CountAsync();var usersTask = pagedQuery.ToListAsync();await Task.WhenAll(countTask, usersTask);int total = countTask.Result;List<SpUser> users = usersTask.Result;var result = new PagedResponse<UserResponse>{TotalRow = total,TotalPage = (int)Math.Ceiling((double)total / page.PageSize),Data = users.Select(x => new UserResponse{Id = x.Id,UserName = x.UserName,Email = x.Email,IsLocked = x.LockoutEnabled}).ToList()};return result;
}

这段代码是一个用于获取用户列表的异步方法,常见于.NET后端服务中,主要实现了分页、条件筛选和高效查询。GetUserList方法是一个异步操作,返回类型为 Task<PagedResponse<UserResponse>>,用于获取分页后的用户列表。参数 UserPageRequest page 封装了分页信息和筛选条件(如用户名、邮箱等),便于灵活查询用户数据。这段代码的设计思路是通过使用IQueryable接口来构建动态查询,结合分页和异步操作来提高性能和用户体验。其中_userManager.Users 获取了所有用户的可查询对象,AsQueryable() 方法使得可以对用户数据进行动态查询。并且我们使用了LINQ的 Where 方法来根据用户名和邮箱进行条件筛选,OrderByDescending 方法按用户ID倒序排列,SkipTake 方法实现了分页功能。这里要重点关注并行查询总数和数据的实现,使用 Task.WhenAll 方法可以同时执行两个异步查询任务,分别获取总记录数和当前页的用户列表,从而提高查询效率。

Tip:Task.WhenAll能提升性能,但要确保两个查询不会互相影响。

1.3 用户信息更新
/// <summary>
/// 更新用户信息
/// </summary>
/// <param name="id"></param>
/// <param name="user"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task UpdateUser(long id, UserUpdateRequest user)
{var spUser = await _userManager.FindByIdAsync(id.ToString());if (spUser == null){throw new NotFoundException($"用户不存在");}spUser.UserName = user.UserName;spUser.Email = user.Email;var result = await _userManager.UpdateAsync(spUser);if (!result.Succeeded){throw new BadRequestException($"更新用户失败");}
}

这段代码是一个用于更新用户信息的服务方法,常见于基于ASP.NET Core Identity的用户管理系统。代码接收用户ID和一个包含更新信息的请求对象 UserUpdateRequest。首先通过 _userManager.FindByIdAsync 方法查找用户,如果找不到用户,则抛出“用户不存在”异常。接着,将请求中的新信息赋值给用户对象的相应属性,如用户名、邮箱和手机号。最后,使用 _userManager.UpdateAsync 方法更新用户信息,如果更新失败,则抛出“更新用户信息失败”异常,并将错误信息拼接成字符串返回。

代码的设计思路很简单,我们采用ASP.NET Core Identity的用户管理功能,通过 _userManager 来操作用户对象。首先通过ID查找用户,确保用户存在;然后更新用户信息,确保数据的完整性和一致性。最后通过抛出异常的方式处理各种错误情况,便于上层统一捕获和处理,提高了代码的可维护性。此外,该实现方式具有良好的扩展性,只需调整请求对象中的属性,即可满足不同业务场景下的用户信息更新需求。

二、高级特性实现

2.1 用户角色关联
/// <summary>
/// 获取用户信息
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<UserResponse?> GetUserInfo(long id)
{// 尝试从缓存获取string cacheKey = $"user:{id}";var cachedUser = await _redis.GetStringAsync(cacheKey);if (!string.IsNullOrEmpty(cachedUser)){return JsonSerializer.Deserialize<UserResponse>(cachedUser);}// 缓存未命中,从数据库查询var user = await _userManager.FindByIdAsync(id.ToString());if (user == null){throw new NotFoundException($"用户不存在");}var response = new UserResponse{Id = user.Id,UserName = user.UserName,Email = user.Email,IsLocked = user.LockoutEnabled};// 缓存结果,设置适当的过期时间await _redis.SetStringAsync(cacheKey, JsonSerializer.Serialize(response), 60 * 10);return response;
}

这段代码是一个用于获取用户信息的服务方法。代码首先尝试从Redis缓存中获取用户信息,如果缓存命中,则直接返回缓存中的数据;如果缓存未命中,则从数据库中查询用户信息,并将查询结果存入缓存中,以便下次快速访问。代码使用了 _userManager.FindByIdAsync 方法来查找用户,如果找不到用户,则抛出“用户不存在”异常。查询到的用户信息被封装成 UserResponse 对象,并存入Redis缓存中,设置了10分钟的过期时间。

代码的设计思路是通过使用Redis缓存来提高用户信息查询的性能,减少数据库访问次数。首先尝试从缓存中获取数据,如果缓存命中,则直接返回;如果缓存未命中,则从数据库查询并更新缓存。这样可以显著提高查询速度,尤其是在高并发场景下。此外,使用Redis作为缓存存储,可以有效降低数据库负载,提高系统的整体性能。

Tip:使用Redis缓存用户信息可以显著提高查询性能,尤其是在高并发场景下。

三、总结

用户管理模块是任何系统的基础功能之一,本篇介绍了如何实现一个完整的用户管理模块,包括用户信息的增删改查、用户状态管理、分页查询、数据验证和权限控制。核心代码实现部分涵盖了控制器(UserController)、服务接口(IUserService)、请求/响应模型以及服务实现(UserServiceImpl),并详细说明了各接口的功能,如获取用户信息、分页获取用户列表、删除用户、禁用/启用用户和更新用户信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/84154.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于深度学习的无人机轨迹预测

完整代码见文末 随着无人机技术的不断发展,无人机在农业、物流、监控等领域的应用日益广泛。精准的轨迹预测不仅能够提高无人机飞行的效率和安全性,还能在应对复杂环境下的突发状况时做出迅速反应。因此,基于深度学习的无人机轨迹预测已成为当前研究和应用的热门方向。 无…

AUTOSAR实战教程--DoIP_02_诊断链路建立流程

第一步&#xff1a;DoIP实体车辆声明/诊断仪车辆识别请求 打开激活线以后&#xff0c;DoIP实体发的三帧车辆声明报文。其中包含了DoIP实体的诊断逻辑地址&#xff08;可以类比DoCAN的物理请求/响应地址&#xff09;&#xff0c;对应车辆的VIN码&#xff08;若已配置&#xff0…

跟我学c++中级篇——多线程中的文件处理

一、文件处理 作为IO处理的一种重要场景&#xff0c;文件处理是几乎所有编程都无法绕过的一个情况。稍微复杂的一些的程序都可能需要文件处理&#xff0c;不管这种文件处理对开发者来说是显式的还是隐式的。相对于其它语言&#xff0c;C并未提供多么好的文件处理API接口&#…

Flutter知识点汇总

Flutter架构解析 1. Flutter 是什么?它与其他移动开发框架有什么不同? Flutter 是 Google 开发的开源移动应用开发框架,可用于快速构建高性能、高保真的移动应用(iOS 和 Android),也支持 Web、桌面和嵌入式设备。。它与其他移动开发框架(如 React Native、Xamarin、原…

【会员专享数据】1980—2022年中国逐日月年潜在蒸散发栅格数据

气象数据是我们在各项研究中都经常使用的数据&#xff0c;尤其是高精度的气象数据应用价值非常高。 之前我们分享过研究者张凌, 胡英屹等发布在国家冰川冻土沙漠科学数据中心平台上的nc格式的1980—2022年中国高分辨率逐日、逐月、逐年气象数据&#xff01;很多小伙伴拿到数据…

前端打包工具简单介绍

前端打包工具简单介绍 一、Webpack 架构与插件机制 1. Webpack 架构核心组成 Entry&#xff08;入口&#xff09; 指定应用的起点文件&#xff0c;比如 src/index.js。 Module&#xff08;模块&#xff09; Webpack 把项目当作模块图&#xff0c;模块可以是 JS、CSS、图片等…

工业控制核心引擎高性能MCU——MM32F5370

RAMSUN提供的MM32F5370搭载180MHz Arm China Star-MC1处理器&#xff0c;集成DSP、FPU与三角函数加速单元&#xff08;CORDIC&#xff09;&#xff0c;轻松应对复杂算法需求。其技术亮点包括&#xff1a; 超高精度PWM&#xff1a;8通道208ps级高精度PWM输出&#xff0c;满足储能…

AI架构师修炼之道

1 AI时代的架构革命 与传统软件开发和软件架构师相比&#xff0c;AI架构师面临着三重范式转换&#xff1a; 1.1 技术维度&#xff0c;需处理异构算力调度与模型生命周期管理的复杂性&#xff1b; 1.2 系统维度&#xff0c;需平衡实时性与资源约束的矛盾&#xff1b; 1.3 价…

数学建模期末速成 主成分分析的基本步骤

设有 n n n个研究对象&#xff0c; m m m个指标变量 x 1 , x 2 , ⋯ , x m x_1,x_2,\cdots,x_m x1​,x2​,⋯,xm​&#xff0c;第 i i i个对象关于第 j j j个指标取值为 a i j a_{ij} aij​,构造数据矩阵 A ( a i j ) n m A\left(\begin{array}{c}a_{ij}\end{array}\right)_{…

博图 SCL 编程技巧:灵活实现上升沿与下降沿检测案例分享(上)

博图 SCL 编程技巧&#xff1a;灵活实现上升沿与下降沿检测案例分享 在 PLC 编程中&#xff0c;检测信号从 0 变为 1 (上升沿) 或从 1 变为 0 (下降沿) 是最基础也是最关键的操作之一。它常用于启动单次动作、计数、状态切换等场景。在西门子 TIA Portal 环境中&#xff0c;虽…

深度学习入门Day3--鱼书学习(2)

这俩天刚忙完答辩的事情&#xff0c;终于有时间学习了 一、3层神经网络实现 1.本节中的符号使用说明。 w 12 ( 1 ) w_{12}^{(1)} w12(1)​表示前一层的第2个神经元 x 2 x_{2} x2​到后一层的第一个神经元 a 1 a_{1} a1​的权重。权重右下角按照“后一层的索引号、前一层的索引…

服务器 | Centos 9 系统中,如何部署SpringBoot后端项目?

系列文章目录 虚拟机 | Ubuntu 安装流程以及界面太小问题解决 虚拟机 | Ubuntu图形化系统&#xff1a; open-vm-tools安装失败以及实现文件拖放 虚拟机 | Ubuntu操作系统&#xff1a;su和sudo理解及如何处理忘记root密码 文章目录 系列文章目录前言一、环境介绍二、 使用syst…

CNN核心机制深度解析:卷积池化原理 PyTorch实现经典网络

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文系统讲解CNN核心原理、经典网络架构和图像分类实战&#xff0c;涵盖卷积层、池化层、LeNet/AlexNet/VGG/ResNet设计思想&#xff0c;并提供CIFAR-…

6个月Python学习计划 Day 17 - 继承、多态与魔术方法

第三周 Day 4 &#x1f3af; 今日目标 理解类的继承和方法重写掌握多态思想及其实际应用了解并使用常见的魔术方法&#xff08;如 str、len 等&#xff09; &#x1f9ec; 类的继承&#xff08;Inheritance&#xff09; Python 支持单继承与多继承&#xff0c;常用语法如下&…

抖音怎么下载视频

抖音作为一款短视频社交平台&#xff0c;凭借其独特的短视频形式和丰富的内容&#xff0c;吸引了大量用户。有些用户在欣赏完抖音视频后&#xff0c;想要将其保存下来&#xff0c;以便日后观看。如何在抖音下载视频呢&#xff1f;本文将为您详细介绍抖音视频下载的技巧和方法。…

使用MinIO搭建自己的分布式文件存储

目录 引言&#xff1a; 一.什么是 MinIO &#xff1f; 二.MinIO 的安装与部署&#xff1a; 三.Spring Cloud 集成 MinIO&#xff1a; 1.前提准备&#xff1a; &#xff08;1&#xff09;安装依赖&#xff1a; &#xff08;2&#xff09;配置MinIO连接&#xff1a; &…

uni-app 如何实现选择和上传非图像、视频文件?

在 uni-app 中实现选择和上传非图像、视频文件&#xff0c;可根据不同端&#xff08;App、H5、小程序&#xff09;的特点&#xff0c;采用以下方法&#xff1a; 一、通用思路&#xff08;多端适配优先推荐&#xff09; 借助 uni.chooseFile 选择文件&#xff0c;再用 uni.upl…

正点原子[第三期]Arm(iMX6U)Linux移植学习笔记-12.1 Linux内核启动流程简介

前言&#xff1a; 本文是根据哔哩哔哩网站上“Arm(iMX6U)Linux系统移植和根文件系统构键篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。 引用&#xff1a; …

UDP与TCP通信协议技术解析

文章目录 协议基础原理TCP&#xff1a;可靠的面向连接通信UDP&#xff1a;高效的无连接通信 性能特征分析TCP性能表现UDP性能表现 应用场景分析TCP适用场景UDP适用场景 技术实现考量错误处理策略网络资源利用 选择决策框架可靠性需求评估性能要求分析 混合方案设计协议组合策略…

mysql 页的理解和实际分析

目录 页&#xff08;Page&#xff09;是 Innodb 存储引擎用于管理数据的最小磁盘单位B树的一般高度记录在页中的存储 innodb ibd文件innodb 页类型分析ibd文件查看数据表的行格式查看ibd文件 分析 ibd的第4个页&#xff1a;B-tree Node类型先分析File Header(38字节-描述页信息…