本文主要讲解了如何把ABP官方的在线生成解决方案运行起来,并说明了解决方案中项目间的依赖关系。然后手动实践了如何从0搭建了一个简化的解决方案。ABP官方的在线生成解决方案源码下载参考[3],手动搭建的简化的解决方案源码下载参考[4]。

一.ABP官方在线生成解决方案

1.将在线生成解决方案跑起来

首先进入页面https://abp.io/get-started,然后创建项目:



然后头脑中要有一个项目之间的依赖关系图,不清楚的可以参考《基于ABP实现DDD》:

截止目前为止,项目使用的.NET版本是6.0,ABP版本是5.3.3。

使用Rider打开项目Acme.BookStore后,会提示使用yarn安装package,安装包后:



在整个解决方案中搜索ConnectionStrings,发现其在Acme.BookStore.HttpApi.Host、Acme.BookStore.DbMigrator和Acme.BookStore.IdentityServer这3个启动项目中出现:



将ConnectionStrings中的内容替换为:

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

然后开始运行Acme.BookStore.DbMigrator进行数据种子迁移:



出现上面图片输出结果,基本上表示迁移成功完成了,接下来看看数据库:



运行Acme.BookStore.Web项目如下:



启动后发现报错了,发现主要是3个问题:一个是Redis没有启动,另一个问题是IDS4服务没有启动,最后一个问题是Acme.BookStore.HttpApi.Host没有启动



启动IDS4服务的时候发现报错Volo.Abp.AbpException: Could not find the bundle file '/libs/abp/core/abp.css' for the bundle 'Basic.Global'!



在该项目下执行命令abp install-libs:



发现消息提示说ABP CLI有个更新的5.3.3版本,通过命令dotnet tool update -g Volo.Abp.Cli进行升级。再次运行Acme.BookStore.IdentityServer项目,发现不报错误了。如果在启动其它项目(特指Acme.BookStore.Web项目)的时候报同样的错误,那么同样执行命令abp install-libs即可解决问题。同时启动这3个项目如下:



启动成功后就可以见到熟悉的界面:



下面是项目Swagger的界面:



至此,已经把从官方下载下来的项目成功地运行起来了。

2.ABP运行流程

下面是在网上[1]找到的一张图,很清晰的说明了AspNet Core和ABP模块的运行流程,个人认为图上的Startup.ConfigureServices应该是Startup.Configure,已经在图中做了修改。



