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

目录

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; }
    }
}

数据库生成结果

 项目启动页

 最终项目架构

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JDK源码阅读环境搭建

本次针对jdk8u版本的搭建 1.新建项目 新建java项目JavaSourceLearn &#xff0c;这里我创建的是maven 2.获取JDK源码 打开Project Structure 找到本地JDK安装位置将src.zip解压到项目java包中 整理下项目结构&#xff0c;删除用不到的目录 提示: 添加源码到项目之后首次运行…

从零玩转设计模式之原型模式-yuanxingmoshi

title: 从零玩转设计模式之原型模式 date: 2022-12-11 20:05:35.488 updated: 2022-12-23 15:35:44.159 url: https://www.yby6.com/archives/yuanxingmoshi categories: - 设计模式 tags: - 设计模式 - 原型模式 什么是原型模式设计模式? 原型模式是一种软件设计模式&#…

公司招了一个00后,以为是个小年轻,没想到人家是个卷王...

公司前段缺人&#xff0c;也面了不少测试&#xff0c;结果竟然没有一个合适的。一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资也不低&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。 令我印象最深的是一个00后测试员&#xff0c;…

【Linux高级 I/O(2)】如何使用阻塞 I/O 与非阻塞 I/O?——select()函数

上次我们虽然使用非阻塞式 I/O 解决了阻塞式 I/O 情况下并发读取文件所出现的问题&#xff0c;但依然不够完美&#xff0c;使得程序的 CPU 占用率特别高。解决这个问题&#xff0c;就要用到本文将要介绍的 I/O 多路复用方法。 何为 I/O 多路复用 I/O 多路复用&#xff08;IO m…

AI 将完全取代前端开发吗?

注&#xff1a;今晨&#xff0c;我浏览 Medium&#xff0c;看到了篇颇为标题党的文章&#xff0c;于是我就将它抛给了 ChatGPT。本篇文章全部由 ChatGPT 所写。同时&#xff0c;我也请 ChatGPT 分享了它对此的观点。 最近&#xff0c;我的同事向我讲述了他与他老板的一次谈话。…

Python机器学习:Scikit-learn和TensorFlow的应用和模型设计

一、引言 Python在机器学习领域中已经成为非常受欢迎的编程语言。Scikit-learn和TensorFlow是Python中应用最广泛的两个机器学习库&#xff0c;它们提供了丰富的机器学习算法和工具&#xff0c;帮助开发人员轻松地构建和训练机器学习模型。本文将详细介绍Scikit-learn和Tensor…

功率放大器的选型原则和方法是什么

功率放大器是一种能够将低电平信号放大到足够高的电平以驱动负载的电子器件。在各种电子设备中&#xff0c;功率放大器被广泛应用&#xff0c;如音响系统、电视广播、汽车音响、射频通信等。因此&#xff0c;正确选型功率放大器非常重要&#xff0c;可以提高设备的性能和可靠性…

如何在linux中配置JDK环境变量

在linux系统部署皕杰报表&#xff0c;因皕杰报表是一款纯java报表工具&#xff0c;运行时需要jre环境&#xff0c;所以要在服务器上配置三个jdk环境变量path、classpath、JAVA_HOME。 那么为什么要配置jdk环境变量呢&#xff1f;因为java软件运行时要用到一些java命令&#xff…

Python挑选出无Labelme标注文件的图片文件

Python挑选出无Labelme标注文件的图片文件 前言前提条件相关介绍实验环境Python挑选出无Labelme标注文件的图片文件代码实现输出结果 前言 本文是个人使用Python处理文件的电子笔记&#xff0c;由于水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。 (https://blog.…

JAVA常用API - Runtime和System

文章目录 前言 大家好,我是最爱吃兽奶,今天给大家带来JAVA常用API中的Runtime类和System类 那么就让我们一起去看看吧! 一、Rubtime 1.Rubtime是什么? 2.Runtime常用方法 Runtime提供了很多方法,在这里演示两个 public static Runtime getRuntime(): 返回当前运行时环境的…

