在前面随笔《循序渐进VUE+Element 前端应用开发(12)--- 整合ABP框架的前端登录处理》简单的介绍了一个结合ABP后端的登陆接口实现前端系统登陆的功能,本篇随笔继续深化这一主题,着重介绍基于ABP后端接口信息,实现对前端界面的开发工作。
ABP(ASP.NET Boilerplate)框架主要是基于.net core 进行的后端Web API的开发,结合Swagger的管理界面我们可以看到发布的 API 的接口明细信息,这样前端技术人员可以很容易整合前端的API应用。Vue + Element的前端应用,是目前较为流行的前端技术整合,Vue提供了前端框架很好的支持,Element提供了非常不错的界面组件封装和处理,通过ABP后端API接口和前端Vue+Element的整合,可以很好实现前后端的分离处理,同时又极大提高各自开发过程,并利用最新、应用广泛的技术来实现最好的技术应用。
1、ABP接口和前端对接处理
ABP框架主要还是基于领域驱动的理念来构建整个架构的,其中领域驱动包含的概念有 域对象Entities、仓储对象Repositories、域服务接口层Domain Services、域事件Domain Events、应用服务接口Application Services、数据传输对象DTOs等。
ABP官方网站:http://www.aspnetboilerplate.com,从里面可以查看很详细的案例和文档说明,可以根据需要下载不同类型的基础框架。
ABP GitHub源码地址:https://github.com/aspnetboilerplate,可以下载整个基础的框架内容,以及相关的样板案例代码。
关于ABP框架使用,如果不知道,请自行补习一下我的随笔:ABP框架使用。
整理后的ABP快速开发框架的架构图示,如下图所示(以字典模块为例说明)
针对Web API接口调用的封装,为了适应客户端快速调用的目的,这个封装作为一个独立的封装层,以方便各个模块之间进行共同调用。
在基于VUE+Element 前端应用中,上图的ApiCaller组件,其实就是我们封装的API的JS类,同时也有相关的继承封装处理,类似C#中类的继承关系了。
在JS里面引入了ES6的语法,JS函数就可以使用类的方式来实现各种基础接口的封装和子类的继承关系了。
例如我们先定义好JS中常规的API封装接口BaseApi类,然后定义子类有DIctType、DictData等业务类,那么这些类继承BaseApi,就会具有相关的接口了,如下所示继承关系。
这些API类的文件视图如下所示。
有了这些业务类的准备,那么我们和后端ABP的API接口对接,就很容易了,如下图所示。
一般来说,我们页面模块可能会涉及到Store模块,用来存储对应的状态信息,也可能是直接访问API模块,实现数据的调用并展示。在页面开发过程中,多数情况下,不需要Store模块进行交互,一般只需要存储对应页面数据为全局数据状态的情况下,才可能启用Store模块的处理。
通过WebProxy代理的处理,我们可以很容易在前端中实现跨域的处理,不同的路径调用不同的域名地址API都可以,最终转换为本地的API调用,这就是跨域的处理操作。
2、ABP接口信息和前端界面处理
有了上面的一些知识准备,相信对ABP+Vue+Element的前端对接有了一个大概的认识了。
ABP+Swagger负责API接口的开发和公布,如下是API接口的管理界面。
进一步查看GetAll的API接口说明,我们可以看到对应的条件参数,如下所示。
这些是作为查询条件的处理,用来给后端获取对应的条件信息,从而过滤返回的数据记录的。
那么我们前端界面也需要根据这些参数来构造查询界面,我们可以通过部分条件进行处理即可,其中MaxResultCount和SkipCount是用于分页定位的参数。
前端界面代码如下所示。
主要就是构造一个条件查询的表单如下所示。
其中定义了一个searchForm的属性,那么我们可以了解下它的定义。
然后我们在查询处理的函数getlist里面,就可以根据这些条件,以及分页参数进行数据的请求查询了,如下代码所示。
getlist() { // 列表数据获取 var param = { // 构造常规的分页查询条件 SkipCount: (this.pageinfo.pageindex - 1) * this.pageinfo.pagesize, MaxResultCount: this.pageinfo.pagesize, // 过滤条件 Name: this.searchForm.name, Remark: this.searchForm.remark, DictType_ID: this.searchForm.dictType_ID }; // 获取产品列表,绑定到模型上,并修改分页数量 this.listLoading = true dictdata.GetAll(param).then(data => { this.list = data.result.items this.pageinfo.total = data.result.totalCount this.listLoading = false }) },
其中的dictdata.GetAll就是调用API模块里面的函数进行处理,是我们在视图页面类中导入这些API类的定义的。
// 业务API对象 import dicttype from '@/api/dicttype' import dictdata from '@/api/dictdata'
我们对于DictDataApi的JS类定义如下所示。
其中JS类的BaseApi具有常规的增删改查接口,如下所示。
其中list是列表的数据,pageinfo是分页信息,那么我们在前端的列表展示界面代码如下所示。
<el-table v-loading="listLoading" :data="list" border fit stripe highlight-current-row :header-cell-style="{background:'#eef1f6',color:'#606266'}" @selection-change="selectionChange" @row-dblclick="rowDbclick" > <el-table-column type="selection" width="55" /> <el-table-column label="字典名称"> <template slot-scope="scope"> {{ scope.row.name }} </template> </el-table-column> <el-table-column align="center" label="字典值"> <template slot-scope="scope"> {{ scope.row.value }} </template> </el-table-column> <el-table-column label="备注"> <template slot-scope="scope"> {{ scope.row.remark }} </template> </el-table-column> <el-table-column align="center" label="排序" width="80"> <template slot-scope="scope"> {{ scope.row.seq }} </template> </el-table-column> <el-table-column label="操作" width="140"> <template scope="scope"> <el-row> <el-tooltip effect="light" content="查看" placement="top-start"> <el-button icon="el-icon-search" type="success" circle size="mini" @click="showView(scope.row.id)" /> </el-tooltip> <el-tooltip effect="light" content="编辑" placement="top-start"> <el-button icon="el-icon-edit" type="primary" circle size="mini" @click="showEdit(scope.row.id)" /> </el-tooltip> <el-tooltip effect="light" content="删除" placement="top-start"> <el-button icon="el-icon-delete" type="danger" circle size="mini" @click="showDelete(scope.row.id)" /> </el-tooltip> </el-row> </template> </el-table-column> </el-table> <div class="block" style="height:70px;"> <el-pagination :current-page="pageinfo.pageindex" :page-size="pageinfo.pagesize" :total="pageinfo.total" :page-sizes="[10,20,30,40]" layout="total, sizes, prev, pager, next" @size-change="sizeChange" @current-change="currentChange" /> </div>
这样就可以简单实现列表的查询和展示了。
当然我们一般情况下,可能有一些列表用来进行数据过滤处理的,如这里的字典类型,可以通过树列表的进行展示,从而可以友好的管理不同类型的字典数据,如下是整合了树形列表的查询处理过程,界面相对复杂一些,不过原理差不多,都是根据条件进行API数据的请求,然后展示在列表中即可。
完整的对字典管理界面的实现。
其中包括对字典大类的维护,以及对应字典大类的数据列表数据的添加处理。