ABP vNext微服务架构详细教程——分布式权限框架(上)

2023-11-05 19:38

本文主要是介绍ABP vNext微服务架构详细教程——分布式权限框架(上),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1

简介

3e5764ada323a9ea07d18cdf184d98f9.png

ABP vNext框架本身提供了一套权限框架,其功能非常丰富,具体可参考官方文档:https://docs.abp.io/en/abp/latest/Authorization

0768681cd19340aa43ba9743ea22e945.gif

但是我们使用时会发现,对于正常的单体应用,ABP vNext框架提供的权限系统没有问题, 但是在微服务架构下,这种权限系统并不是非常的友好。

a58eca97ed79796317a83504dc349bee.gif

我希望我的权限系统可以满足以下要求:

每个聚合服务持有独立的权限集合

每个聚合服务可以独立声明、使用其接口访问所需的权限。

提供统一接口负责管理、存储所有服务权限并实现对角色的授权。

每个接口可以灵活组合使用一个或多个权限码。

权限框架使用尽量简单,减少额外编码量。

8934846192858daf5531d12bde980b57.gif

在ABP vNext框架基础上,重新编写了一套分布式权限框架,大体规则如下:

使用ABP vNext框架中提供的用户、角色模型不做改变,替代重新定义权限模型,重新定义权限的实体及相关服务接口。

在身份管理服务中,实现权限的统一管理、角色授权和权限认证。

在聚合服务中定义其具有的权限信息、权限关系并通过特性声明各接口所需要的权限。

在聚合服务启动时,自动将其权限信息注册到身份管理服务。

客户端访问聚合服务层服务时在聚合服务层中间件中验证当前用户是否具有该接口权限,验证过程需调用身份管理服务对应接口。 

796fc6bddb913ceedc406e955c9db6a3.gif

权限系统具体实现见下文。

2

身份认证服务

2be48d4482e970fa122386e05f90f3fa.gif

在之前的文章中我们已经搭建了身份认证服务的基础框架,这里我们直接在此基础上新增代码。

0063425d49ab05abe57474c708b9a62d.gif

在Demo.Identity.Domain项目中添加Permissions文件夹,并添加Entities子文件夹。在此文件夹下添加实体类SysPermission和RolePermissions如下:

using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Domain.Entities;namespace Demo.Identity.Permissions.Entities;/// <summary>
/// 权限实体类
/// </summary>
public class SysPermission : Entity<Guid>
{/// <summary>/// 服务名称/// </summary>[MaxLength(64)]public string ServiceName { get; set; }/// <summary>/// 权限编码/// </summary>[MaxLength(128)]public string Code { get; set; }/// <summary>/// 权限名称/// </summary>[MaxLength(64)]public string Name { get; set; }/// <summary>/// 上级权限ID/// </summary>[MaxLength(128)]public string ParentCode { get; set; }/// <summary>/// 判断两个权限是否相同/// </summary>/// <param name="obj"></param>/// <returns></returns>public override bool Equals(object? obj)
{return obj is SysPermission permission&& permission.ServiceName == ServiceName&& permission.Name == Name&& permission.Code == Code&& permission.ParentCode == ParentCode;}/// <summary>/// 设置ID的值/// </summary>/// <param name="id"></param>public void SetId(Guid id)
{Id = id;}
}
using System;
using Volo.Abp.Domain.Entities;namespace Demo.Identity.Permissions.Entities;/// <summary>
/// 角色权限对应关系
/// </summary>
public class RolePermissions : Entity<Guid>
{/// <summary>/// 角色编号/// </summary>public Guid RoleId { get; set; }/// <summary>/// 权限编号/// </summary>public Guid PermissionId { get; set; }
}

02f6bdec93f849b88bd8485abbdf1cd9.gif

将Demo.Identity.Application.Contracts项目中原有Permissions文件夹中所有类删除,并添加子文件夹Dto。在此文件夹下添加SysPermissionDto、PermissionTreeDto、SetRolePermissionsDto

类如下:

using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Application.Dtos;namespace Demo.Identity.Permissions.Dto;/// <summary>
/// 权限DTO
/// </summary>
public class SysPermissionDto:EntityDto<Guid>
{/// <summary>/// 服务名称/// </summary>[MaxLength(64)]public string ServiceName { get; set; }/// <summary>/// 权限编码/// </summary>[MaxLength(128)]public string Code { get; set; }/// <summary>/// 权限名称/// </summary>[MaxLength(64)]public string Name { get; set; }/// <summary>///     上级权限ID/// </summary>[MaxLength(128)]public string ParentCode { get; set; }
}
using System;
using System.Collections.Generic;
using Volo.Abp.Application.Dtos;namespace Demo.Identity.Permissions.Dto;/// <summary>
/// 权限树DTO
/// </summary>
public class PermissionTreeDto : EntityDto<Guid>
{/// <summary>/// 服务名称/// </summary>public string ServiceName { get; set; }/// <summary>/// 权限编码/// </summary>public string Code { get; set; }/// <summary>/// 权限名称/// </summary>public string Name { get; set; }/// <summary>/// 上级权限ID/// </summary>public string ParentCode { get; set; }/// <summary>/// 子权限/// </summary>public List<PermissionTreeDto> Children { get; set; }}
using System;
using System.Collections.Generic;namespace Demo.Identity.Permissions.Dto;/// <summary>
/// 设置角色权限DTO
/// </summary>
public class SetRolePermissionsDto
{/// <summary>/// 角色编号/// </summary>public Guid RoleId { get; set; }/// <summary>/// 权限ID列表/// </summary>public List<Guid> Permissions { get; set; }
}

282a8c294ce4f62ab02dd1a7d3dc66ba.gif

将Demo.Identity.Application.Contracts项目中Permissions文件夹下添加接口IRolePermissionsAppService如下:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Demo.Identity.Permissions.Dto;
using Volo.Abp.Application.Services;namespace Demo.Identity.Permissions;/// <summary>
///     角色管理应用服务接口
/// </summary>
public interface IRolePermissionsAppService: IApplicationService
{/// <summary>/// 获取角色所有权限/// </summary>/// <param name="roleId">角色ID</param>/// <returns></returns>Task<List<PermissionTreeDto>> GetPermission(Guid roleId);/// <summary>/// 设置角色权限/// </summary>/// <param name="dto">角色权限信息</param>/// <returns></returns>Task SetPermission(SetRolePermissionsDto dto);
}

33cb301ffb60cce4ba8bad696d3bd99c.gif

将Demo.Identity.Application.Contracts项目中Permissions文件夹下添加接口ISysPermissionAppService如下:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Demo.Identity.Permissions.Dto;
using Volo.Abp.Application.Services;namespace Demo.Identity.Permissions;/// <summary>
/// 权限管理应用服务接口 
/// </summary>
public interface ISysPermissionAppService:IApplicationService
{/// <summary>/// 按服务注册权限/// </summary>/// <param name="serviceName">服务名称</param>/// <param name="permissions">权限列表</param>/// <returns></returns>Task<bool> RegistPermission(string serviceName, List<SysPermissionDto> permissions);/// <summary>/// 按服务获取权限/// </summary>/// <param name="serviceName">服务名称</param>/// <returns>查询结果</returns>Task<List<SysPermissionDto>> GetPermissions(string serviceName);/// <summary>/// 获取完整权限树/// </summary>/// <param name="Permission"></param>/// <returns>查询结果</returns>Task<List<PermissionTreeDto>> GetPermissionTree();/// <summary>/// 获取用户权限码/// </summary>/// <param name="userId">用户编号</param>/// <returns>查询结果</returns>Task<List<string>> GetUserPermissionCode(Guid userId);
}

a842c0641ab27358777cf7627f48ef31.gif

在公共类库文件夹common中创建.Net6类库项目项目Demo.Core,用于存放通用类。

3278852ff639c4fe7f82826c9a3e471c.gif

这里我们在Demo.Core中添加文件夹CommonExtension用于存放通用扩展,添加EnumExtensions和ListExtensions类如下:

namespace Demo.Core.CommonExtension;/// <summary>
/// 枚举扩展类
/// </summary>
public static class EnumExtensions
{/// <summary>/// 获取描述特性/// </summary>/// <param name="enumValue">枚举值</param>/// <returns></returns>public static string GetDescription(this Enum enumValue){string value = enumValue.ToString();FieldInfo field = enumValue.GetType().GetField(value);object[] objs = field.GetCustomAttributes(typeof(DescriptionAttribute), false);  //获取描述属性if (objs == null || objs.Length == 0)  //当描述属性没有时,直接返回名称return value;DescriptionAttribute descriptionAttribute = (DescriptionAttribute)objs[0];return descriptionAttribute.Description;}
}
namespace Demo.Core.CommonExtension;public static class ListExtensions
{/// <summary>/// 集合去重/// </summary>/// <param name="lst">目标集合</param>/// <param name="keySelector">去重关键字</param>/// <typeparam name="T">集合元素类型</typeparam>/// <typeparam name="TKey">去重关键字数据类型</typeparam>/// <returns>去重结果</returns>public static List<T> Distinct<T,TKey>(this List<T> lst,Func<T, TKey> keySelector){List<T> result = new List<T>();HashSet<TKey> set = new HashSet<TKey>();foreach (var item in lst){var key = keySelector(item);if (!set.Contains(key)){set.Add(key);result.Add(item);}}return result;}
}

84a26677b92c9a80074d86c7de486d64.gif

在Demo.Core项目中添加文件夹CommonFunction用于存放通用方法,这里我们添加用于集合比对的ListCompare类如下:

using VI.Core.CommonExtension;namespace VI.Core.CommonFunction;/// <summary>
/// 集合比对
/// </summary>
public class ListCompare
{/** 调用实例:*  MutiCompare<Permission, string>(lst1, lst2, x => x.Code, (obj, isnew) =>*  {*      if (isnew)*      {*          Console.WriteLine($"新增项{obj.Id}");*      }*      else*      {*          Console.WriteLine($"已存在{obj.Id}");*      }*  }, out var lstNeedRemove);*//// <summary>/// 对比源集合和目标集合,处理已有项和新增项,并找出需要删除的项/// </summary>/// <param name="lstSource">源集合</param>/// <param name="lstDestination">目标集合</param>/// <param name="keySelector">集合比对关键字</param>/// <param name="action">新增或已有项处理方法,参数:(数据项, 是否是新增)</param>/// <param name="needRemove">需要删除的数据集</param>/// <typeparam name="TObject">集合对象数据类型</typeparam>/// <typeparam name="TKey">对比关键字数据类型</typeparam>public static void MutiCompare<TObject,TKey>(List<TObject> lstDestination,List<TObject> lstSource,Func<TObject, TKey> keySelector,Action<TObject, bool> action, out Dictionary<TKey, TObject> needRemove){//目标集合去重lstDestination.Distinct(keySelector);//将源集合存入字典,提高查询效率needRemove = new Dictionary<TKey, TObject>();foreach (var item in lstSource){needRemove.Add(keySelector(item),item);}//遍历目标集合,区分新增项及已有项//在字典中排除目标集合中的项,剩余的即为源集合中需删除的项foreach (var item in lstDestination){if (needRemove.ContainsKey(keySelector(item))){action(item, false);needRemove.Remove(keySelector(item));}else{action(item, true);}}}
}

774eda5f91fa5f9f23e62b8ce752335d.gif

在Demo.Identity.Application项目中添加Permissions文件夹。

316da11e90fa1461b08d804effc01b68.gif

在Demo.Identity.Application项目Permissions文件夹中添加PermissionProfileExtensions类用于定义对象映射关系如下:

using Demo.Identity.Permissions.Dto;
using Demo.Identity.Permissions.Entities;namespace Demo.Identity.Permissions;public static class PermissionProfileExtensions
{/// <summary>/// 创建权限领域相关实体映射关系/// </summary>/// <param name="profile"></param>public static void CreatePermissionsMap(this IdentityApplicationAutoMapperProfile profile){profile.CreateMap<SysPermission, PermissionTreeDto>();profile.CreateMap<SysPermission,SysPermissionDto>();profile.CreateMap<SysPermissionDto,SysPermission>();}
}

8bc6c8668e75a02b4f5c412b9542eba5.gif

在Demo.Identity.Application项目IdentityApplicationAutoMapperProfile类的IdentityApplicationAutoMapperProfile方法中添加如下代码:

this.CreatePermissionsMap();

75171c85c6a87c6f43a105900b24fdff.gif

在Demo.Identity.Application项目Permissions文件夹中添加PermissionTreeBuilder类,定义构造权限树形结构的通用方法如下:

using System.Collections.Generic;
using System.Linq;
using Demo.Identity.Permissions.Dto;namespace Demo.Identity.Permissions;/// <summary>
/// 权限建树帮助类
/// </summary>
public static class PermissionTreeBuilder
{/// <summary>/// 建立树形结构/// </summary>/// <param name="lst"></param>/// <returns></returns>public static List<PermissionTreeDto> Build(List<PermissionTreeDto> lst){var result = lst.ToList();for (var i = 0; i < result.Count; i++){if (result[i].ParentCode == null){continue;}foreach (var item in lst){item.Children ??= new List<PermissionTreeDto>();if (item.Code != result[i].ParentCode){continue;}item.Children.Add(result[i]);result.RemoveAt(i);i--;break;}}return result;}
}

030c797a2c1931482430a4de28c4d644.gif

之后我们在Demo.Identity.Application项目Permissions文件夹中添加权限管理实现类SysPermissionAppService如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Demo.Core.CommonFunction;
using Demo.Identity.Permissions.Dto;
using Demo.Identity.Permissions.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;
using Demo.Core.CommonExtension;namespace Demo.Identity.Permissions
{/// <summary>/// 权限管理应用服务/// </summary>public class SysPermissionAppService : IdentityAppService, ISysPermissionAppService{#region 初始化private readonly IRepository<RolePermissions> _rolePermissionsRepository;private readonly IRepository<SysPermission> _sysPermissionsRepository;private readonly IRepository<IdentityUserRole> _userRolesRepository;public SysPermissionAppService(IRepository<RolePermissions> rolePermissionsRepository,IRepository<SysPermission> sysPermissionsRepository,IRepository<IdentityUserRole> userRolesRepository
){_rolePermissionsRepository = rolePermissionsRepository;_sysPermissionsRepository = sysPermissionsRepository;_userRolesRepository = userRolesRepository;}#endregion#region 按服务注册权限/// <summary>/// 按服务注册权限/// </summary>/// <param name="serviceName">服务名称</param>/// <param name="permissions">权限列表</param>/// <returns></returns>public async Task<bool> RegistPermission(string serviceName, List<SysPermissionDto> permissions){//根据服务名称查询现有权限var entities = await AsyncExecuter.ToListAsync( (await _sysPermissionsRepository.GetQueryableAsync()).Where(c => c.ServiceName == serviceName));var lst = ObjectMapper.Map<List<SysPermissionDto>, List<SysPermission>>(permissions);ListCompare.MutiCompare(lst, entities, x => x.Code, async (entity, isNew) =>{if (isNew){//新增await _sysPermissionsRepository.InsertAsync(entity);}else{//修改var tmp = lst.FirstOrDefault(x => x.Code == entity.Code);//调用权限判断方法,如果code和name相同就不进行添加if (!entity.Equals(tmp)&&tmp!=null){entity.SetId(tmp.Id);await _sysPermissionsRepository.UpdateAsync(entity);}}}, out var needRemove);foreach (var item in needRemove){//删除多余项await _sysPermissionsRepository.DeleteAsync(item.Value);}return true;}#endregion#region 按服务获取权限/// <summary>///     按服务获取权限/// </summary>/// <param name="serviceName">服务名称</param>/// <returns>查询结果</returns>public async Task<List<SysPermissionDto>> GetPermissions(string serviceName){var query = (await _sysPermissionsRepository.GetQueryableAsync()).Where(x => x.ServiceName == serviceName);//使用AsyncExecuter进行异步查询var lst = await AsyncExecuter.ToListAsync(query);//映射实体类到dtoreturn ObjectMapper.Map<List<SysPermission>, List<SysPermissionDto>>(lst);}#endregion#region 获取完整权限树/// <summary>/// 获取完整权限树/// </summary>/// <returns>查询结果</returns>public async Task<List<PermissionTreeDto>> GetPermissionTree(){var per = await _sysPermissionsRepository.ToListAsync();var lst = ObjectMapper.Map<List<SysPermission>, List<PermissionTreeDto>>(per);return PermissionTreeBuilder.Build(lst);}#endregion#region 获取用户权限码/// <summary>/// 获取用户权限码/// </summary>/// <param name="userId">用户编号</param>/// <returns>查询结果</returns>public async Task<List<string>> GetUserPermissionCode(Guid userId){var query = from user in (await _userRolesRepository.GetQueryableAsync()).Where(c => c.UserId == userId)join rp in (await _rolePermissionsRepository.GetQueryableAsync()) on user.RoleId equals rp.RoleIdjoin pe in (await _sysPermissionsRepository.GetQueryableAsync()) on rp.PermissionId equals pe.Idselect pe.Code;var permission = await AsyncExecuter.ToListAsync(query);return permission.Distinct(x=>x);}#endregion}
}

