新建Service

Service

通过Service和API进行交互,并将数据返回。

在libs下面建立文件夹名为:backend 用于存放和API交互的Service

1. 创建名为backend的module

1
ng generate lib backend --tags=lib:backend --routing --lazy --unit-test-runner jest --parent-module=apps/client/src/app/app.module.ts

2. 新建名为hr-manager的service文件

libs->backend->src->lib 文件夹上,右键选择:Open in Integrated Termial。

执行下记代码,创建service。

1
ng generate service hr-manager/hr-manager

3. 测试

接下来,开始编写关于用户的增删改查的service代码块。

3.1 改造结构体

之前在第一个程序中, 创建state的时候,生成了content-hrmanager.models.ts。我们需要在里面填写各个属性字段。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
/**
 * 用户结构体
 */
export interface ContentHrmanagerEntity {
  /**
   * ID
   */
  id: number;
  /**
   * 名称
   */
  name: string;
  /**
   * 年龄
   */
  age: number;
}
3.2 编写GET代码

打开刚才创建的HrManagerService文件。利用Angualar中HttpClient来进行代码编写。

1. 在BackendModule中引入:HttpClientModule

在app.module.ts中引入BackendMoudle

2. 在constructor中引入HttpClient

3. 手动引入ContentHrmanagerEntity

1
import { ContentHrmanagerEntity } from '@redux-app/content/hrmanager';

上记的 redux-app/content/hrmanager 在下记的tsconfig中查找。

4. 获取全部用户接口

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  /**
   * mock服务器接口
   */
  private readonly API = 'http://localhost:3000/users';

  /**
   * 获取user全部数据
   */
  public getAll(): Observable<ContentHrmanagerEntity[]> {
    return this.http.get(`${this.API}`).pipe(
      map(data => (data || [] ) as ContentHrmanagerEntity[])
    );
  }

5. 将创建的HrManagerService导出

6. 在form.component.ts中,引入HrManagerSerivce

1
import { HrManagerService } from '@redux-app/backend';

引入方法和3类似,因为backend和content是作为libs的两个小模块,没有相互引用。所以需要收入引入相关的Entity、Service之类的。

在constructor中引用:

1
constructor(private hrManagerService: HrManagerService) {}

下面我们开始测试第一个实际交互的例子,通过点击“查询”按钮,获取所有用户信息,并在控制台显示出来。

因为我们需要利用rxjs操作符来将observable流的数据取出来,没有安装rxjs,按下记方式install。

1
npm install rxjs

在search查找方法中,我们填写下面的代码,之后按照下记的步骤查看运行结果

  • 用 json-server ./mock/_fixture/hr-manager.json 命令启动mock

  • 运行client程序

1
2
3
4
5
6
const users$ = this.hrManagerService.getAll();
  users$.subscribe(data => {
    data.forEach(user => {
      console.log('id = ' + user.id + '  name = ' + user.name + '  age = ' + user.age);
    })
  });

在浏览器中,点击“查询”按钮,并在控制台查看结果。

虽然从控制台看到了运行的结果,但是我们没有测试错误的场景,下面 我们来改造一下代码。

  • 在service代码块中,添加catchError来捕获异常
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// hr-manager.service.ts
/**
 * 获取user全部数据
 */
public getAll(): Observable<ContentHrmanagerEntity[]> {
  return this.http.get(`${this.API}`).pipe(
    map((data) => (data || []) as ContentHrmanagerEntity[]),
    catchError((err: HttpErrorResponse) => {
      if (err.status === 404) {
        return of(null);
      }
      return throwError(err);
    })
  );
}
  • search方法中添加err函数进行处理
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/**
 * 查找
 */
search() {
  const users$ = this.hrManagerService.getAll();
  users$.subscribe(data => {
    if(data === null) {
      // 跳转到404页面
      return;
    }
    data.forEach(user => {
      console.log('id = ' + user.id + '  name = ' + user.name + '  age = ' + user.age);
    })
  },
  err => {
    console.log((err as HttpErrorResponse).message);
  });
}
  • 测试场景:

    • 将mock服务器断开链接:

    当点击“查询”按钮,在控制台输入errMessage

    • 访问未知的接口

    如: 将查询接口中的users换成users2

接下来,继续扩展get方法,根据id来查询用户数据。

  • 在service代码中,添加下面方法
1
2
3
4
5
6
/**
 * 获取指定id的user数据
 */
public get(id: number): Observable<ContentHrmanagerEntity> {
  return this.http.get(`${this.API}/${id}`) as Observable<ContentHrmanagerEntity>;
}
  • search方法改造
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/**
 * 查找
 */
search() {
  const id = this.id.nativeElement.value;
  const user$ = this.hrManagerService.get(+id);
  user$.subscribe(
    user => console.log('id = ' + user.id + '  name = ' + user.name + '  age = ' + user.age),
    err => {
      console.log((err as HttpErrorResponse).message);
    });
}
  • 测试场景

    • id输入框中输入1

    • id输入框输入users不存在的数据,如:5