使用Angular2与WebApi开发SPA类型的企业应用 - Part 1- 概览

来源:互联网 发布:ubuntu 打印机 编辑:程序博客网 时间:2024/06/02 02:22

使用Angular2及RESTful WebApi开发SPA类型的企业应用 - Part 1 概览
作者:techcoaching,翻译:飘落寒冰
原文 有道
注:第一次翻译文章,有错译之处还请多多包涵,欢迎指出以便改进。

该系列的全部文章

  1. 概览
  2. 添加新角色
  3. 项目结构
  4. 多语言
  5. 依赖注入和控制反转-为什么和为什么不?
  6. RESTful & WebApi
  7. 应用生命周期管理
  8. 应用构建与部署

简介

首先我跟大家分享的是“我们不是在学习技术,而是在学习怎样使用技术为我们的商业服务”。
注:代码所用的Angular2 为RC版

当今,随着Web开发的日益增加,越来越多的桌面应用(例如HRM,CRM,工资系统…)已经迁移成为Web应用。

Web应用可以使用Web环境的诸多好处。我们很容易就可以检索到大量Web应用与桌面应用之间的利弊分析,在此我们不做讨论。

本系列的文章主要是为了帮助你组织管理你的下列类型的项目

目前一些非常流行的技术:

  • Angular2 (typescript)
  • WebApi (RESTful)
  • Entity Framework
  • Bootstrap
  • IoC
  • Multi-Layer architecture
  • Modular your Application
  • Multi Languages
  • Design Pattern (Unit Of Work, Repository, …)
  • SOLID principle
  • Gulp
  • NodeJs

到目前为止他们仍在不断改进和提升。

如何获取代码

从Github上下载源码https://github.com/techcoaching/TinyERP.git

如何运行代码

代码分配在2个目录
- Client: 客户端代码,typescript写成,使用angular2框架。
- Api: 服务器段代码,用来处理客户端的请求

运行客户端:

  1. 运行客户端代码,首先需要安装:
    • Nodejs: https://nodejs.org/en/
    • Visual Code: https://code.visualstudio.com
  2. 运行app
    • 打开命令行并跳转到客户端的根目录
      image
    • 键入“npm install”,安装确实的NodeJS包
      image
    • 使用“npm start”,运行app
      控制台输出
      image
      浏览器输出
      image
      到这一步,客户端运行成功

运行API

  • 第一次运行,我们需要更新app.common\configurations\configuration.(debug|release).config文件中的connectionstring
    image
  • 在VS2015中打开 Api 项目
    image
  • 按F5 使用IIS Express运行程序,我们将在浏览器中看到以下输出:
    image
    如果配置过默认路由,将不会看到这个错误页面

应用初探

  • 首先我们需要登录
    image
  • 使用tu.tran@yahoo.com/123456登录,我们将看到下面的默认页面(可以在应用配置中变更):
    image

角色列表页面

在这一部分,我们将展示如何实现一个新页面
image

分析

我习惯在实现页面之前先做分析,能帮我们发现:
- 列出完成该页面的所有需要实现的步骤。
- 找出缺少的信息,然后立即寻求帮助
- 思考从客户端到服务器端的逻辑流程,从UI到数据访问,这有助于我们更好的编码。我的很多同事习惯先写代码,然后Debug。当有错误发生时,它令你不得不修改代码去维持系统运转,这样做很可能打破系统的逻辑流程,而且修改的代码往往不太符合该程序开发的结构与规范。这些将来可能会引发新的潜在的问题并且代码难以维护。

分析完页面之后,我们找出了以下需要完成的事情:

客户端
  • 创建新的模块(命名为security),我将谈论到一些模块化应用程序的优缺点。
  • 为角色组件(Angular里称page为组件)注册路由,并为其分配菜单信息(左侧面板的子菜单)
  • 将该组件的配置项导入并注册到应用配置中。
  • 创建组件文件(UI的html文件,逻辑处理的ts文件,组件视图模型的ts文件)
  • 实现角色管理组件的UI
  • 实现角色管理的逻辑(包含请求服务器及获取数据)
  • 实现页面的请求(请求通过调用REST api来获取授权列表)
服务器API
  • 增加名为RolesController的Controller来处理角色的相关请求
  • 增加RoleService和RoleRepository来获取角色列表(本文采用多层架构)
  • 在DbContext中增加实体类
    接来下我们一步一步来讲

实现客户端

在本节,目录为客户端所在目录
1. 创建一个新的模块(命名为security)。按照惯例,我们在”/app/modules/secutiry/_share/config”创建一个新的module.ts文件,如下:
image
创建route.ts文件
image
在此文件,我们将为security模块提供一个配置信息,例如:子菜单列表,模块路由
2. 为Roles组件注册路由和子菜单信息,将该行内容加入到上一步创建的module.ts文件中。
image
3. 将该模块的配置导入和注册到应用配置中。下面的代码把security模块注册到应用中,该模块和它的子菜单将在左侧列表中显示。
image
系统会自动为security模块注册路由。
4. 创建组件文件(UI的html文件,逻辑处理的ts文件,组件视图模型的ts文件)
image
5. 实现角色组件的UI。这里有一些本文会用到的指令已经创建出来,我将在其他的文件里介绍这些指令的细节。
image
在此Html中,我们用了:
- “grid”指令,显示角色列表。包含了若干我们可以处理的事件和在mode.options属性中定义的列
- “page-action”指令,在角色列表之上显示“添加角色”,如图
image
- page, page-header, page-content指令,这些是我的框架体系中页面结构指令
6. 实现角色组件的逻辑(包含请求服务器及获取数据)
image
为定义新的组件我们需要:
- 为组件指定模板文件(9行)
- 声明在组件中用到的指令(11行),如果指令没有被声明,在组件文件中他将不会被渲染,angular会将其标签(page-action/>, )解释成html标签
- 为BasePage声明新的角色类
- 为组件声明视图模型。每个组件必须包含自己的视图模型。这将帮助我们降低role.ts文件的复杂性
- 通过请求Api,调用roleService的相关方法,获取数据。我们将这些工作挪到service中可以使role.
注:我们在RolesModel的构造器中使用了i18nHelper,他将帮助我们解决表格列标题正确显示当前语言(多语言支持)
7. 实现页面的请求(请求通过调用REST api来获取授权列表)
image
这是一个通过请求REST api来获取角色列表的简单例子,更多IConnection的信息可以参考/app/common/connectors/RESTConnector.ts

