手動從0搭建ABP框架-ABP官方完整解決方案和手動搭建簡化解決方案實踐

??本文主要講解了如何把ABP官方的在線生成解決方案運行起來,并說明了解決方案中項目間的依賴關系。然后手動實踐了如何從0搭建了一個簡化的解決方案。ABP官方的在線生成解決方案源碼下載參考[3],手動搭建的簡化的解決方案源碼下載參考[4]。

一.ABP官方在線生成解決方案

1.將在線生成解決方案跑起來

首先進入頁面https://abp.io/get-started,然后創建項目:641601958fb9e92b445185bf76143442.png然后頭腦中要有一個項目之間的依賴關系圖,不清楚的可以參考《基于ABP實現DDD》:10d56140f30f46734df0899aa74a88ac.png

截止目前為止,項目使用的.NET版本是6.0,ABP版本是5.3.3。使用Rider打開項目Acme.BookStore后,會提示使用yarn安裝package,安裝包后:2488effbaba436982594cb20a13070c4.png在整個解決方案中搜索ConnectionStrings,發現其在Acme.BookStore.HttpApi.Host、Acme.BookStore.DbMigrator和Acme.BookStore.IdentityServer這3個啟動項目中出現:8329a15ef76ec3dc97e589499f4f36c7.png將ConnectionStrings中的內容替換為:

"ConnectionStrings": {"Default": "Server=127.0.0.1;Database=BookStore;Trusted_Connection=True;User ID=sa;Password=913292836;"},

然后開始運行Acme.BookStore.DbMigrator進行數據種子遷移:e129768a6b67aa1dce45971868bdfcad.png出現上面圖片輸出結果,基本上表示遷移成功完成了,接下來看看數據庫:096591ae543856d7be0a8df1d2db1abd.png運行Acme.BookStore.Web項目如下:

d3c9d5dd96e40343ff8e5458c712bc13.png啟動后發現報錯了,發現主要是3個問題:一個是Redis沒有啟動,另一個問題是IDS4服務沒有啟動,最后一個問題是Acme.BookStore.HttpApi.Host沒有啟動a3f9d8fa8e17a8c93b9976cc4a5574d3.png啟動IDS4服務的時候發現報錯Volo.Abp.AbpException: Could not find the bundle file '/libs/abp/core/abp.css' for the bundle 'Basic.Global'!

328b0832a5d33505076e81ef9761b4c0.png在該項目下執行命令abp install-libs:622f2c9e13c12669dd507d1d0c563e0d.png發現消息提示說ABP CLI有個更新的5.3.3版本,通過命令dotnet tool update -g Volo.Abp.Cli進行升級。再次運行Acme.BookStore.IdentityServer項目,發現不報錯誤了。如果在啟動其它項目(特指Acme.BookStore.Web項目)的時候報同樣的錯誤,那么同樣執行命令abp install-libs即可解決問題。同時啟動這3個項目如下:b1301539fd914390e350c9d7819a2156.png啟動成功后就可以見到熟悉的界面:16bea4028d1f36010fb151f05c7983bd.png下面是項目Swagger的界面:07c6ae7fa3ac947aa3144dd49a3fd93e.png至此,已經把從官方下載下來的項目成功地運行起來了。

2.ABP運行流程

下面是在網上[1]找到的一張圖,很清晰的說明了AspNet Core和ABP模塊的運行流程,個人認為圖上的Startup.ConfigureServices應該是Startup.Configure,已經在圖中做了修改。bae0c78b5322f37061cb172244751669.png(1)AspNet Core運行流程
簡單理解,基本上就是在Startup.ConfigureServices中進行依賴注入配置,然后在Startup.Configure中配置管道中間件,訪問的時候就像洋蔥模型。
(2)ABP模塊運行流程

  • 在ABP模塊中對Startup.ConfigureServices做了擴展,增加了PreConfigureServices和PostConfigureServices。對Startup.Configure也做了擴展,當然名字也修改了,Startup.Configure相當于是OnApplicationInitialization,同時增加了OnPreApplicationInitialization和OnPostApplicationInitialization。

  • 在ABP解決方案中有多個項目,每個項目都會有一個類繼承自AbpModule。并且通過DependsOn描述了該模塊依賴的模塊。這樣在ABP解決方案中就會有很多模塊之間的依賴關系,通過拓撲排序算法對模塊進行排序,從最深層的模塊依次加載,直到啟動所有模塊。