(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.cs

二.手动创建解决方案

0.创建解决方案

首先创建一个目录BookStoreHand用于存放解决方案:



然后创建一个解决方案,执行命令dotnet new sln -n Acme.BookStore:



用Rider打开后解决方案是空的,然后手动创建2个New Solution Folder,分别为src和test:

1.创建领域共享层和领域层

(1)Acme.BookStore.Domain.Shared[领域共享层]

通常定义的常量和枚举,都放在该项目中。通过命令dotnet new classlib -n Acme.BookStore.Domain.Shareddotnet sln ../Acme.BookStore.sln add Acme.BookStore.Domain.Shared创建领域共享层,并将其添加到解决方案当中:



然后就是创建模块类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如下:



Acme.BookStore.Domain项目依赖于Acme.BookStore.Domain.Shared项目:



创建模块类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如下:



Acme.BookStore.EntityFrameworkCore项目依赖于Acme.BookStore.Domain项目:



(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:



Acme.BookStore.Application.Contracts项目依赖于Acme.BookStore.Domain.Shared项目如下:



创建模块类BookStoreApplicationContractsModule如下:

[DependsOn(
typeof(BookStoreDomainSharedModule), //依赖于BookStoreDomainSharedModule
typeof(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如下:



Acme.BookStore.Application项目依赖于

Acme.BookStore.Application.Contracts和Acme.BookStore.Domain项目:



创建模块类BookStoreApplicationModule如下:

[DependsOn(
typeof(AbpAutoMapperModule), //依赖于AutoMapper
typeof(BookStoreDomainModule), //依赖于BookStoreDomainModule
typeof(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如下:



Acme.BookStore.DbMigrator项目依赖于Acme.BookStore.Application.Contracts和Acme.BookStore.EntityFrameworkCore项目如下:



创建模块类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项目没有迁移成功,最后还是通过命令行实现迁移的。迁移结果如下:



说明:Program.cs、DbMigratorHostedService.cs和BookStoreDbMigrationService.cs的源码等完整项目源码参考[4]。

5.创建远程服务层

Acme.BookStore.HttpApi[远程服务层],简单理解就是很薄的控制层,该项目主要用于定义HTTP API,即应用服务层的包装器,将它们公开给远程客户端调用。通过Rider创建Class Library项目Acme.BookStore.HttpApi如下:



Acme.BookStore.HttpApi项目依赖于Acme.BookStore.Application.Contracts项目如下:



创建模块类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如下:



Acme.BookStore.HttpApi.Host项目依赖于Acme.BookStore.Application、Acme.BookStore.EntityFrameworkCore和Acme.BookStore.HttpApi项目如下:



创建模块类BookStoreHttpApiHostModule如下:

[DependsOn(
typeof(BookStoreHttpApiModule), //依赖于BookStoreHttpApiModule
typeof(AbpAutofacModule), //依赖于AbpAutofacModule
typeof(BookStoreApplicationModule), //依赖于BookStoreApplicationModule
typeof(BookStoreEntityFrameworkCoreModule), //依赖于BookStoreEntityFrameworkCoreModule
typeof(AbpAspNetCoreSerilogModule), //依赖于AbpAspNetCoreSerilogModule
typeof(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项目启动起来后如下:



通过Swagger界面测试https://localhost:7016/api/app/book/get-book?id=1接口如下:

  奇怪的是在线生成解决方案的时候,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)

手动从0搭建ABP框架-ABP官方完整解决方案和手动搭建简化解决方案实践的更多相关文章

  1. 后台工作者HangFire与ABP框架Abp.Hangfire及扩展

    HangFire与Quartz.NET相比主要是HangFire的内置提供集成化的控制台,方便后台查看及监控,对于大家来说,比较方便. HangFire是什么 Hangfire是一个开源框架(.NET ...

  2. ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十四节--后台工作者HangFire与ABP框架Abp.Hangfire及扩展

    返回总目录:ABP+AdminLTE+Bootstrap Table权限管理系统一期 HangFire与Quartz.NET相比主要是HangFire的内置提供集成化的控制台,方便后台查看及监控,对于 ...

  3. ABP框架个人开发实战(1)_环境搭建

    前言 之前关注ABP框架有一阵子了,一直没有潜下心来实际研究一下.最近想自己建站,以后有自己的功能开发项目,可以在自己的站点上开发,并一步步的完善,所以找个比较好用的框架迫在眉睫,选来选去,决定用AB ...

  4. ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十七节--Quartz与ABP框架Abp.Quartz及扩展

    ABP+AdminLTE+Bootstrap Table权限管理系统一期 Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate- ...

  5. ABP module-zero +AdminLTE+Bootstrap Table+jQuery权限管理系统第十六节--SignalR与ABP框架Abp.Web.SignalR及扩展

    SignalR简介 SignalR是什么? ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指 ...

  6. 关于使用ABP框架搭建的项目升级时需要注意的问题汇总

    ABP理论学习总目录 一步一步使用ABP框架搭建正式项目系列教程 ABP之Module-Zero学习目录 本篇目录 说明 升级方法 问题_01:Log4Net导致编译不成功 2015/12/18更新 ...

  7. ABP架构学习系列三:手工搭建ABP框架

    由于公司的项目才接触到ABP这个框架,当时就觉得高大上,什么IOC.AOP.ddd各种专业词汇让人激情 澎湃,但在使用过程中碰到了许多坑,可能也许是没有去看源码导致的,但工作确实没有那么多时间让人去慢 ...

  8. 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问

    中小研发团队架构实践之生产环境诊断工具WinDbg 生产环境偶尔会出现一些异常问题,WinDbg或GDB是解决此类问题的利器.调试工具WinDbg如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具 ...

  9. 手工搭建ABP框架(1) - Web项目

    为了防止不提供原网址的转载,特在这里加上原文链接: http://www.cnblogs.com/skabyy/p/7295533.html ABP是 ASP.NET Boilerplate Proj ...

随机推荐

  1. SQL注入的几种类型

    SQL注入就是: 将构造SQL语句来插入到web提交的数据之中,让其返回数据时运行自己构造的恶意SQL语句. SQL注入构造恶意SQL语句的方法有: 构造堆叠,构造闭合,构造报错,构造时间差,等等 S ...

  2. 注解,lombok

    使用注解开发 UserMapper public interface UserMapper { @Select("select * from db4.user") List< ...

  3. 重新认识 MSBuild - 1

    前言 很多人一谈到 MSBuild,脑子里就会出现 "XML"."只能用 VS 的属性框图形界面操作"."可定制性和扩展性差" 和 &quo ...

  4. 811. Subdomain Visit Count - LeetCode

    Question 811. Subdomain Visit Count Example 1: Input: ["9001 discuss.leetcode.com"] Output ...

  5. Ubuntu16.04编译OpenJDK7u40

    下图是OpenJDK6.OpenJDK7.OpenJDK7u和OpenJDK8这几个项目之间的关系: 下面把编译步骤记录下来: 编译环境 Ubuntu 16.04.4 LTS jdk版本 openjd ...

  6. Linux篇-The slave I/O thread stops because master and slave have equal...

    1)操作系统 cat /etc/issue CentOS release 6.6 (Final) Kernel \r on an \m cat /proc/version Linux version ...

  7. Android7.1.2 源码编译并烧写Nexus5X

    1.环境配置 Ubuntu18.04 openJDK1.8 Python2.7 2.更新Ubuntu镜像源 编辑/etc/apt/source.list,替换为以下内容 deb http://mirr ...

  8. python之部分内置函数与迭代器与异常处理

    目录 常见内置函数(部分) 可迭代对象 迭代器对象 for循环内部原理 异常处理 异常信息的组成部分 异常的分类 异常处理实操 异常处理的其他操作 for循环本质 迭代取值与索引取值的区别 常见内置函 ...

  9. swiper使用

    swiper使用 初始化 var mySwiper = new Swiper ('容器区域类', { // 存放swiper属性 }) 属性 基本属性: 1.initialSlide 设定初始化时sl ...

  10. 前端CSS3布局display:grid用法

    前端CSS3布局display:flex用法 1. 先附上代码 点击查看代码 <!DOCTYPE html> <html> <head> <meta char ...