实现API

在此节,目录为api代码所在目录.
1. Api 项目结构
image
- App.Common: 该目录包含了app各部门用到的基础代码。
- App.Api: 客户端可以调用对外公开的REST Api。
- App.Service: 包含所有的service接口及相应的数据传输对象。
- App.Service.Impl: 只包含对应的service接口的实现。
- App.Repository: 包含所有的数据访问接口。每个数据仓库只操作数据库中的一个实体模型。
- App.Repository.Impl: 只包含对应的数据访问接口的实现。
- App.Entity: 包含App中所有的实体模型。
- App.Context: 在本示例中,它包含我们在使用EF framework时所有的DbContext。我计划在将来将他和App.Entity合并。

注:我们只用接口在各层之间的进行通信(例如: App.Api -> App.Service => App.Repository)。
2. 增加名为RolesController的Controller来处理角色的相关请求。
按照本app的约定,我们在”App.Api/Features/Security”创建了RolesController。

namespace App.Api.Features.Security{    [RoutePrefix("api/roles")]    public class RolesController : ApiController    {        [HttpGet]        [Route("")]        public IResponseData<IList<RoleListItemSummary>> GetRoles()        {            IResponseData<IList<RoleListItemSummary>> response = new ResponseData<IList<RoleListItemSummary>>();            try            {                IRoleService roleService = IoC.Container.Resolve<IRoleService>();                IList<RoleListItemSummary> roles=roleService.GetRoles();                response.SetData(roles);            }            catch (ValidationException ex)            {                response.SetErrors(ex.Errors);                response.SetStatus(System.Net.HttpStatusCode.PreconditionFailed);            }            return response;        }    }}

我觉得这部分代码很简单。在controller中我们通过调用对应的service中的“GetRoles”,来获取角色列表(DTO)。
IoC将返回service中接口的实例
在 App.Service.Impl中,我们使用了boostrap.cs文件,我们在此注册了接口与其对应实现的实例。

namespace App.Service.Impl{    public class Bootstrap : App.Common.Tasks.BaseTask<IBaseContainer>, IBootstrapper    {        public Bootstrap():base(App.Common.ApplicationType.All)        {        }        public void Execute(IBaseContainer context)        {            context.RegisterSingleton<App.Service.Security.IRoleService, App.Service.Impl.Security.RoleService>();        }    }}
  1. 增加RoleService和RoleService来获取角色列表(本文采用多层架构)
namespace App.Service.Security{    public interface IRoleService    {        System.Collections.Generic.IList<RoleListItemSummary> GetRoles();    }}namespace App.Service.Impl.Security{    internal class RoleService : IRoleService    {        public IList<RoleListItemSummary> GetRoles()        {            IRoleRepository repository = IoC.Container.Resolve<IRoleRepository>();            return repository.GetItems<RoleListItemSummary>();        }    }}

注:
- 我们需要为每个action定义对应的DTO,大部分情况我们只需要实体模型的部分属性,这样有助于简化代码,并且在将来容易维护。
- RoleService 类并定义成internal,而不是public,所以外部无法创建该类的实例
4. 增加IRoleRepository和RoleRepository for getting the list of Roles

namespace App.Repository.Secutiry{    public interface IRoleRepository: App.Common.Data.IBaseContentRepository<Role>    {    }}namespace App.Repository.Impl.Security{    internal class RoleRepository: BaseContentRepository<Role>, IRoleRepository    {        public RoleRepository() : base(new App.Context.AppDbContext(App.Common.IOMode.Read))        {        }        public RoleRepository(IUnitOfWork uow) : base(uow.Context as IMSSQLDbContext)        {        }    }}

注:同RoleService一样, RoleRepository也被定义为internal.只有接口能被Project以外调用。
5. 在DbContext中增加实体类

namespace App.Entity.Security{    public class Role:BaseContent    {        public IList<Permission> Permissions { get; set; }        public Role():base()        {            this.Permissions = new List<Permission>();        }        public Role(string name, string desc, IList<Permission> permissions): this() {            this.Name = name;            this.Key = App.Common.Helpers.UtilHelper.ToKey(name);            this.Description = desc;            if (permissions == null) { return; }            this.Permissions = permissions;        }    }}namespace App.Context{    public class AppDbContext : App.Common.Data.MSSQL.MSSQLDbContext    {        public AppDbContext(IOMode mode = IOMode.Read) : base(new App.Common.Data.MSSQL.MSSQLConnectionString(), mode)        {        }        public System.Data.Entity.DbSet<Role> Roles { get; set; }    }}

总结

在本文中,我概述了SPA项目,在UI里如何获取和显示角色列表。
在下一片中,我将讲如何创建和更新角色,并将介绍该架构的更多细节(例如:项目结构,指令…)

授权

本文,以及所包含的源码,文件遵循CPOL协议

0 0