使用Angular2及WebApi开发SPA类型的企业应用 - Part 2- 添加新角色

时间:2022-10-23 10:38:23

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

在本文中,我们将学习如何创建和编辑角色
从Github上下载源码

该系列的全部文章

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

简介

本部分,我们将通过一系列步骤来学习如何使用代码来实现添加角色页面:
使用Angular2及WebApi开发SPA类型的企业应用 - Part 2- 添加新角色

分析页面

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

客户端
  • 为“添加角色”页面注册路由(angular2组件)
  • 创建组件文件(UI的html文件,逻辑处理的ts文件,组件视图模型的ts文件)
  • 实现角色管理组件的UI
  • 实现角色管理的逻辑(包含请求服务器及获取数据)
  • 实现页面的请求(请求通过调用REST api来获取授权列表)
API
  • 在RolesController中增加一个方法处理创建角色的请求,Role作为参数
  • 在Role service 和 Role repository 中各增加一个创建Role的方法

在客户端实现

在本节,目录为客户端所在目录

  1. 为“添加角色”页面注册路由(angular2组件)
    到”/app/modules/secutiry/_share/config”中更新 addRoutes 方法如下:
import {IModule, Module, MenuItem} from "../../../../common/models/layout";
import {Roles} from "../../role/roles";
import {AddRole} from "../../role/addRole";
import {AuthenticationMode} from "../../../../common/enum";
import route from "./route";
let module: IModule = createModule();
export default module;
function createModule() {
let module = new Module("app/modules/secutiry", "secutiry");
module.menus.push(
new MenuItem(
"Security", route.role.roles.name, "fa fa-user-md",
new MenuItem("Roles", route.role.roles.name, ""),
)
);
module.addRoutes([
{ path: route.role.roles.path, name: route.role.roles.name, component: Roles,
data: { authentication: AuthenticationMode.Require }, useAsDefault: true },
{ path: route.role.addRole.path, name: route.role.addRole.name, component: AddRole,
data: { authentication: AuthenticationMode.Require } }
]);
return module;
}

route.ts 内容:

let route = {
role: {
roles: { name: "Roles", path: "/roles" },
addRole: { name: "Add Role", path: "/addRole" }
}
};
export default route;
  1. 创建组件文件(UI的html文件,逻辑处理的ts文件,组件视图模型的ts文件)
    使用Angular2及WebApi开发SPA类型的企业应用 - Part 2- 添加新角色

  2. 实现角色管理组件的UI

<page>
<page-header>
{{i18n.security.addOrUpdateRole.title}}
</page-header>
<page-content>
<form-default>
<form-text-input [placeHolderText]=i18n.security.addOrUpdateRole.inputName
[labelText]=i18n.security.addOrUpdateRole.name

[validation]="['security.addOrUpdateRole.validation.nameIsRequire',
'security.addOrUpdateRole.validation.keyAlreadyExisted']"

[(model)]=model.name>

</form-text-input>
<form-textarea [placeHolderText]=i18n.security.addOrUpdateRole.inputDesc
[labelText]=i18n.security.addOrUpdateRole.desc [(model)]=model.description>

</form-textarea>

<form-permission-select [(values)]=model.permissions
[placeHolderText]=i18n.security.addOrUpdateRole.inputPermissions
[labelText]=i18n.security.addOrUpdateRole.permission

[(model)]=model.permissions>

</form-permission-select>

<form-footer>
<button id="save"
(click)="onSaveClicked($event)" type="button"
class="btn btn-primary">
{{i18n.common.form.save}}</button>
<button id="cancel"
(click)="onCancelClicked($event)" type="button"
class="btn btn-default">
{{i18n.common.form.cancel}}</button>
</form-footer>
</form-default>
</page-content>
</page>

浏览器输出:
使用Angular2及WebApi开发SPA类型的企业应用 - Part 2- 添加新角色

该文件中:
- 我们用的不是标准HTML创建UI和Form,我们用了一些指令来完成这个工作,例如form, form-textarea, ······
- 本页的结构:
- page-header: 包含页首内容
- page-content: 包含页面主要内容

  1. 实现角色管理的逻辑
import {BasePage} from "../../../common/models/ui";
import {Router, RouteParams} from "angular2/router";
import {Component} from "angular2/core";
import {AddRoleModel} from "./addRoleModel";
import {Page, SelectPermission, Form, FormTextInput, FormFooter,
FormTextArea, FormPermissionSelect} from "../../../common/directive";
import {ValidationDirective} from "../../../common/directive";
import roleService from "../_share/services/roleService";
import {FormMode} from "../../../common/enum";
import route from "../_share/config/route";
@Component({
templateUrl: "app/modules/security/role/addRole.html",
directives: [Page, Form, FormTextInput, FormFooter, FormTextArea, FormPermissionSelect]
})
export class AddRole extends BasePage {
public model: AddRoleModel = new AddRoleModel();
private router: Router;
constructor(router: Router, routeParams: RouteParams) {
super();
let self: AddRole = this;
self.router = router;
}
public onSaveClicked(event: any): void {
let self: AddRole = this;
roleService.create(this.model).then(function () {
self.router.navigate([route.role.roles.name]);
});
}
public onCancelClicked(event: any): void {
let self: AddRole = this;
self.router.navigate([route.role.roles.name]);
}
}