(3)AbpModule抽象類中的方法 除了主要的PreConfigureServices()、ConfigureServices()、PostConfigureServices()、OnPreApplicationInitialization()、OnApplicationInitialization()、OnPostApplicationInitialization()方法外,還有一些其它的方法。abp\framework\src\Volo.Abp.Core\Volo\Abp\Modularity\AbpModule.csbbe263895181fb6c66ebf972fc7cb0ff.png

二.手動創建解決方案

0.創建解決方案

首先創建一個目錄BookStoreHand用于存放解決方案:64f3ecb631c6ca754f6271f0b2d8e7cc.png然后創建一個解決方案,執行命令dotnet new sln -n Acme.BookStore:008839531c84b2431dc32c7aa1060a54.png用Rider打開后解決方案是空的,然后手動創建2個New Solution Folder,分別為src和test:1267e211cdea17ce185fb06e9e0dc229.png

1.創建領域共享層和領域層

(1)Acme.BookStore.Domain.Shared[領域共享層]
通常定義的常量和枚舉,都放在該項目中。通過命令dotnet new classlib -n Acme.BookStore.Domain.Shareddotnet sln ../Acme.BookStore.sln add Acme.BookStore.Domain.Shared創建領域共享層,并將其添加到解決方案當中:07cb75c3781edd7c3d01444ed7a3e5d4.png然后就是創建模塊類BookStoreDomainSharedModule如下:

namespace Acme.BookStore.Domain.Shared
{public class BookStoreDomainSharedModule: AbpModule{public override void ConfigureServices(ServiceConfigurationContext context){base.ConfigureServices(context);}public override void OnApplicationInitialization(ApplicationInitializationContext context){base.OnApplicationInitialization(context);}}
}

說明:接下來創建項目、添加項目間的引用等都使用Rider,而不再使用CLI操作,覺得CLI并不方便操作。基本思路順序都是:創建項目,設置引用關系,創建模塊,其它操作。
(2)Acme.BookStore.Domain[領域層]
該項目包含實體、值對象、領域服務、規約、倉儲接口等。通過Rider創建Class Library項目Acme.BookStore.Domain如下:2de65424c708e9c68bc9f1b333f477b6.pngAcme.BookStore.Domain項目依賴于Acme.BookStore.Domain.Shared項目:954cd186a2aee83d382051a01aa5819b.png創建模塊類BookStoreDomainSharedModule如下:

[DependsOn(typeof(BookStoreDomainSharedModule) //依賴領域共享模塊
)]
public class BookStoreDomainModule: AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){base.ConfigureServices(context);}public override void OnApplicationInitialization(ApplicationInitializationContext context){base.OnApplicationInitialization(context);}
}

創建領域實體Book:

public class Book: Entity<int>
{public string BookName { get; set; } //名字public string Author { get; set; } //作者public DateTime PublishDate { get; set; } //出版日期public double Price { get; set; } //價格
}

創建倉儲IBookRepository接口:

public interface IBookRepository: IRepository<Book, int>
{
}

2.創建基礎設施層

(1)創建項目
基礎設施層Acme.BookStore.EntityFrameworkCore是EF Core核心基礎依賴項目,包含數據上下文、數據庫映射、EF Core倉儲實現等。通過Rider創建Class Library項目Acme.BookStore.EntityFrameworkCore如下:3b54a509f7291a211862c1ff919a99aa.pngAcme.BookStore.EntityFrameworkCore項目依賴于Acme.BookStore.Domain項目:f5fe3083d0caa0ca1cdbd8fdf5301bf5.png(2)創建模塊
創建模塊類BookStoreEntityFrameworkCoreModule如下:

[DependsOn(typeof(BookStoreDomainModule),typeof(AbpEntityFrameworkCoreSqlServerModule)
)]
public class BookStoreEntityFrameworkCoreModule: AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){context.Services.AddAbpDbContext<BookStoreDbContext>(options =>{// 給所有的實體都增加默認倉儲options.AddDefaultRepositories(includeAllEntities: true);});Configure<AbpDbContextOptions>(options =>{options.UseSqlServer();});}public override void OnApplicationInitialization(ApplicationInitializationContext context){base.OnApplicationInitialization(context);}
}

(3)創建數據庫上下文
創建數據庫上下文BookStoreDbContext:

public class BookStoreDbContext: AbpDbContext<BookStoreDbContext>
{public BookStoreDbContext(DbContextOptions<BookStoreDbContext> options) : base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.ApplyConfigurationsFromAssembly(typeof(BookStoreDbContext).Assembly);}
}

ApplyConfigurationsFromAssembly應用來自IEntityTypeConfiguration中的配置。定義實體映射BookDbMapping如下:

public class BookDbMapping: IEntityTypeConfiguration<Book>
{public void Configure(EntityTypeBuilder<Book> builder){// 配置主鍵builder.HasKey(b => b.Id).HasName("Id");// 配置表和字段builder.ToTable("AbpBook");builder.Property(t => t.BookName).IsRequired().HasColumnName("BookName").HasComment("書名");builder.Property(t => t.Author).IsRequired().HasColumnName("Author").HasComment("作者");builder.Property(t => t.PublishDate).IsRequired().HasColumnName("PublishDate").HasComment("出版日期");builder.Property(t => t.Price).IsRequired().HasColumnName("Price").HasComment("價格");// 配置關系}
}

(4)創建倉儲實現 定義IBookRepository的實現BookRepository如下:

public class BookRepository: EfCoreRepository<BookStoreDbContext, Book, int>, IBookRepository
{public BookRepository(IDbContextProvider<BookStoreDbContext> dbContextProvider) : base(dbContextProvider){}
}

3.創建應用契約層和應用層

(1)Acme.BookStore.Application.Contracts[應用契約層]
包含應用服務接口和數據傳輸對象。該項?被應?程序客戶端引用,比如Web項目、API客戶端項目。通過Rider創建Class Library項目Acme.BookStore.Application.Contracts:71065766413483f9d71eb14fda2d4b42.pngAcme.BookStore.Application.Contracts項目依賴于Acme.BookStore.Domain.Shared項目如下:f28797ccabeab715d4b11907621860e3.png創建模塊類BookStoreApplicationContractsModule如下:

[DependsOn(typeof(BookStoreDomainSharedModule), //依賴于BookStoreDomainSharedModuletypeof(AbpObjectExtendingModule) //依賴于AbpObjectExtendingModule
)]
public class BookStoreApplicationContractsModule: AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){base.ConfigureServices(context);}public override void OnApplicationInitialization(ApplicationInitializationContext context){base.OnApplicationInitialization(context);}
}

創建服務接口IBookAppService如下:

public interface IBookAppService: IApplicationService
{/// <summary>/// 獲取書籍/// </summary>Task<BookDto> GetBookAsync(int id);
}

創建輸出DTO為BookDto如下:

public class BookDto
{public int Id { get; set; } //主鍵public string BookName { get; set; } //名字public string Author { get; set; } //作者public DateTime PublishDate { get; set; } //出版日期public double Price { get; set; } //價格
}

(2)Acme.BookStore.Application[應用層]
實現在Contracts項目中定義的接?。通過Rider創建Class Library項目Acme.BookStore.Application如下:b22a4a57a7bac22cd8b5d33b4fd9e9de.pngAcme.BookStore.Application項目依賴于 Acme.BookStore.Application.Contracts和Acme.BookStore.Domain項目:6eb38f96ddf4a9dbfb53d6a1537daf04.png創建模塊類BookStoreApplicationModule如下:

[DependsOn(typeof(AbpAutoMapperModule), //依賴于AutoMappertypeof(BookStoreDomainModule), //依賴于BookStoreDomainModuletypeof(BookStoreApplicationContractsModule) //依賴于BookStoreApplicationContractsModule
)]
public class BookStoreApplicationModule: AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){var services = context.Services;// 添加ObjectMapper注入services.AddAutoMapperObjectMapper<BookStoreApplicationModule>();// Abp AutoMapper設置Configure<AbpAutoMapperOptions>(config =>{config.AddMaps<BookStoreApplicationAutoMapperProfile>();});}public override void OnApplicationInitialization(ApplicationInitializationContext context){base.OnApplicationInitialization(context);}
}

創建自動映類BookStoreApplicationAutoMapperProfile如下:

public class BookStoreApplicationAutoMapperProfile: Profile
{public BookStoreApplicationAutoMapperProfile(){CreateMap<BookDto, Book>();CreateMap<Book, BookDto>();}
}

創建IBookAppService類的實現類BookAppService如下:

public class BookAppService: ApplicationService, IBookAppService
{private readonly IBookRepository _bookRepository;public BookAppService(IBookRepository bookRepository){_bookRepository = bookRepository;}public async Task<BookDto> GetBookAsync(int id){var queryable = await _bookRepository.GetQueryableAsync();var book = queryable.FirstOrDefault(t => t.Id == id);if (book == null){throw new ArgumentNullException(nameof(book));}return ObjectMapper.Map<Book, BookDto>(book);}
}

4.創建種子遷移

Acme.BookStore.DbMigrator是控制臺應用程序,主要是遷移數據庫結構并初始化種子數據。通過Rider創建ASP.NET Core Web Application的Empty項目Acme.BookStore.DbMigrator如下:834b5a2608866a48590fa487c4853714.pngAcme.BookStore.DbMigrator項目依賴于Acme.BookStore.Application.Contracts和Acme.BookStore.EntityFrameworkCore項目如下:6edd65e9e04fc94640d67f35e3f21a05.png創建模塊類BookStoreDbMigratorModule如下:

[DependsOn(typeof(AbpAutofacModule),typeof(BookStoreEntityFrameworkCoreModule),typeof(BookStoreApplicationContractsModule))]
public class BookStoreDbMigratorModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){base.ConfigureServices(context);}public override void OnApplicationInitialization(ApplicationInitializationContext context){base.OnApplicationInitialization(context);}
}

在Program.cs中添加services.AddHostedService()這個數據庫遷移主機服務,在DbMigratorHostedService類中包含StartAsync()和StopAsync()這2個方法,在StartAsync()中獲取BookStore數據庫遷移服務BookStoreDbMigrationService,并執行數據庫遷移方法MigrateAsync()。數據庫遷移的思路基本上就是在Acme.BookStore.DbMigrator目錄下執行命令:dotnet ef migrations add InitialCreate和dotnet ef database update,只不過使用的C#代碼來實現的。自己通過Acme.BookStore.DbMigrator項目沒有遷移成功,最后還是通過命令行實現遷移的。遷移結果如下:
6aa2e7103dd90805b78ecce15d3ac14d.png說明:Program.cs、DbMigratorHostedService.cs和BookStoreDbMigrationService.cs的源碼等完整項目源碼參考[4]。

5.創建遠程服務層

Acme.BookStore.HttpApi[遠程服務層],簡單理解就是很薄的控制層,該項目主要用于定義HTTP API,即應用服務層的包裝器,將它們公開給遠程客戶端調用。通過Rider創建Class Library項目Acme.BookStore.HttpApi如下:
6def3dcd6ee89230465e0de5a4214e61.pngAcme.BookStore.HttpApi項目依賴于Acme.BookStore.Application.Contracts項目如下:5b43eca762af5f3a9e34d32c99bbe757.png創建模塊類BookStoreHttpApiModule如下:

[DependsOn(typeof(BookStoreApplicationContractsModule) //依賴于BookStoreApplicationContractsModule
)]
public class BookStoreHttpApiModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){base.ConfigureServices(context);}public override void OnApplicationInitialization(ApplicationInitializationContext context){base.OnApplicationInitialization(context);}
}

為了簡要說明問題,創建一個簡單的控制器類BookStoreController如下:

[RemoteService]
[Area("BookStore")]
[Route("api/app/book")]
public class BookStoreController: AbpControllerBase
{private readonly IBookAppService _bookAppService;public BookStoreController(IBookAppService bookAppService){_bookAppService = bookAppService;}[HttpGet][Route("get-book")]public Task<BookDto> GetBookAsync(int id){return _bookAppService.GetBookAsync(id);}
}

6.創建展示層

Acme.BookStore.HttpApi.Host這個是前后端分離時的項目命名方式。通過Rider創建ASP.NET Core Web Application的Empty項目Acme.BookStore.HttpApi.Host如下:49904e4fc9fd1d1ce9546c0207356394.pngAcme.BookStore.HttpApi.Host項目依賴于Acme.BookStore.Application、Acme.BookStore.EntityFrameworkCore和Acme.BookStore.HttpApi項目如下:e2cc1acd931d70d89d298e61dfb3711c.png創建模塊類BookStoreHttpApiHostModule如下:

[DependsOn(typeof(BookStoreHttpApiModule), //依賴于BookStoreHttpApiModuletypeof(AbpAutofacModule), //依賴于AbpAutofacModuletypeof(BookStoreApplicationModule), //依賴于BookStoreApplicationModuletypeof(BookStoreEntityFrameworkCoreModule), //依賴于BookStoreEntityFrameworkCoreModuletypeof(AbpAspNetCoreSerilogModule), //依賴于AbpAspNetCoreSerilogModuletypeof(AbpSwashbuckleModule) //依賴于AbpSwashbuckleModule
)]
public class BookStoreHttpApiHostModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){var services = context.Services;var configuration = services.GetConfiguration();ConfigureConventionalControllers();ConfigureCors(context, configuration);ConfigureSwaggerServices(context, configuration);}private void ConfigureConventionalControllers(){Configure<AbpAspNetCoreMvcOptions>(options =>{options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly);});}private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration){context.Services.AddCors(options =>{options.AddPolicy("AllowAll",builder =>{builder.WithOrigins(configuration["App:CorsOrigins"].Split(",", StringSplitOptions.RemoveEmptyEntries).Select(o => o.RemovePostFix("/")).ToArray()).WithAbpExposedHeaders().SetIsOriginAllowedToAllowWildcardSubdomains().AllowAnyHeader().AllowAnyMethod().AllowCredentials();});});}private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration){context.Services.AddSwaggerGen(options =>{options.SwaggerDoc("v1", new OpenApiInfo { Title = "BookStore API", Version = "v1" });options.DocInclusionPredicate((docName, description) => true);options.CustomSchemaIds(type => type.FullName);});}public override void OnApplicationInitialization(ApplicationInitializationContext context){var env = context.GetEnvironment();var app = context.GetApplicationBuilder();var configuration = context.GetConfiguration();if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseCors("AllowAll");if (configuration["UseSwagger"] == "true"){app.UseSwagger();app.UseSwaggerUI(options =>{options.SwaggerEndpoint("/swagger/v1/swagger.json", "Acme.BookStore API");});}app.UseRouting();app.UseConfiguredEndpoints();}
}

說明:HomeController.cs、Program.cs和配置文件等項目完整源碼參考[4]。
將Acme.BookStore.HttpApi.Host項目啟動起來后如下:0734e1b037ac943fbac4445ec3d205ba.png通過Swagger界面測試https://localhost:7016/api/app/book/get-book?id=1接口如下:61c8203185136a367e2df1d040f219a9.png

??奇怪的是在線生成解決方案的時候,UI框架選擇了MVC,但是還是出現了這個項目,并且在啟動Acme.BookStore.Web項目的時候,如果不啟動Acme.BookStore.HttpApi.Host項目,還會報錯Volo.Abp.AbpException: Remote service 'AbpMvcClient' was not found and there is no default configuration,并且還沒有找到Acme.BookStore.Web項目在哪里用到了Acme.BookStore.HttpApi.Host項目。因為自己主要關注前后端分離的項目,所以就不糾結這個細節了。
??在線生成解決方案中還包括:Acme.BookStore.IdentityServer(認證授權項目),Acme.BookStore.HttpApi.Client(遠程服務代理層),Acme.BookStore.Web(前后端不分離的展示層),Acme.BookStore.TestBase(其它項目共享或使用的類),Acme.BookStore.Domain.Tests(測試領域層對象),Acme.BookStore.EntityFrameworkCore.Tests(測試自定義倉儲實現或EF Core映射),Acme.BookStore.Application.Tests(測試應用層對象),Acme.BookStore.HttpApi.Client.ConsoleTestApp(從.NET控制臺中調用HTTP API)等。一篇文章放不下,后面繼續解說實踐。

參考文獻:
[1]聊一聊ABP vNext的模塊化系統:https://www.sohu.com/a/436373048_468635
[2]Abp vNext源碼分析文章目錄:https://www.cnblogs.com/myzony/p/10722506.html
[3]手動從0搭建ABP框架-ABP官方完整解決方案源碼:https://url39.ctfile.com/f/2501739-625678611-787336?p=2096 (訪問密碼: 2096)
[4]手動從0搭建ABP框架-手動搭建簡化解決方案源碼:https://url39.ctfile.com/f/2501739-625678627-091eb9?p=2096 (訪問密碼: 2096)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284321.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284321.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284321.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java捕獲并處理線程失敗拋出的異常