Ada 语言学习(3)复合类型数据——Array

文章目录 Array数据类型声明数组索引数组范围数组复制数组初始化直接赋值通过拷贝赋值不同索引范围但长度相等非指定类型边界收缩 多维数组数组遍历数组切片访问和动态检查直接访问动态检查 数组字面量 Array literal数组拼接两个数组拼接数组和单个值拼接 Array Equality&…

SpringBoot【开发实用篇】---- 整合第三方技术(消息)

SpringBoot【开发实用篇】---- 整合第三方技术&#xff08;消息&#xff09; 消息的概念Java处理消息的标准规范JMSAMQPMQTTKafka 购物订单发送手机短信案例订单业务短息处理业务 SpringBoot整合ActiveMQ安装整合 SpringBoot整合RabbitMQ安装整合&#xff08;direct模型&#x…

加密解密软件VMProtect教程(六):主窗口之控制面板“项目”部分(2)

VMProtect 是新一代软件保护实用程序。VMProtect支持德尔菲、Borland C Builder、Visual C/C、Visual Basic&#xff08;本机&#xff09;、Virtual Pascal和XCode编译器。 同时&#xff0c;VMProtect有一个内置的反汇编程序&#xff0c;可以与Windows和Mac OS X可执行文件一起…

solidworks2020及麦迪工具箱安装

1、麦迪工具箱安装 1&#xff09;下载 下载链接&#xff1a;www.maidiyun.com/download 下载今日制造 2&#xff09;安装 由于电脑上安装了杀毒软件&#xff0c;会直接删除解压后的安装包&#xff0c;因此需要关闭杀毒软件或者在被删除后进入杀毒软件的隔离区将该文件添加…

Tomcat安装与使用

Tomcat 是HTTP服务器&#xff0c;用于使用HTTP协议。 1、下载Tomcat 下载链接&#xff1a;https://tomcat.apache.org/ 进入官网后&#xff0c;根据自己想要下载的版本进行下载&#xff0c;我这里选择下载的版本是Tomcat 8. 点击选择自己想要下载的对应版本&#xff0c;下载Z…

Netty入门

Netty入门 1. 概述 1.1 Netty是什么&#xff1f; Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients.以上片段摘自官网&#xff0c;Netty 是一个异步的、基于事…

三十六、链路追踪、配置中心

1、链路追踪 在一次调用链路中&#xff0c;可能设计到多个微服务&#xff0c;如果在线上&#xff0c;某个微服务出现故障&#xff0c;如何快速定位故障所在额微服务呢。 可以使用链路追踪技术 1.1链路追踪介绍 在大型系统的微服务化构建中&#xff0c;一个系统被拆分成了许多微…

chatgpt赋能Python-python3_排序

Python3 排序指南&#xff1a;介绍、说明和实践 Python3是当今最受欢迎的编程语言之一&#xff0c;拥有许多可用于各种任务的库和框架。其中之一是它自带的排序函数&#xff0c;在数据分析和机器学习等领域中非常有用。 在本篇文章中&#xff0c;我们将简要介绍Python3的排序和…

基于AT89C51单片机的贪吃蛇游戏设计

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87778030 源码获取 主要内容: 设计一个贪吃蛇游戏,使其具有以下游戏规则:①当没有改变方向时,贪吃蛇沿原来路径一直前进②贪吃蛇无法回头,只能异于当前方向改变行动③蛇…

第7章链接:如何动态连接共享库、从应用程序中加载和链接共享库

文章目录 7.10 动态链接共享库静态库的缺点何为共享库共享库的"共享"的含义动态链接过程 7.11 从应用程序中加载和链接共享库运行时动态加载和连接共享库的接口 dlopen函数 dlsym函数 dlclose函数 dlerror动态加载和链接共享库的应用程序示例 7.12 *与位置无关的代码…