2e9636e35cd687e69a7bda0f414e2491.gif

添加角色权限关系管理实现类RolePermissionsAppService如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Demo.Identity.Permissions.Dto;
using Demo.Identity.Permissions.Entities;
using Volo.Abp.Domain.Repositories;namespace Demo.Identity.Permissions
{/// <summary>/// 角色管理应用服务/// </summary>public class RolePermissionsAppService : IdentityAppService, IRolePermissionsAppService{#region 初始化private readonly IRepository<RolePermissions> _rolePermissionsRepository;private readonly IRepository<SysPermission> _sysPermissionsRepository;public RolePermissionsAppService(IRepository<RolePermissions> rolePermissionsRepository,IRepository<SysPermission> sysPermissionsRepository
){_rolePermissionsRepository = rolePermissionsRepository;_sysPermissionsRepository = sysPermissionsRepository;}#endregion#region 获取角色所有权限/// <summary>/// 获取角色所有权限/// </summary>/// <param name="roleId">角色ID</param>/// <returns></returns>public async Task<List<PermissionTreeDto>> GetPermission(Guid roleId){var query = from rp in (await _rolePermissionsRepository.GetQueryableAsync()).Where(x => x.RoleId == roleId)join permission in (await _sysPermissionsRepository.GetQueryableAsync())on rp.PermissionId equals permission.Idselect permission;var permissions = await AsyncExecuter.ToListAsync(query);var lst = ObjectMapper.Map<List<SysPermission>, List<PermissionTreeDto>>(permissions);return PermissionTreeBuilder.Build(lst);}#endregion#region 设置角色权限/// <summary>/// 设置角色权限/// </summary>/// <param name="roleId">橘色编号</param>/// <param name="permissions">权限编号</param>/// <returns></returns>public async Task SetPermission(SetRolePermissionsDto dto){await _rolePermissionsRepository.DeleteAsync(x => x.RoleId == dto.RoleId);foreach (var permissionId in dto.Permissions){RolePermissions entity = new RolePermissions(){PermissionId = permissionId,RoleId = dto.RoleId,};await _rolePermissionsRepository.InsertAsync(entity);}}#endregion}
}

