开发框架Furion之WebApi+SqlSugar (一)

news2024/11/13 7:52:15

目录

1.开发环境

2.项目创建

2.1创建WebApi主项目

2.2 创建Start类库

2.3创建Model实体类库

2.4创建Application仓储业务类库

2.5创建Unility通用方法类库

3.基础功能配置

3.1 Model实体对象与数据表映射

3.2 基类仓储及动态Api接口配置

3.3 数据库IOC注册

 3.4 Startup配置

3.5 Swagger配置

3.6启动配置

4.项目使用示例展示


1.开发环境

.NET6

Visual Studio 2022

SQLServer

SqlSugar SqlSugar ORM 5.X 官网 、文档、教程 - SqlSugar 5x - .NET果糖网

2.项目创建

2.1创建WebApi主项目

创建名为MyFurion.WebApi的项目

 

 

2.2 创建Start类库

创建名称为 MyFurion.Start的类库

解决方案右击——添加——新项目——类库

 

 

2.3创建Model实体类库

创建名称为 MyFurion.Model的类库

创建步骤同 2.2创建Startup类库

2.4创建Application仓储业务类库

创建名称为 MyFurion.Application的类库

创建步骤同 2.2创建Startup类库

2.5创建Unility通用方法类库

创建名称为 MyFurion.Unility的类库

创建步骤同 2.2创建Startup类库

至此需要的类库项目创建完成

3.基础功能配置

3.1 Model实体对象与数据表映射

MyFurion.Model项目中,通过Nuget添加Furion、Furion.Extras.DatabaseAccessor.SqlSugar、Furion.Extras.ObjectMapper.Mapster、SqlSugarCore,同时添加对项目MyFurion.Unility的引用

创建实体基类BaseEntity

using SqlSugar;
using System.Text.Json.Serialization;
using MyFurion.Unility.Const;
namespace MyFurion.Model
{
    /// <summary>
    /// 实体基类
    /// </summary>
    public class BaseEntity
    {
        /// <summary>
        /// 
        /// </summary>
        public BaseEntity()
        {
            CreateTime = DateTime.Now;
            IsDeleted = false;
            Id = SnowFlakeSingle.Instance.NextId();
        }
        /// <summary>
        /// id
        /// </summary>
        [SugarColumn(IsPrimaryKey =true,DefaultValue ="主键")]
        public long Id { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>
        [SugarColumn(IsOnlyIgnoreUpdate = true,ColumnDescription = "创建时间")]
        public DateTime CreateTime { get; set; }
        /// <summary>
        /// 创建人id
        /// </summary>
        [SugarColumn(IsOnlyIgnoreUpdate = true,IsNullable =true, ColumnDescription = "创建人id")]
        [JsonIgnore]
        public string? CreateUserId { get; set; }
        /// <summary>
        /// 创建人
        /// </summary>
        [SugarColumn(IsOnlyIgnoreUpdate = true, IsNullable = true, ColumnDescription = "创建人")]
        [JsonIgnore]
        public string? CreateUser { get; set; }
        /// <summary>
        /// 创建单位id
        /// </summary>
        [SugarColumn(IsOnlyIgnoreUpdate = true, IsNullable = true, ColumnDescription = "创建单位id")]
        [JsonIgnore]
        public string? CreateOrgId { get; set; }
        /// <summary>
        /// 修改时间
        /// </summary>
        [SugarColumn(IsOnlyIgnoreInsert =true,IsNullable =true, ColumnDescription = "修改时间")]
        public DateTime? ModifyTime { get; set; }
        /// <summary>
        /// 修改人id
        /// </summary>
        [SugarColumn(IsOnlyIgnoreInsert = true, IsNullable = true, ColumnDescription = "修改人id")]
        [JsonIgnore]
        public string? ModifyUserId { get; set; }
        /// <summary>
        /// 修改人
        /// </summary>
        [SugarColumn(IsOnlyIgnoreInsert = true, IsNullable = true, ColumnDescription = "修改人")]
        [JsonIgnore]
        public string? ModifyUser { get; set; }
        /// <summary>
        /// 删除标识
        /// </summary>
        [SugarColumn(ColumnDescription ="删除标识")]
        public bool IsDeleted { get; set; }
        /// <summary>
        /// 删除时间
        /// </summary>
        [SugarColumn(IsOnlyIgnoreInsert = true, ColumnDescription = "删除时间",IsNullable =true)]
        [JsonIgnore]
        public DateTime? DeleteTime { get; set; }
        /// <summary>
        /// 删除原因
        /// </summary>
        [SugarColumn(IsOnlyIgnoreInsert = true, ColumnDescription = "删除原因", IsNullable = true)]
        public string? DeleteReason { get; set; }
        /// <summary>
        /// 删除人id
        /// </summary>
        [SugarColumn(IsOnlyIgnoreInsert = true, ColumnDescription = "删除人id", IsNullable = true)]
        [JsonIgnore]
        public string? DeleteUserId { get; set; }
        /// <summary>
        /// 删除人
        /// </summary>
        [SugarColumn(IsOnlyIgnoreInsert = true, ColumnDescription = "删除人", IsNullable = true)]
        [JsonIgnore]
        public string? DeleteUser { get; set; }
        /// <summary>
        /// 排序
        /// </summary>
        [SugarColumn(ColumnDescription ="排序")]
        public int SortNum { get; set; }
        /// <summary>
        /// 备注
        /// </summary>
        [SugarColumn(ColumnDescription = "备注", IsNullable =true,ColumnDataType =CommonConst.DB_STRING_MAX)]
        public string? Remark { get; set; }
        /// <summary>
        /// 多租户ID
        /// </summary>
        [SugarColumn(ColumnDescription = "多租户ID", DefaultValue = "0")]
        [JsonIgnore]
        public long TenantId { get; set; }
    }
}

3.2 基类仓储及动态Api接口配置

MyFurion.Application项目中,通过Nuget添加SqlSugar.IOC,同时添加对MyFurion.Model项目的引用

新增Dtos、Repository、Controller三个文件夹,分别用于查询条件及输出信息的实体对象、业务代码、Api接口文件

在Dtos文件加下创建PageResult类(分页结果)及PageBaseInput(分页查询条件基类)

namespace MyFurion.Application.Dtos
{
    /// <summary>
    /// 分页数据信息
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class PageResult<T>
    {
        /// <summary>
        /// 页码
        /// </summary>
        public int PageIndex { get; set; }
        /// <summary>
        /// 分页大小
        /// </summary>
        public int PageSize { get; set; }
        /// <summary>
        /// 页总数
        /// </summary>
        public int TotalPage { get; set; }
        /// <summary>
        /// 记录总数
        /// </summary>
        public int TotalCount { get; set; }
        /// <summary>
        /// 记录集合
        /// </summary>
        public List<T> Items { get; set; } = new();
    }
}
namespace MyFurion.Application.Dtos
{
    /// <summary>
    /// 分页查询条件基类
    /// </summary>
    public class PageBaseInput
    {
        /// <summary>
        /// 页码
        /// </summary>
        public int PageIndex { get; set; } = 1;
        /// <summary>
        /// 分页大小
        /// </summary>
        public int PageSize { get; set; } = 20;
        /// <summary>
        /// 开始日期
        /// </summary>
        public DateTime? StartTime { get; set; }
        /// <summary>
        /// 结束日期
        /// </summary>
        public DateTime? EndTime { get; set; }
    }
}