该文件中:
- 通过routeParams.get(“id”)获得选中角色的id
- 通过调用router.navigate切换页面

  1. 实现页面的请求(请求通过调用REST api来获取授权列表)
import configHelper from "../../../../common/helpers/configHelper";
import {Promise} from "../../../../common/models/promise";
let roleServices = {
getRoles: getRoles,
create: create
};
export default roleServices;
function getRoles(): Promise {
let connector = window.ioc.resolve("IConnector");
let url = String.format("{0}roles", configHelper.getAppConfig().api.baseUrl);
return connector.get(url);
}

function create(role: any): Promise {
let connector = window.ioc.resolve("IConnector");
let url = String.format("{0}roles", configHelper.getAppConfig().api.baseUrl);
return connector.post(url, role);
}

实现API

  1. 在RolesController中增加一个方法处理创建角色的请求,Role作为参数
using App.Common.DI;
using App.Common.Http;
using App.Common.Validation;
using App.Service.Security;
using System;
using System.Collections.Generic;
using System.Web.Http;

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

[HttpPost]
[Route("")]
public IResponseData<CreateRoleResponse> CreateRole(CreateRoleRequest request)
{
IResponseData<CreateRoleResponse> response = new ResponseData<CreateRoleResponse>();
try
{
IRoleService roleService = IoC.Container.Resolve<IRoleService>();
CreateRoleResponse role = roleService.Create(request);
response.SetData(role);
}
catch (ValidationException ex)
{
response.SetErrors(ex.Errors);
response.SetStatus(System.Net.HttpStatusCode.PreconditionFailed);
}
return response;
}
}
}
  1. 在IRoleService 和 RoleService 中各增加一个创建Role的方法
    • IRoleService.cs
namespace App.Service.Security
{
public interface IRoleService
{
System.Collections.Generic.IList<RoleListItemSummary> GetRoles();
CreateRoleResponse Create(CreateRoleRequest request);
}
}
  • RoleService.cs
using System.Collections.Generic;
using App.Service.Security;
using App.Common.DI;
using App.Repository.Secutiry;
using App.Entity.Security;
using App.Common;
namespace App.Service.Impl.Security
{
public class RoleService : IRoleService
{
public CreateRoleResponse Create(CreateRoleRequest request)
{
ValidateCreateRequest(request);
using (App.Common.Data.IUnitOfWork uow =
new App.Common.Data.UnitOfWork(new App.Context.AppDbContext(IOMode.Write)))
{
IRoleRepository roleRepository =
IoC.Container.Resolve<IRoleRepository>(uow);
IPermissionRepository permissionRepo =
IoC.Container.Resolve<IPermissionRepository>(uow);
IList<Permission> permissions =
permissionRepo.GetPermissions(request.Permissions);
Role role = new Role(request.Name, request.Description, permissions);
roleRepository.Add(role);
uow.Commit();
}
return new CreateRoleResponse();
}
private void ValidateCreateRequest(CreateRoleRequest request)
{
if (string.IsNullOrWhiteSpace(request.Name))
{
throw new App.Common.Validation.ValidationException
("security.addOrUpdateRole.validation.nameIsRequire");
}
}
public IList<RoleListItemSummary> GetRoles()
{
IRoleRepository repository = IoC.Container.Resolve<IRoleRepository>();
return repository.GetItems<RoleListItemSummary>();
}
}
}

Role service:
- 通过调用Role repository 中的Create方法创建角色。
- 需要特别指出的是,我们使用了UnitOfWork(单元工作模式),来避免一些意料之外的更改被保存到数据库中。
- Exception “security.addOrUpdateRole.validation.nameIsRequire”, 会在客户端以当前的语言,以tooltip的方式展示到组件内。本示例中我们只将错误的Key返回到客户端,客户端将根据其的语言显示相应的内容。

  1. IRoleRepository 和 RoleRepository 用来创建Role。
    我们不需要对repository继承的方法做任何修改。
namespace App.Repository.Secutiry
{
public interface IRoleRepository: App.Common.Data.IBaseContentRepository<Role>
{
}
}

using App.Common.Data.MSSQL;
using App.Entity.Security;
using App.Repository.Secutiry;

namespace App.Repository.Impl.Security
{
public 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)
{
}
}
}

总结

到目前为止,我们已经能够创建一个新的角色。

授权

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