533db24a7e27c1df73b6eb3a7547613b.gif

 在Demo.Identity.EntityFrameworkCore项目IdentityDbContext类中加入以下属性:

public DbSet<SysPermission> SysPermissions { get; set; }
public DbSet<RolePermissions> RolePermissions { get; set; }

541fee81fe0e6e01440cada0ca593859.gif

在Demo.Identity.EntityFrameworkCore项目目录下启动命令提示符,执行以下命令分别创建和执行数据迁移:

dotnet-ef migrations add AddPermissions
dotnet-ef database update

7b7b9ffcbbf1363fbedb091b3b45329d.gif

在Demo.Identity.EntityFrameworkCore项目IdentityEntityFrameworkCoreModule类ConfigureServices方法中找到 options.AddDefaultRepositories(includeAllEntities: true); ,在其后面加入以下代码:

options.AddDefaultRepository<IdentityUserRole>();

51cc46674ce16b0cac6aa979d588dcf6.png

完成后运行身份管理服务,可正常运行和访问各接口,则基础服务层修改完成。后续操作请看下一篇

f8e71b4940c5412ab101fd7014ee2fb3.png

end

781c6fa3e12d116dbb90390fd14e7a12.png

cc34818bd82fcfd1bb2808e7b6dbe677.png

5b994a5a44dd2ca3f1d7d13201560b2a.png