 创建GlobalUsings.cs全局引用配置类

global using System.Reflection;
global using System.ComponentModel.DataAnnotations;
global using System.Linq.Expressions;
global using Microsoft.AspNetCore.Authorization;
global using Microsoft.AspNetCore.Http;
global using Microsoft.AspNetCore.Mvc;
global using Microsoft.CodeAnalysis;
global using Furion;
global using Furion.DataEncryption;
global using Furion.DataValidation;
global using Furion.DependencyInjection;
global using Furion.DynamicApiController;
global using Furion.Extensions;
global using Furion.FriendlyException;
global using Furion.Logging;
global using SqlSugar;
global using Mapster;
global using SqlSugar.IOC;
global using MyFurion.Model;
global using MyFurion.Application.Dtos;

创建仓储基类BaseRepository

namespace MyFurion.Application
{
    /// <summary>
    /// 仓储基类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class BaseRepository<T> : SimpleClient<T> where T : BaseEntity, new()
    {
        public ITenant itenant = null;//多租户事务
        public BaseRepository(ISqlSugarClient context = null) : base(context)
        {
            //通过特性拿到ConfigId
            var configId = typeof(T).GetCustomAttribute<TenantAttribute>()?.configId;
            if (configId != null)
            {
                Context = DbScoped.SugarScope.GetConnectionScope(configId);//根据类传入的ConfigId自动选择
            }
            else
            {
                Context = context ?? DbScoped.SugarScope.GetConnectionScope(0);//没有默认db0
            }
            //Context = DbScoped.SugarScope.GetConnectionScopeWithAttr<T>();
            itenant = DbScoped.SugarScope;//设置租户接口
        }

        #region 基础业务
        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public async Task<bool> Add(T t)
        {
            try
            {
                int rowsAffect = await Context.Insertable(t).IgnoreColumns(true).ExecuteCommandAsync();
                return rowsAffect > 0;
            }
            catch (Exception ex)
            {
                Log.Error($"新增失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 批量新增
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public async Task<bool> Insert(List<T> t)
        {
            try
            {
                int rowsAffect = await Context.Insertable(t).ExecuteCommandAsync();
                return rowsAffect > 0;
            }
            catch (Exception ex)
            {
                Log.Error($"批量新增失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 插入设置列数据
        /// </summary>
        /// <param name="parm"></param>
        /// <param name="iClumns"></param>
        /// <param name="ignoreNull"></param>
        /// <returns></returns>
        public async Task<bool> Insert(T parm, Expression<Func<T, object>> iClumns = null, bool ignoreNull = true)
        {
            try
            {
                int rowsAffect = await Context.Insertable(parm).InsertColumns(iClumns).IgnoreColumns(ignoreNullColumn: ignoreNull).ExecuteCommandAsync();
                return rowsAffect > 0;
            }
            catch (Exception ex)
            {
                Log.Error($"插入设置列数据失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="ignoreNullColumns"></param>
        /// <returns></returns>
        public async Task<bool> Update(T entity, bool ignoreNullColumns = false)
        {
            try
            {
                int rowsAffect = await Context.Updateable(entity).IgnoreColumns(ignoreNullColumns).ExecuteCommandAsync();
                return rowsAffect >= 0;
            }
            catch (Exception ex)
            {
                Log.Error($"更新失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 根据实体类更新指定列 eg:Update(dept, it => new { it.Status });只更新Status列,条件是包含
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="expression"></param>
        /// <param name="ignoreAllNull"></param>
        /// <returns></returns>
        public async Task<bool> Update(T entity, Expression<Func<T, object>> expression, bool ignoreAllNull = false)
        {
            try
            {
                int rowsAffect = await Context.Updateable(entity).UpdateColumns(expression).IgnoreColumns(ignoreAllNull).ExecuteCommandAsync();
                return rowsAffect >= 0;
            }
            catch (Exception ex)
            {
                Log.Error($"根据实体类更新指定列失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 根据实体类更新指定列 eg:Update(dept, it => new { it.Status }, f => depts.Contains(f.DeptId));只更新Status列,条件是包含
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="expression"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public async Task<bool> Update(T entity, Expression<Func<T, object>> expression, Expression<Func<T, bool>> where)
        {
            try
            {
                int rowsAffect = await Context.Updateable(entity).UpdateColumns(expression).Where(where).ExecuteCommandAsync();
                return rowsAffect >= 0;
            }
            catch (Exception ex)
            {
                Log.Error($"根据实体类更新指定列失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 更新指定列 eg:Update(w => w.NoticeId == model.NoticeId, it => new SysNotice(){ UpdateTime = DateTime.Now, Title = "通知标题" });
        /// </summary>
        /// <param name="where"></param>
        /// <param name="columns"></param>
        /// <returns></returns>
        public async Task<bool> Update(Expression<Func<T, bool>> where, Expression<Func<T, T>> columns)
        {
            try
            {
                int rowsAffect = await Context.Updateable<T>().SetColumns(columns).Where(where).RemoveDataCache().ExecuteCommandAsync();
                return rowsAffect >= 0;
            }
            catch (Exception ex)
            {
                Log.Error($"更新指定列失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 事务 eg:var result = UseTran(() =>{SysRoleRepository.UpdateSysRole(sysRole);DeptService.DeleteRoleDeptByRoleId(sysRole.ID);DeptService.InsertRoleDepts(sysRole);});
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        public bool UseTran(Action action)
        {
            try
            {
                var result = Context.Ado.UseTran(() => action());
                return result.IsSuccess;
            }
            catch (Exception ex)
            {
                Context.Ado.RollbackTran();
                Log.Error($"事务执行失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id">主键id</param>
        /// <param name="IsDelete">是否真删除</param>
        /// <returns></returns>
        public async Task<bool> DeleteById(long id, bool IsDelete = false)
        {
            int rowsAffect = 0;
            try
            {
                if (IsDelete)
                {
                    rowsAffect = await Context.Deleteable<T>().In(id).ExecuteCommandAsync();
                }
                else
                {
                    //假删除 实体属性有isdelete或者isdeleted 请升级到5.0.4.9+,(5.0.4.3存在BUG)
                    rowsAffect = await Context.Deleteable<T>().In(id).IsLogic().ExecuteCommandAsync();
                }
                return rowsAffect > 0;
            }
            catch (Exception ex)
            {
                Log.Error($"删除失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 根据查询条件删除
        /// </summary>
        /// <param name="where"></param>
        /// <param name="IsDelete"></param>
        /// <returns></returns>
        public async Task<bool> DeleteByWhere(Expression<Func<T, bool>> where, bool IsDelete = false)
        {
            int rowsAffect = 0;
            try
            {
                if (IsDelete)
                {
                    rowsAffect = await Context.Deleteable<T>().Where(where).ExecuteCommandAsync();
                }
                else
                {
                    //假删除 实体属性有isdelete或者isdeleted 请升级到5.0.4.9+,(5.0.4.3存在BUG)
                    rowsAffect = await Context.Deleteable<T>().Where(where).IsLogic().ExecuteCommandAsync();
                }
                return rowsAffect > 0;
            }
            catch (Exception ex)
            {
                Log.Error($"根据查询条件删除失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 根据id获取数据
        /// </summary>
        /// <param name="id">主键值</param>
        /// <returns>泛型实体</returns>
        public async Task<T> GetEntityById(long id)
        {
            return await Context.Queryable<T>().FirstAsync(p => p.Id == id);
        }
        /// <summary>
        /// 数据是否存在
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public async Task<bool> IsExists(Expression<Func<T, bool>> expression)
        {
            return await Context.Queryable<T>().Where(expression).AnyAsync();
        }
        /// <summary>
        /// 获取所有数据
        /// </summary>
        /// <returns></returns>
        public async Task<List<T>> GetAll()
        {
            return await Context.Queryable<T>().ToListAsync();
        }
        /// <summary>
        /// 根据查询条件获取数据
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public async Task<List<T>> GetListByWhere(Expression<Func<T, bool>> expression)
        {
            return await Context.Queryable<T>().Where(expression).ToListAsync();
        }
        /// <summary>
        /// 根据查询条件获取数据(动态表格拼接查询条件)
        /// </summary>
        /// <param name="conditions"></param>
        /// <returns></returns>
        public async Task<List<T>> GetListByWhere(List<IConditionalModel> conditions)
        {
            return await Context.Queryable<T>().Where(conditions).ToListAsync();
        }
        /// <summary>
        /// 根据查询条件获取数据
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="orderFiled">排序字段</param>
        /// <param name="orderEnum">排序方式</param>
        /// <returns></returns>
        public async Task<List<T>> GetList(Expression<Func<T, bool>> expression, Expression<Func<T, object>> orderFiled, OrderByType orderEnum = OrderByType.Desc)
        {
            return await Context.Queryable<T>().Where(expression).OrderByIF(orderEnum == OrderByType.Asc, orderFiled, OrderByType.Asc).OrderByIF(orderEnum == OrderByType.Desc, orderFiled, OrderByType.Desc).ToListAsync();
        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public PageResult<T> GetPageList(Expression<Func<T, bool>> expression, int pageIndex, int pageSize)
        {
            int totalCount = 0;
            var result = Context.Queryable<T>().Where(expression).ToPageList(pageIndex, pageSize, ref totalCount);
            var pageResult = new PageResult<T>();
            pageResult.Items = result;
            pageResult.TotalCount = totalCount;
            pageResult.TotalPage = (int)Math.Ceiling(totalCount / (double)pageSize);
            return pageResult;
        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        public async Task<PageResult<T>> GetPageListAsync(Expression<Func<T, bool>> expression, int pageIndex, int pageSize)
        {
            RefAsync<int> totalCount = 0;
            var result = await Context.Queryable<T>().Where(expression).ToPageListAsync(pageIndex, pageSize, totalCount);
            var pageResult = new PageResult<T>();
            pageResult.Items = result;
            pageResult.TotalCount = totalCount;
            pageResult.TotalPage = (int)Math.Ceiling(totalCount / (double)pageSize);
            return pageResult;
        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderFiled"></param>
        /// <param name="orderEnum"></param>
        /// <returns></returns>
        public PageResult<T> GetPageList(Expression<Func<T, bool>> expression, int pageIndex, int pageSize, Expression<Func<T, object>> orderFiled, OrderByType orderEnum = OrderByType.Desc)
        {
            int totalCount = 0;
            var result = Context.Queryable<T>().Where(expression).OrderByIF(orderEnum == OrderByType.Asc, orderFiled, OrderByType.Asc).OrderByIF(orderEnum == OrderByType.Desc, orderFiled, OrderByType.Desc)
                .ToPageList(pageIndex, pageSize, ref totalCount);
            var pageResult = new PageResult<T>();
            pageResult.Items = result;
            pageResult.TotalCount = totalCount;
            pageResult.TotalPage = (int)Math.Ceiling(totalCount / (double)pageSize);
            return pageResult;
        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderFiled"></param>
        /// <param name="orderEnum"></param>
        /// <returns></returns>
        public async Task<PageResult<T>> GetPageListAsync(Expression<Func<T, bool>> expression, int pageIndex, int pageSize, Expression<Func<T, object>> orderFiled, OrderByType orderEnum = OrderByType.Desc)
        {
            RefAsync<int> totalCount = 0;
            var result = await Context.Queryable<T>().Where(expression).OrderByIF(orderEnum == OrderByType.Asc, orderFiled, OrderByType.Asc).OrderByIF(orderEnum == OrderByType.Desc, orderFiled, OrderByType.Desc)
                .ToPageListAsync(pageIndex, pageSize, totalCount);
            var pageResult = new PageResult<T>();
            pageResult.Items = result;
            pageResult.TotalCount = totalCount;
            pageResult.TotalPage = (int)Math.Ceiling(totalCount / (double)pageSize);
            return pageResult;
        }
        /// <summary>
        /// 获取分页数据
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderFiled"></param>
        /// <param name="orderEnum"></param>
        /// <returns></returns>
        public async Task<PageResult<T>> GetOffsetPageListAsync(Expression<Func<T, bool>> expression, int pageIndex, int pageSize, Expression<Func<T, object>> orderFiled, OrderByType orderEnum = OrderByType.Desc)
        {
            RefAsync<int> totalCount = 0;
            var result = await Context.Queryable<T>().Where(expression).OrderByIF(orderEnum == OrderByType.Asc, orderFiled, OrderByType.Asc).OrderByIF(orderEnum == OrderByType.Desc, orderFiled, OrderByType.Desc)
                .ToOffsetPageAsync(pageIndex, pageSize, totalCount);
            var pageResult = new PageResult<T>();
            pageResult.Items = result;
            pageResult.TotalCount = totalCount;
            pageResult.TotalPage = (int)Math.Ceiling(totalCount / (double)pageSize);
            return pageResult;
        }
        #endregion

        #region 海量业务高性能
        /// <summary>
        /// 新增(对于海量数据并且性能要高的)
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public async Task<bool> BulkAdd(T t)
        {
            try
            {
                int rowsAffect = await Context.Storageable(t).ToStorage().BulkCopyAsync();
                return rowsAffect > 0;
            }
            catch (Exception ex)
            {
                Log.Error($"新增失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 批量新增(对于海量数据并且性能要高的)
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public async Task<bool> BatchBulkAdd(List<T> t)
        {
            try
            {
                int rowsAffect = await Context.Storageable(t).ToStorage().BulkCopyAsync();
                return rowsAffect > 0;
            }
            catch (Exception ex)
            {
                Log.Error($"批量新增失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 更新(对于海量数据并且性能要高的)
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<bool> BulkUpdate(T entity)
        {
            try
            {
                int rowsAffect = await Context.Storageable(entity).ToStorage().BulkUpdateAsync();
                return rowsAffect >= 0;
            }
            catch (Exception ex)
            {
                Log.Error($"更新失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 批量更新(对于海量数据并且性能要高的)
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public async Task<bool> BatchBulkUpdate(List<T> t)
        {
            try
            {
                Context.QueryFilter = new QueryFilterProvider();//清空过滤器 否则会出现Parameter '@IsDelete0' must be defined错误
                int rowsAffect = await Context.Storageable(t).ToStorage().BulkUpdateAsync();
                return rowsAffect >= 0;
            }
            catch (Exception ex)
            {
                Log.Error($"更新失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 批量更新(对于海量数据并且性能要高的)
        /// </summary>
        /// <param name="t"></param>
        /// <param name="updateColumns"></param>
        /// <returns></returns>
        public async Task<bool> BatchBulkUpdate(List<T> t, string[] updateColumns)
        {
            try
            {
                Context.QueryFilter = new QueryFilterProvider();//清空过滤器 否则会出现Parameter '@IsDelete0' must be defined错误
                int rowsAffect = await Context.Storageable(t).ToStorage().BulkUpdateAsync(updateColumns);
                return rowsAffect >= 0;
            }
            catch (Exception ex)
            {
                Log.Error($"更新失败:{ex.Message}");
                return false;
            }
        }
        #endregion

        #region 存储过程
        /// <summary>
        /// 存储过程
        /// </summary>
        /// <param name="procedureName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public async Task<System.Data.DataTable> ProcedureQuery(string procedureName, object parameters)
        {
            return await Context.Ado.UseStoredProcedure().GetDataTableAsync(procedureName, parameters);
        }
        /// <summary>
        /// 存储过程
        /// </summary>
        /// <param name="procedureName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public async Task<List<T>> ProcedureQueryList(string procedureName, object parameters)
        {
            return await Context.Ado.UseStoredProcedure().SqlQueryAsync<T>(procedureName, parameters);
        }
        #endregion

        #region Fastest
        /// <summary>
        /// 批量新增
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public async Task<bool> BatchFastestkAdd(List<T> t)
        {
            try
            {
                int rowsAffect = await Context.Fastest<T>().BulkCopyAsync(t);
                return rowsAffect > 0;
            }
            catch (Exception ex)
            {
                Log.Error($"fastest批量新增失败:{ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// 批量更新
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public async Task<bool> BatchFastestUpdate(List<T> t)
        {
            try
            {
                Context.QueryFilter = new QueryFilterProvider();//清空过滤器 否则会出现Parameter '@IsDelete0' must be defined错误
                int rowsAffect = await Context.Fastest<T>().BulkUpdateAsync(t);
                return rowsAffect >= 0;
            }
            catch (Exception ex)
            {
                Log.Error($"fastest批量更新失败:{ex.Message}");
                return false;
            }
        }
        #endregion
    }
}

 创建applicationsettings.json配置文件,用于配置api接口的风格及分组显示等

{
  "$schema": "https://gitee.com/dotnetchina/Furion/raw/net6/schemas/v3/furion-schema.json",
  /*swagger文档描述配置*/
  "SpecificationDocumentSettings": {
    "DocumentTitle": "MyFurion | 规范化接口",
    "DocExpansionState": "None", //文档展开方式
    "GroupOpenApiInfos": [
      {
        "Group": "Default",
        "Title": "MyFurion API接口",
        "Description": "我的Furion",
        "Version": "1.0.0",
        "TermsOfService": "",
        "Contact": {
          "Name": "Furion",
          "Url": "",
          "Email": ""
        },
        "License": {
          "Name": "Apache-2.0",
          "Url": ""
        }
      }
    ]
  },
  /* controller 接口风格设置*/
  "DynamicApiControllerSettings": {
    "KeepName": true,
    "KeepVerb": true,
    "LowercaseRoute": false,
    "AsLowerCamelCase": true,
    "UrlParameterization": true,
    "VerbToHttpMethods": [
      //[ "getall", "HEAD" ], // => getall 会被复写为 `[HttpHead]`
      //[ "other", "PUT" ] // => 新增一条新规则,比如,一 `[other]` 开头会转换为 `[HttpPut]` 请求
    ]
  },
  /*
  跨域配置
  PolicyName:跨域策略名,string 类型,必填,默认 App.Cors.Policy
  WithOrigins:允许跨域的域名列表,string[] 类型,默认 *
  WithHeaders:请求表头,没有配置则允许所有表头,string[] 类型
  WithExposedHeaders:设置客户端可获取的响应标头,string[] 类型,默认 ["access-token", "x-access-token"]
  WithMethods:设置跨域允许请求谓词,没有配置则允许所有,string[] 类型
  AllowCredentials:是否允许跨域请求中的凭据,bool 类型,默认值 true
  SetPreflightMaxAge:设置预检过期时间,int 类型,默认值 24小时
  FixedClientToken:是否默认配置 WithExposedHeaders,bool 类型,默认 true
  SignalRSupport:是否启用 SignalR 跨域支持,bool 类型,默认 false
  */
  "CorsAccessorSettings": {
    "SignalRSupport": true, //是否启用 SignalR 跨域支持,bool 类型,默认 false
    //设置客户端可获取的响应标头,string[] 类型,默认 ["access-token", "x-access-token"]
    "WithExposedHeaders": [ "access-token", "x-access-token", "environment", "Content-Disposition" ]
  }
}

3.3 数据库IOC注册

在MyFurion.Start项目中,通过Nuget添加 AspNetCoreRateLimit、System.Linq.Dynamic.Core,同时添加对项目MyFurion.Application的引用

创建GlobalUsings类配置全局引用

global using System.Reflection;
global using System.Linq.Expressions;
global using Microsoft.Extensions.DependencyInjection;
global using Furion;
global using Furion.Logging;
global using SqlSugar;
global using SqlSugar.IOC;
global using System.Linq.Dynamic.Core;
global using MyFurion.Model;
global using MyFurion.Unility.Const;

创建SqlSugarSetup类,实现sqlsugar数据库IOC注册、CodeFirst、全局过滤器等功能的实现

namespace MyFurion.Start
{
    /// <summary>
    /// sqlsugarIOC注册
    /// </summary>
    public static class SqlSugarSetup
    {
        public static void AddSqlsugarSetup(IServiceCollection services)
        {
            List<IocConfig> iocConfigs = App.GetConfig<List<IocConfig>>("ConnectionConfigs");//获取数据库连接配置
            SugarIocServices.AddSqlSugar(iocConfigs);
            SugarIocServices.ConfigurationSugar(db =>
            {
                foreach (var iocItem in iocConfigs)
                {
                    SqlSugarProvider dbClient = db.GetConnection(iocItem.ConfigId);
                    SetQueryFilter(dbClient);
                    dbClient.Aop.OnLogExecuting = (sql, pars) =>
                    {
                        Log.Information(SqlProfiler.ParameterFormat(sql, pars));
                        Console.WriteLine(SqlProfiler.ParameterFormat(sql, pars));
                        Console.WriteLine();
                    };
                    var dbtype = dbClient.CurrentConnectionConfig.DbType;
                    dbClient.CurrentConnectionConfig.ConfigureExternalServices = new ConfigureExternalServices()
                    {
                        //自定义类型多库兼容
                        EntityService = (c, p) =>
                        {
                            if (p.DataType == CommonConst.DB_STRING_MAX)
                            {
                                if (dbtype == DbType.MySql)
                                {
                                    p.DataType = "longtext";
                                }
                                else if (dbtype == DbType.SqlServer)
                                {
                                    p.DataType = "nvarchar(max)";
                                }
                            }

                        }
                    };
                }
            });
            CreateTable(iocConfigs);
        }
        /// <summary>
        /// 创建数据库表 codefirst
        /// </summary>
        private static void CreateTable(List<IocConfig> iocConfigs)
        {
            foreach (var item in iocConfigs)
            {
                string configId = item.ConfigId;
                ISqlSugarClient db = DbScoped.SugarScope.GetConnectionScope(configId);
                db.DbMaintenance.CreateDatabase();//没有数据库的时候创建数据库
                var tableLists = db.DbMaintenance.GetTableInfoList();
                var files = System.IO.Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "MyFurion.Model.dll");
                if (files.Length > 0)
                {
                    Type[] types = Assembly.LoadFrom(files[0]).GetTypes().Where(it => it.BaseType == typeof(BaseEntity)).ToArray();
                    //Type[] types = Assembly.LoadFrom(files[0]).GetTypes().ToArray();
                    foreach (var entityType in types)
                    {
                        //创建数据表
                        string tableName = entityType.GetCustomAttribute<SugarTable>().TableName.ToLower();//根据特性获取表名称
                        var configid = entityType.GetCustomAttribute<TenantAttribute>()?.configId;//根据特性获取租户id
                        configid = configid == null ? "0" : configid.ToString();
                        if (!tableLists.Any(p => p.Name == tableName) && configId == configid.ToString())
                        {
                            //创建数据表包括字段更新
                            db.CodeFirst.InitTables(entityType);
                        }
                    }
                    db.Close();
                }
            }
        }
        /// <summary>
        /// 添加全局过滤器
        /// </summary>
        /// <param name="provider"></param>
        private static void SetQueryFilter(SqlSugarProvider provider)
        {
            //添加全局过滤器
            var files = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "MyFurion.Model.dll");
            if (files.Length > 0)
            {
                Type[] types = Assembly.LoadFrom(files[0]).GetTypes().Where(it => it.BaseType == typeof(BaseEntity)).ToArray();
                foreach (var entityType in types)
                {
                    //string tableName = entityType.GetCustomAttribute<SugarTable>().TableName;//根据特性获取表名称
                    var lambda = DynamicExpressionParser.ParseLambda( new[] { Expression.Parameter(entityType, "it") },typeof(bool), $"{nameof(BaseEntity.IsDeleted)} ==  @0",false);
                    provider.QueryFilter.Add(new TableFilterItem<object>(entityType, lambda, true)); //将Lambda传入过滤器
                }
            }
            //插入/更新过滤器,用于审计日志
            provider.Aop.DataExecuting = (oldValue, entityInfo) =>
            {
                if (entityInfo.OperationType == DataFilterType.InsertByObject)
                {
                    //if (entityInfo.PropertyName == "CreatedUId")
                    //{
                    //    entityInfo.SetValue(CurrentUserInfo.UId.ToString());//CreatedUId
                    //}
                    //if (entityInfo.PropertyName == "CreatedUName")
                    //{
                    //    entityInfo.SetValue(CurrentUserInfo.Name);
                    //}
                    //if (entityInfo.PropertyName == "CreateOrgId")
                    //{
                    //    entityInfo.SetValue(CurrentUserInfo.OrgId.ToString());
                    //}
                    //if (entityInfo.PropertyName == "CreateOrgName")
                    //{
                    //    entityInfo.SetValue(CurrentUserInfo.OrgName.ToString());
                    //}
                }
                //update生效        
                if (entityInfo.OperationType == DataFilterType.UpdateByObject)
                {
                    //if (entityInfo.PropertyName == "UpdatedTime")
                    //{
                    //    entityInfo.SetValue(DateTimeOffset.Now);//修改UpdateTime字段
                    //}
                    //if (entityInfo.PropertyName == "UpdatedUId")
                    //{
                    //    entityInfo.SetValue(CurrentUserInfo.UId.ToString());//修改UpdateTime字段
                    //}
                    //if (entityInfo.PropertyName == "UpdatedUName")
                    //{
                    //    entityInfo.SetValue(CurrentUserInfo.Name);//修改UpdateTime字段
                    //}
                }
            };
        }
    }
}

 3.4 Startup配置

在MyFurion.Start项目中创建Handlers文件夹,然后创建XnRestfulResultProvider类,自定义接口规范化输出数据格式

using Furion.DataValidation;
using Furion.FriendlyException;
using Furion.UnifyResult;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace MyFurion.Start
{
    /// <summary>
    /// 规范化RESTful风格返回值
    /// </summary>
    [UnifyModel(typeof(XnRestfulResult<>))]
    public class XnRestfulResultProvider : IUnifyResultProvider
    {
        /// <summary>
        /// 异常返回值
        /// </summary>
        /// <param name="context"></param>
        /// <param name="metadata"></param>
        /// <returns></returns>
        public IActionResult OnException(ExceptionContext context, ExceptionMetadata metadata)
        {
            return new JsonResult(new XnRestfulResult<object>
            {
                Code = metadata.StatusCode,
                Success = false,
                Data = null,
                Message = context.Exception.Message,// metadata.Errors,
                //Extras = UnifyContext.Take(),
                //Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            });
        }

        /// <summary>
        /// 成功返回值
        /// </summary>
        /// <param name="context"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public IActionResult OnSucceeded(ActionExecutedContext context, object data)
        {
            return new JsonResult(new XnRestfulResult<object>
            {
                Code = StatusCodes.Status200OK,// context.Result is EmptyResult ? StatusCodes.Status204NoContent : StatusCodes.Status200OK,  // 处理没有返回值情况 204
                Success = true,
                Data = data,
                Message = "请求成功",
                //Extras = UnifyContext.Take(),
                //Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            });
        }

        /// <summary>
        /// 验证失败返回值
        /// </summary>
        /// <param name="context"></param>
        /// <param name="metadata"></param>
        /// <returns></returns>
        public IActionResult OnValidateFailed(ActionExecutingContext context, ValidationMetadata metadata)
        {
            return new JsonResult(new XnRestfulResult<object>
            {
                Code = StatusCodes.Status400BadRequest,
                Success = false,
                Data = null,
                Message = metadata.Message,
                //Extras = UnifyContext.Take(),
                //Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            });
        }

        /// <summary>
        /// 处理输出状态码
        /// </summary>
        /// <param name="context"></param>
        /// <param name="statusCode"></param>
        /// <param name="unifyResultSettings"></param>
        /// <returns></returns>
        public async Task OnResponseStatusCodes(HttpContext context, int statusCode, UnifyResultSettingsOptions unifyResultSettings)
        {
            // 设置响应状态码
            UnifyContext.SetResponseStatusCodes(context, statusCode, unifyResultSettings);

            switch (statusCode)
            {
                // 处理 401 状态码
                case StatusCodes.Status401Unauthorized:
                    await context.Response.WriteAsJsonAsync(new XnRestfulResult<object>
                    {
                        Code = StatusCodes.Status401Unauthorized,
                        Success = false,
                        Data = null,
                        Message = "401 登录已过期,请重新登录",
                        //Extras = UnifyContext.Take(),
                        //Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
                    }, App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
                    break;
                // 处理 403 状态码
                case StatusCodes.Status403Forbidden:
                    await context.Response.WriteAsJsonAsync(new XnRestfulResult<object>
                    {
                        Code = StatusCodes.Status403Forbidden,
                        Success = false,
                        Data = null,
                        Message = "403 禁止访问,没有权限",
                        //Extras = UnifyContext.Take(),
                        //Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
                    }, App.GetOptions<JsonOptions>()?.JsonSerializerOptions);
                    break;
                default:
                    break;
            }
        }
    }

    /// <summary>
    /// RESTful风格---XIAONUO返回格式
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class XnRestfulResult<T>
    {
        /// <summary>
        /// 执行成功
        /// </summary>
        public bool Success { get; set; }
        /// <summary>
        /// 状态码
        /// </summary>
        public int? Code { get; set; }
        /// <summary>
        /// 错误信息
        /// </summary>
        public virtual string Message { get; set; } = String.Empty;
        /// <summary>
        /// 数据
        /// </summary>
        public T? Data { get; set; }
        / <summary>
        / 附加数据
        / </summary>
        //public  object Extras { get; set; }
        / <summary>
        / 时间戳
        / </summary>
        //public long Timestamp { get; set; }
    }
}

在MyFurion.Start项目中创建Startup类,用于Service注册、日志、JSON序列化、Swagger等配置

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace MyFurion.Start
{
    /// <summary>
    /// 
    /// </summary>
    public class Startup:AppStartup
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="services"></param>
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSensitiveDetection();//注册脱敏词汇检测服务
            services.AddControllers().AddNewtonsoftJson();//防止json数据类型转换失败
            services.AddControllers().AddInjectWithUnifyResult<XnRestfulResultProvider>();//规范化输出设置
            services.AddCorsAccessor();//配置跨域                 
            //统一日期类型返回
            services.AddControllersWithViews().AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
            });
            services.Configure<KestrelServerOptions>(options =>
            {
                options.Limits.MaxRequestBodySize = int.MaxValue;
            });
            //设置日志
            Array.ForEach(new[] { LogLevel.Information, LogLevel.Error }, logLevel =>
            {
                services.AddFileLogging("Logs/{1}-{0:yyyy}-{0:MM}-{0:dd}-{0:HH}.log", options =>
                {
                    options.FileNameRule = fileName => string.Format(fileName, DateTime.UtcNow, logLevel.ToString());
                    options.WriteFilter = logMsg => logMsg.LogLevel == logLevel;
                    options.Append = true;
                    //options.MessageFormat = (logMsg) =>
                    //{
                    //    var stringBuilder = new System.Text.StringBuilder();
                    //    stringBuilder.Append(System.DateTime.Now.ToString("o"));
                    //    // 其他的。。。自己组装
                    //    return stringBuilder.ToString();
                    //};
                });
            });
            SqlSugarSetup.AddSqlsugarSetup(services);        
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            //  NGINX 反向代理获取真实IP
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
            });
            app.UseUnifyResultStatusCodes();// 添加状态码拦截中间件 添加规范化结果状态码        
            app.UseHttpsRedirection();// 强制https
            app.UseStaticFiles(); //启用静态文件
            app.UseRouting();
            app.UseCorsAccessor();//跨域中间件
            //开启身份认证
            //app.UseAuthentication();
            //app.UseAuthorization();
            app.UseInject("MyFurion");
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

3.5 Swagger配置

 在项目MyFurion.Model、MyFurion.Application、MyFurion.Start三个项目Debug及Release模式下设置api XML文件输出

以MyFurion.Model为配置示例

然后在Startup中的Configure中添加注册Inject 

app.UseInject("MyFurion");//MyFurion swagger文档的路由前缀

配置项目默认启动页为Swagger

MyFurion.WebApi项目中,Properties/launchSettings.json配置文件中,将launchUrl修改为配置的Swagger路由地址 

 

 

3.6启动配置

MyFurion.WebApi项目 删除Controllers文件夹及WeatherForecast文件,卸载Nuget中对Swagger的引用,添加对项目MyFurion.Start的引用

Program.cs中的代码改为

Serve.Run(RunOptions.Default);

appSettings.json配置文件内容改为

{
  "$schema": "https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information",
      "Microsoft.EntityFrameworkCore": "Information"
    }
  },
  "AllowedHosts": "*",
  /*数据库连接配置
   ConnectionString:连接字符串
   DbType:数据库类型 支持MySql = 0,SqlServer = 1,Sqlite = 2,Oracle = 3,PostgreSQL = 4,Dm = 5,Kdbndp = 6,Oscar = 7,MySqlConnector = 8,Access = 9,OpenGauss = 10,Custom = 900
   ConfigId:租户id
   IsAutoCloseConnection:自动释放和关闭数据库连接,如果有事务事务结束时关闭,否则每次操作后关闭
   AllowLoadLocalInfile:大数据写入是 mysql数据配置必须
  */
  "ConnectionConfigs": [
    {
      "ConnectionString": "Data Source=.;User ID=sa;Password=123456;Initial Catalog=MyFurionTest",
      "DbType": 1,
      "ConfigId": "0",
      "IsAutoCloseConnection": true
    }
  ],
  "AppSettings": {
    "InjectSpecificationDocument": true //如果不需要线上环境开启 Swagger 功能,则设置为false 修改时需要重新发布
  }
}

4.项目使用示例展示

在Furion.Model中创建Org实体对象,用于验证CodeFirst功能

namespace MyFurion.Model
{
    /// <summary>
    /// 组织机构信息
    /// </summary>
    [SugarTable("Sys_Org")]
    [Tenant(0)]
    public class OrgInfo:BaseEntity
    {
        /// <summary>
        /// 机构编码
        /// </summary>
        [SugarColumn(IsNullable =true,ColumnDescription ="机构编码")]
        public string? OrgCode { get; set; }
        /// <summary>
        /// 机构名称
        /// </summary>
        [SugarColumn(IsNullable = true, ColumnDescription = "机构名称")]
        public string? OrgName { get; set; }
    }
}

在MyFurion.Application项目中创建OrgRepository类,用于实现业务代码的仓储类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyFurion.Application
{
    /// <summary>
    /// 机构服务仓储
    /// </summary>
    public class OrgRepository:BaseRepository<OrgInfo>
    {
        //TODO
    }
}

在MyFurion.Application项目中,创建Controller文件夹,存放接口文件

创建FurionTestController

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyFurion.Application.Controller
{
    /// <summary>
    /// furionTest
    /// </summary>
    [ApiDescriptionSettings(Name = "FurionTest", Order = 1)]
    [Route("api/furionTest")]
    public class FurionTestController:IDynamicApiController
    {
        private readonly OrgRepository _orgRepository;
        public FurionTestController(OrgRepository orgRepository)
        {
            _orgRepository = orgRepository;
        }
        /// <summary>
        /// furionTestGet
        /// </summary>
        /// <returns></returns>
        [HttpGet("furionHello")]
        public string GetHello()
        {
            return "Hello Furion";
        }
        /// <summary>
        /// post test
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [HttpPost("testPost")]
        public string TestPost(TestPostData data)
        {
            return "Hello Post";
        }
        /// <summary>
        /// 获取组织机构信息
        /// </summary>
        /// <returns></returns>
        [HttpGet("getOrgList")]
        public async Task<List<OrgInfo>> GetOrgList()
        {
            return await _orgRepository.GetAll();
        }
    }

    public class TestPostData
    {
        public string? DataValue { get; set; }

        public int TestTimes { get; set; }
    }
}

数据库生成结果

 项目启动页

 最终项目架构

 

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

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

相关文章

Java字符串知多少:String、StringBuffer、StringBuilder

一、String 1、简介 String 是 Java 中使用得最频繁的一个类了&#xff0c;不管是作为开发者的业务使用&#xff0c;还是一些系统级别的字符使用&#xff0c; String 都发挥着重要的作用。String 是不可变的、final的&#xff0c;不能被继承&#xff0c;且 Java 在运行时也保…

【C++】哈希表-开散列闭散列

文章目录 哈希概念例子: 哈希冲突哈希函数哈希冲突解决方法1:闭散列 哈希表的闭散列实现闭散列结构设计**哈希表的插入过程:****哈希表的查找过程:**哈希表的删除过程:只能存储key为整形的元素 那其他类型怎么解决 CloseHash.h哈希表的开散列实现开散列概念开散列的最坏情况及解…

车机CarLauncher的Activity多屏模式WindowingMode为WINDOWING_MODE_MULTI_WINDOW疑问解析

hi&#xff0c;粉丝朋友们&#xff01; IntDef(prefix { "WINDOWING_MODE_" }, value {WINDOWING_MODE_UNDEFINED,WINDOWING_MODE_FULLSCREEN,WINDOWING_MODE_MULTI_WINDOW,WINDOWING_MODE_PINNED,WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,WINDOWING_MODE_SPLIT_SCREE…

nacos注册中心源码分析一之服务注册、服务心跳

源码分析 nacos客户端注册分析 依赖包 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>Nacos的客户端是基于SpringBoot的自动装配实现的 看下依…

算法性能分析

一、时间复杂度分析 1.什么是时间复杂度 时间复杂度是一个函数&#xff0c;它定性描述该算法的运行时间。我们在软件开发中&#xff0c;时间复杂度就是用来方便开发者估算出程序运行的答题时间。 那么该如何估计程序运行时间呢&#xff0c;通常会估算算法的操作单元数量来代表…

10个顶级AI艺术生成器

人工智能 (AI) 不仅影响商业和医疗保健等行业。 通过开创人工智能生成艺术的新时代&#xff0c;它还在创意产业中发挥着越来越重要的作用。 人工智能技术和工具通常可供任何人广泛使用&#xff0c;这有助于创造全新一代的艺术家。 我们经常听说人工智能将自动化或接管所有人类…

Java中的正则表达式详解

文章和代码已经归档至【Github仓库&#xff1a;https://github.com/timerring/java-tutorial 】或者【AIShareLab】回复 java 也可获取。 文章目录 正则表达式为什么要学习正则表达式再提出几个问题解决之道-正则表达式正则表达式基本介绍介绍 正则表达式底层实现实例分析 正则…

Word控件Aspose.Words教程:设置图表数据标签的默认选项

Aspose.Words是一种高级Word文档处理API&#xff0c;用于执行各种文档管理和操作任务。API支持生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现和打印文档&#xff0c;而无需在跨平台应用程序中直接使用Microsoft Word。 Aspose API支持流行文件格式处理&#xff0c;并…

新星计划2023【网络应用领域基础】————————Day4

常见的网络基础介绍 前言 我们学习了一些基础的网络协议&#xff0c;以及子网掩码和vlan&#xff0c;同时也做了个简单的单臂路由实验 这篇文章我将仔细的讲解单臂路由的应用和交换机二层接口类型&#xff0c;以及wireshark的教程。 一&#xff0c;交换机二层接口 交换机的二…

Everypixel: AI图片搜索引擎

【产品介绍】 Everypixel是一个基于人工智能的图片搜索引擎。可以搜索超过 50 个图片来源的优质的授权图库版权素材图片&#xff0c;还可以使用免费图案功能&#xff0c;找到适合自己需求的可定制无缝图案。 Everypixel利用深度学习和计算机视觉技术&#xff0c;为客户提供先进…

Taro小程序配置网络请求

目录 1. 创建目录结构2. 全局通用的config的变量配置3. 配置http网络请求4. 使用 1. 创建目录结构 在 src 目录下新建 service 目录&#xff0c;目录下创建 api 和 http 子目录在 src 目录下新建 config 配置文件 2. 全局通用的config的变量配置 在 config 文件中添加一下代…

日本进口Hioki IM3536 LCR测试仪

Hioki IM3536 LCR测试仪 测量频率DC&#xff0c;4Hz~8MHz 测量时间&#xff1a;最快1ms 基本精度&#xff1a;0.05% rdg 1mΩ以上的精度保证范围&#xff0c;也可安心进行低阻测量 可内部发生DC偏压测量 从研发到生产线活跃在各种领域中 测量频率4Hz~8MHz&#xff0c;精度…

【pyq文案】可可爱爱、脑回路清奇の朋友圈文案

1.人每一个身体器官都是无价之宝&#xff0c;全部加起来1个月3000 2.别人出门&#xff1a;辣妹风、复古风、学院风&#xff1b;我出门&#xff1a;打工的勤劳小蜜蜂 3.看见自己就烦&#xff0c;50出&#xff1b;和今天星期四没关系 4.上学时拿钱混日子&#xff0c;上班后拿日…

种子轮、天使轮等相关知识

我们可以通过查询企业的相关工具网站&#xff0c;查看企业是否上市、独角兽、瞪羚企业、上市企业等情况。 转载&#xff1a; https://zhuanlan.zhihu.com/p/565389690 科创板挂牌不属于上市&#xff0c;企业在挂牌之后要经过协会核准后可以进行股份登记挂牌&#xff0c;大概需要…

【Redis】Redis 命令之 Hash

文章目录 ⛄介绍⛄命令⛄RedisTemplate API⛄应用场景 ⛄介绍 Hash类型&#xff0c;也叫散列&#xff0c;其value是一个无序字典&#xff0c;类似于Java中的 HashMap 结构。 String结构是将对象序列化为JSON字符串后存储&#xff0c;当需要修改对象某个字段时很不方便&#xf…

java服务-常用技术-生僻函数、方法、技巧

一、字符串操作 1. 需要转义的字符 java字符串中需要转义的特殊字符1. \n 表示换行&#xff1b;2. \t 表示制表符&#xff0c;相当于Table键&#xff1b;3. \ 表示单引号&#xff1b;4. \" 表示双引号&#xff1b;5. \\ 表示一个斜杠“\”。 2. split第二个参数limit的用…

Dynamics 365 DevOps CI/CD之WebResource

对于D365自身的发布&#xff0c;简单点来说就是Solution的发布&#xff0c;复杂一些会涉及周边集成接口等一系列的发布。如果是单纯的Solution的发布的Azure DevOps商店里有很多工具&#xff0c;比如Power DevOps Tools&#xff0c;这个我之前也有博文转载过相关文章&#xff0…

史上最通俗易懂的EWMA(指数加权移动平均)的参数解释以及程序代码

文章目录 一、EWMA&#xff08;指数加权移动平均&#xff09;是什么&#xff1f;二、详细的参数解释3、使用Python pandas库中的ewm()函数实现指数加权移动平均&#xff08;EWMA&#xff09;的示例代码总结 一、EWMA&#xff08;指数加权移动平均&#xff09;是什么&#xff1f…

抢跑智驾AI芯片「新路径」

“胆量”这个词&#xff0c;被后摩智能创始人兼CEO吴强着重提及。 5月10日&#xff0c;后摩智能发布首款存算一体智驾芯片鸿途™H30&#xff0c;以12nm制程实现最高物理算力 256TOPS&#xff0c;典型功耗 35W&#xff0c;成为国内率先落地存算一体大算力 AI 芯片的公司。即&am…

多线程的最最简单的基本了解

引言&#xff1a; 在学习完常规的语法后&#xff0c;我们将进入下一步的学习&#xff0c;而多线程则是被大多数人认为的下一步的学习目标&#xff0c;因为在有了基础的语法大框架后我们都有了对编程的一个基本的认知&#xff0c;而多线程则是开始有了一定的深度。 一、线程的基…