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

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

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

相关文章

前端每隔几秒发送一个请求

2019独角兽企业重金招聘Python工程师标准>>> <html><head><SCRIPT LANGUAGE"JavaScript"> var timer;//声明一个定时器 var count 0; function test() { //每隔500毫秒执行一次add()方法 timer window.setInterval("add()"…

element 表单回显验证_关于vue el-form表单报错的问题

在写el-form表单的时候&#xff0c;遇到了蛮多问题&#xff0c;在这里记录一下。1.表单验证报错[Element Warn][Form]model is required for validate to work!初始代码如下&#xff1a;<!-- 表单部分 --> <el-formref"inputForm"size"mini"inlin…

我做了一个 Istio Workshop,这是第一讲介绍

我是 Jimmy Song[1]&#xff0c;Tetrate 布道师&#xff0c;云原生社区创始人。你可以能想到为什么在这个时候创建一个 Istio 教程&#xff0c;因为市面上已经林林总总有不少关于 Istio 的书籍和教程了&#xff0c;但是我们都知道 Istio 是一个新兴技术&#xff0c;发展十分迅速…

Swoole入门指南:PHP7安装Swoole详细教程(一)

好久未更新了&#xff0c;不是懒呃&#xff0c;是太忙啦&#xff01;终于偷得浮生几日闲。这一段时间准备为大家带来swoole的入门教程&#xff0c;感受一下php的nodeJs强悍之处。 所有的示例代码均放在了github上&#xff1a;learn-swoole 环境 这里不在使用apache做为web serv…

C/C++之#ifdef、#if、#if defined的区别

1、看代码 2、运行结果 3、分析 #fi&#xff1a;后面接的表达式&#xff0c;如果为1就编译包含里面的内容 #ifdef&#xff1a;后面接的是一个宏&#xff0c;只要定义这个宏就行 #if defined(x)&#xff1a;和#ifdef效果一样 #if !defined(x)&#xff1a;和#ifndef效果一样

.Net Core 读取文件时中文乱码问题的解决方法

背景今天在使用core web api上传txt文档的时候本来很顺利的&#xff0c;但是一测试发现读取的中文内容是乱码的&#xff0c;很是纳闷。出于经验&#xff0c;立马把代码的Encoding.Default改成 Encoding.uft8, 发现还是不行。后面索性把上传的文件另存为下&#xff0c;特地选择带…

关于使用indexedDB的本地存储(2)

我又回来了~这几天估计没喝茶&#xff0c;每天头都晕晕的&#xff0c;昨晚上和室友看了素鸡7&#xff0c;伤心啊&#xff0c;自己一直都喜欢这个系列&#xff0c;感觉童年真的是渐行渐远了…… 上一篇说到了哪些内容我这里罗列一下 建立和打开数据库、删除数据库、判断objectSt…

BCVP开发者社区2022专属周边第一弹

BCVP TeamBCVP开发者社区是博主老张的哲学发起&#xff0c;鼓励每个人都可参与的一个分享社区&#xff0c;目前已经有12个参与者&#xff0c;19个开源项目。欢迎加入BCVP&#xff0c;获取专属周边礼品&#xff08;文末有介绍&#xff09;。官方博客还在筹建中&#xff0c;预计2…

C++之类模板最简单的使用

1、说明类模板 1) 声明类模板时要增加一行 template <class 类型参数名> template意思是“模板”,是声明类模板时必须写的关键字。在template后面的尖括号内的内容为模板的参数表列,关键字class表示其后面的是类型参数 2、写代码理解 3、运行结果 4、总结 上…

mysql 5.5主从同步_MySQL5.5+配置主从同步并结合ThinkPHP5设置分布式数据库

This browser does not support music or audio playback. Please play it in WeChat or another browser.前言&#xff1a;本文章是在同处局域网内的两台windows电脑&#xff0c;且MySQL是5.5以上版本下进行的一主多从同步配置&#xff0c;并且使用的是集成环境工具PHPStudy为…

C# 10的新特性

点击上方蓝字关注我们&#xff08;本文阅读所需15分钟&#xff09;我们很高兴地宣布 C# 10 作为 .NET 6 和 Visual Studio 2022的一部分已经发布了。在这篇文章中&#xff0c;我们将介绍 C# 10 的许多新功能&#xff0c;这些功能使您的代码更漂亮、更具表现力、更快。阅读 Visu…

C++编译出现binding ‘const string {aka const std::__cxx11::basic_string<char>}’ to reference of type ‘std

编译异常如下&#xff1a; 解决办法&#xff1a; 我的函数是这样的 string &larger(const string &s1, const string &s2){return s1.size() > s2.size()? s1 : s2; }改成这样就行了 const string &larger(const string &s1, const string &s2){r…

POJ 3181 Dollar Dayz DP

f[i][j]f[i-j][j]f[i][j-1]&#xff0c;结果很大需要高精度。 //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<iostream> #include…

.NET再出发!20岁生日快乐

.NET 20周年纪念2022年是.NET20周年纪念&#xff0c;一个技术能经历20个年头&#xff0c;也说明了它的成功。想起和 .NET刚接触的时候&#xff0c;我还是一个大一的学生&#xff0c;现在也已经步入中年。作为一名80后开发者&#xff0c;我相信很多同龄人和我一样经历了中国甚至…

C++之invalid initialization of non-const reference of type ‘int’ from an rvalue of type ‘int’

1、看代码 2、编译结果 3、分析和解决 就拿f(a + b)来说,a+b的值会存在一个临时变量中,当把这个临时变量传给f时,由于f的声明中,参数是int&,不是常量引用,因为c++编译器的一个关于语义的限制。如果一个参数是以非const引用传入,c++编译器就有理由认为程序员会在函数…

mysql cbo优化器_查询优化器介绍 - PolarDB-X 云原生分布式数据库 - 阿里云

PolarDB-X接收到一条SQL后的执行过程大致如下&#xff1a;语法解析器(Parser)将SQL文本解析成抽象语法树(AST)。语法树被转化成基于关系代数的逻辑计划。优化器(Optimizer)对逻辑计划进行优化得到物理计划。执行器(Executor)执行该计划&#xff0c;得到查询结果并返回给用户。本…

这周,我们作前端,实现统一的过滤搜索

这周统一了过滤和搜索样式&#xff0c; 作个记录。 还自己写了两个css样式&#xff0c;长见识了。 filter.html {% load staticfiles %}<link rel"stylesheet" href"{% static css/select2.min.css%}" /> <link rel"stylesheet" href&q…

找最大重复次数的数和重复次数(C++ Pair)

Problem A: 第一集 你好&#xff0c;世界冠军 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 265 Solved: 50[Submit][Status][Web Board]Description “我宣布&#xff0c;第十届国际程序设计竞赛现在开始&#xff01;本次比赛时间为9点到14点……”伴随着大赛主席的宣布…

观察者模式VS发布-订阅模式

前言观察者模式的大名&#xff0c;想必各位看官早已有所耳闻。从我们现实生活来说&#xff0c;微信公众号订阅、医院挂号叫号等都属于它的实际应用。在程序世界中&#xff0c;它是一种用于将代码解耦的设计模式&#xff0c;如果你想掌握并理解这种设计模式&#xff0c;今天就和…

Kubernetes 集群和应用监控方案的设计与实践

目录Kubernetes 监控监控对象Prometheus指标实践节点监控部署 Prometheus部署 Kube State Metrics部署 Grafana应用如何接入 Prometheus 和 Grafana告警Kubernetes 监控当你的应用部署到 Kubenetes 后&#xff0c;你很难看到容器内部发生了什么&#xff0c;一旦容器死掉&#x…