使用 UncaughtExceptionHandler 示例代碼如下&#xff1a; Thread.UncaughtExceptionHandler handler new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread th, Throwable ex) {System.out.println("Uncaught exception: " ex);} }; Th…

【ArcGIS微課1000例】0044:ArcGIS使用山體陰影顯示DEM的3種方法

本文講解了ArcGIS使用山體陰影顯示DEM的3種方法:“影像分析”窗口、使用山體陰影效果和山體陰影效果工具的不同之處。 文章目錄 一、“影像分析”窗口二、使用山體陰影效果三、山體陰影工具一、“影像分析”窗口 使用山體陰影顯示 DEM 的方法有兩種。最簡單并且最具交互效果的…

區塊鏈每日投資指南(0129)-證監會副主席表示數字貨幣需要監管

上一周的走勢依然是工作日下跌&#xff0c;周末拉升的結局。這主要原因依然是&#xff0c;周末不上班。最終政策出爐之前&#xff0c;市場恐怕還將繼續震蕩。下周的工作日恐怕會重演下跌的節奏。但是經過了17號&#xff0c;23號&#xff0c;26號三次筑底來看&#xff0c;如果政…

藍綠發布、滾動發布、灰度發布,有什么區別?

在項目迭代的過程中&#xff0c;不可避免需要”上線“。上線對應著部署&#xff0c;或者重新部署&#xff1b;部署對應著修改&#xff1b;修改則意味著風險。目前有很多部署發布的技術, 這兒將常見的做一個總結。 上面所說難免有些抽象, 舉一個情景例子, 加入你是微博項目負責…

iOS 音頻開發

音頻基礎知識 組成 音頻文件的組成&#xff1a;文件格式(或者音頻容器) 數據格式(或者音頻編碼)。 文件格式(或音頻容器)是用于形容文件本身的格式。 我們可以通過多種不同的方法為真正的音頻數據編碼。例如CAF文件便是一種文件格式&#xff0c;它能夠包含MP3格式&#xff0c;…

【ArcGIS微課1000例】0045:ArcGIS制圖模板的自定義與使用方法

怎樣在ArcGIS中保存地圖模板以在地圖制圖與打印之前使用呢? 文章目錄 一、地圖模板簡介二、地圖模板創建1. 創建模板2. 創建縮略圖3. 保存模板三、地圖模板使用一、地圖模板簡介 使用ArcMap打開一個已有的地圖模板,【文件】→【新建】,任選一個模板,這里選擇一個傳統模板。…

api 接口開發理論 在php中調用接口以及編寫接口

如&#xff1a;http://localhost/openUser.php?actget_user_list&typejson 在這里openUser.php相當于一個接口&#xff0c;其中get_user_list 是一個API&#xff08;獲取用戶列表&#xff09;&#xff0c;講求返回的數據類型為JSON格式。 你只需要在你PHP代碼中執行這條鏈…

怎么樣的框架對于開發者是友好的?

云原生離.NET開發到底有多遠&#xff1f;云原生的概念由來不久&#xff0c;故事從“上云”開始&#xff0c;伴隨dorker、k8s等技術的推出&#xff0c;以及CNCF與各大云廠商的共同加持&#xff0c;云原生逐漸被大家所熟知。云原生不依賴具體的云&#xff0c;不管公有云還是私有云…

JS 燒腦面試題大賞

本文精選了20多道具有一定迷惑性的js題&#xff0c;主要考察的是類型判斷、作用域、this指向、原型、事件循環等知識點&#xff0c;每道題都配有詳細傻瓜式的解析&#xff0c;偏向于初學者&#xff0c;大佬請隨意。 第1題 let a 1 function b(a) {a 2console.log(a) } b(a)…

蘋果ios用js的Date()出現NaN問題解決辦法

原文:蘋果ios用js的Date&#xff08;&#xff09;出現NaN問題解決辦法ios使用如下方法獲得NaN&#xff0c;安卓手機則是正常計算&#xff0c;解決方法是換個這個時間的格式 new Date("2017-04-28 23:59:59").getTime() 換成如下方式就正常了&#xff0c;就是‘-’換成…