更多精彩

关注我获得

4d2710f8e7134bc22784242e2f96ca64.png

这篇关于ABP vNext微服务架构详细教程——分布式权限框架(上)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/352041

相关文章

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1

sysmain服务可以禁用吗? 电脑sysmain服务关闭后的影响与操作指南

《sysmain服务可以禁用吗?电脑sysmain服务关闭后的影响与操作指南》在Windows系统中,SysMain服务(原名Superfetch)作为一个旨在提升系统性能的关键组件,一直备受用户关... 在使用 Windows 系统时,有时候真有点像在「开盲盒」。全新安装系统后的「默认设置」,往往并不尽编

基于C#实现PDF转图片的详细教程

《基于C#实现PDF转图片的详细教程》在数字化办公场景中,PDF文件的可视化处理需求日益增长,本文将围绕Spire.PDFfor.NET这一工具,详解如何通过C#将PDF转换为JPG、PNG等主流图片... 目录引言一、组件部署二、快速入门:PDF 转图片的核心 C# 代码三、分辨率设置 - 清晰度的决定因

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

Java中HashMap的用法详细介绍

《Java中HashMap的用法详细介绍》JavaHashMap是一种高效的数据结构,用于存储键值对,它是基于哈希表实现的,提供快速的插入、删除和查找操作,:本文主要介绍Java中HashMap... 目录一.HashMap1.基本概念2.底层数据结构:3.HashCode和equals方法为什么重写Has

Java Scanner类解析与实战教程

《JavaScanner类解析与实战教程》JavaScanner类(java.util包)是文本输入解析工具,支持基本类型和字符串读取,基于Readable接口与正则分隔符实现,适用于控制台、文件输... 目录一、核心设计与工作原理1.底层依赖2.解析机制A.核心逻辑基于分隔符(delimiter)和模式匹