Thinkphp 驗證碼、文件上傳

一、驗證碼 驗證碼參數 例題&#xff1a;登錄時驗證下驗證碼 LoginController.class.php <?php namespace Home\Controller; use Think\Controller; class LoginController extends Controller {public function Login(){if(empty($_POST)){$this->display(); } e…

ArcGIS實驗教程——實驗四十七:數據驅動頁工具批量制作甘肅省各地級市人口七普專題圖集

本實驗詳細講解利用ArcGIS數據驅動頁工具,制作甘肅省各地級市人口七普專題圖集。 文章目錄 1. 數據驅動頁工具簡介2. 甘肅省各地級市人口七普專題圖集2.1 符號化及標注2.2 數據驅動頁的創建2.3 數據驅動頁面文本操作2.4 數據驅動頁的導出1. 數據驅動頁工具簡介 數據驅動頁面是…

為什么Java有GC調優而沒聽說過有CLR的GC調優?

前言在很多的場合我都遇到過一些群友提這樣的一些問題&#xff1a;為什么Java有GC調優而CLR沒有聽說過有GC調優呢&#xff1f;到底是Java的JVM GC比較強還是C#使用的.NET CLR的GC比較強呢&#xff1f;其實業內已經有幾位大佬的高贊文章和大家分享一下&#xff0c;主要討論JVM和…

Ubuntu16.04 - 安裝RabbitVCS,linux下的TortoiseSVN!!!

RabbitVCS 官網&#xff1a;http://rabbitvcs.org/ 1&#xff0c;添加PPA源。在shell里面執行下面命令&#xff1a; sudo add-apt-repository ppa:rabbitvcs/ppa 這個命令執行完畢后&#xff0c;查看執行結果看是否密鑰導入成功&#xff0c;成功截圖&#xff1a; 如果導入密鑰失…

8 種最坑的SQL錯誤用法

1、LIMIT 語句 2、隱式轉換 3、關聯更新、刪除 4、混合排序 5、EXISTS語句 6、條件下推 7、提前縮小范圍 8、中間結果集下推 總結 sql語句的執行順序&#xff1a; FROM <left_table>ON <join_condition><join_type>JOIN <right_table>WHERE &…

Vue根據菜單json數據動態按需加載路由Vue-router

每個菜單項對應一個頁面組件&#xff0c;根據菜單項動態按需加載路由 路由配置的正確寫法&#xff1a; /*router/index.js*/ import Vue from vue import Router from vue-router import url from ./url import store from ../storeVue.use(Router)const router new Router({/…

【ArcGIS微課1000例】0047:制圖表達(2)---河流漸變效果的實現

當我們在ArcMap中加載河流數據時,得到的效果往往如圖所示,僅僅是表示河流位置的線要素,既無法真實地反映河流的實際情況,同時在出圖的時候也遠沒有任何美化效果。 文章目錄 1.創建制圖表達2.添加幾何效果3.使用制圖規則4.使用制圖表達屬性覆蓋警告:這些操作會對您的數據庫…

操作系統思考 第二章 進程

第二章 進程 作者&#xff1a;Allen B. Downey 原文&#xff1a;Chapter 2 Processes 譯者&#xff1a;飛龍 協議&#xff1a;CC BY-NC-SA 4.0 2.1 抽象和虛擬化 在我們談論進程之前&#xff0c;我打算先定義幾個東西&#xff1a; 抽象&#xff08;Abstraction&#xff09;&…

1 句代碼,搞定 ASP.NET Core 綁定多個源到同一個類

問題有群友希望將路由中的信息綁定到一個Dto對象中&#xff1a;public class DDDDDto {[FromRoute(Name "collectionId")]public Guid collectionId { get; set; }[BindProperty(Name "relativeUrl")]public string relativeUrl { get; set; } }這樣就不用…

redux中間件的用法

1.定義 中間件就是一個函數&#xff0c;對store.dispatch方法進行了改造&#xff0c;在發出 Action 和執行 Reducer 這兩步之間&#xff0c;添加了其他功能。 2.舉例 日志中間件 import { applyMiddleware, createStore } from redux; import createLogger from redux-logger; …