0%

Angular中的服务-Service

常见的后端开发中,有个MVC开发模式:Model-View-Controller。在MVC架构中,有个service层,负责是连接Controller和Model。Controller处理用户的输入和请求,Service负责从Model中获取数据并处理数据,Model定义数据库的字段定义和一些行为。在Angular中,Service作为一个服务,和MVC中的Service相类似,但是还是有差别的。

说起Angular,不得不说下MVVM设计模式:Model-View-ViewModel。

  • Model数据层,它是与应用程序的业务逻辑相关的数据的封装载体,在web页面中,大部分Model都是来自请求的服务端返回单数据或者是全局配置的对象。Angular中service则是封装和处理这些Model相关的业务逻辑的所在。
  • View视图,声明式模板,专注于界面的显示和渲染。
  • ViewModel视图-数据,它是View和Model的黏合体,负责View和Model的交互和协作。利用框架内置的双向绑定技术来实现View和Model的粘合。

为什么我们需要Service?

Angular的service是一个简单的TypeScript类,它封装了一些用于完成应用程序中特定任务的方法,例如从服务器获取数据或者向服务器发送数据。

Angular Service 具有以下的作用:

  • 用来将应用程序中的业务逻辑组件中的渲染逻辑分离
  • 用来在Angular应用中的多个组件之间共享数据
  • 让程序易于测试和调试
  • 用于编写可重用的代码。

创建一个Service

声明一个Service,需要使用Angular Core包提供的@Injectable装饰器,这意味着该服务可以被注入到组件和其他服务中。

我们可以使用Angular cli命令行创建一个服务:

1
ng g s auth

这样就创建了一个文件名为:auth.server.ts文件,里面有一个类:AuthService,看看里面具体的内容:

1
2
3
4
5
6
7
8
9
10
import {Injectable} from '@Angular/core';

@Injectable({
providedIn: 'root'
})
export class AuthService {

constructor() {
}
}

Injectable元数据提供了一个providedIn属性告诉Angular 注入器我们这个类的作用域以及他可以被注入到哪里。

@Injectable为标记性元数据,表示一个类可以由Injector创建。可以接受的选项有providedIn,这个参数描述了这个类的注入等级。providedIn接受的值有:

  • root 将服务注入到根组件中,这样它是全局共享的一个单例服务。
  • platform 页面所有应用程序共享的特殊单例平台注入器。
  • any 可以是任何Angular Module

Service可以被注入到root或者其他任何可用Module(使用any或直接使用Module)。any是Angular9版本开始支持。

我们可以给这个服务增加一个方法,从服务器中获取用户数据。

为了发送Http请求,我们需要导入HttpClientModule来注入HttpClient服务,我们需要src/app.component.ts中的import数组中添加HttpClientModule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import {BrowserModule} from '@angular/platform-browser';
import {AppComponent} from './app.component';
import {HttpClientModule} from '@angular/common/http';
import {NgModule} from '@angular/core';

@NgModule({
declarations: [
AppComponent,
],
imports: [
HttpClientModule,
],
bootstrap: [AppComponent],
})
export class AppModule {
}

HttpClient也是一个服务,我们可以将它注入到我们的AuthService中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';

@Injectable({
providedIn: 'root'
})
export class AuthService {

constructor(
private http: HttpClient,
) {
}

getUserInfo(userId: string) {
return this.http.get('http://localhost:8080/user/get', {
responseType: 'json',
params: {id: userId}
});
}
}

服务提供商配置注入器

我们前面创建的类提供了一个服务,@Injectable装饰器把它标记为可注入的服务。但是在我们使用服务的provider提供商配置好Angular依赖注入器之前,Angular无法将其注入到任何位置。

前面我们创建的服务:AuthService,为什么我们没有配置provider注入器,但是可以在组件中使用呢?

是因为在创建的时候默认将providedIn配置为root,这就创建了一个当前应用程序全局的服务。我们可以在任何组件里面使用,而不用特意在组件或模块中声明provider

可以在以下三种位置之一设置元数据,以便在应用的不同层级使用提供商来配置注入器:

  • 服务本身的@Injectable装饰器providedIn元数据中设置。
  • NgModule@NgModule装饰器providers元数据中设置,模块级的注入器。
  • 在组件的@Component装饰器providers元数据中设置,组件级的注入器。

所有的组件都是指令,而providers选项是从@Directive中继承来的,所以也可以与组件一样的级别为指令、管道配置服务提供商。

注入一个Service

先来了解下DI(Dependency Injection 依赖注入),DI是一种编码模式,一个类请求从外部资源中提供依赖关系,而不是去自己创建它们。

注入服务意味着什么?

Angular使用Dependency Injection(依赖注入,DI)来提供Service的实例给组件或者其他服务,这意味我们在使用这个服务之前无需手动去创建它;我们只需要告诉依赖注入(DI)我们需要使用这个服务,这样依赖注入会给我们提供这个服务的实例。那么我们如何告诉DI我们需要使用这个服务?

我们仅需要在组件或服务的构造函数中定义需要注入的服务,通过带有依赖类型的构造函数参数来要求Angular在组件的构造函数中注入依赖项。

我们在AppComponent中使用AuthService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import {Component, OnInit} from '@angular/core';
import {AuthService} from './auth.service';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit{
constructor(
private authService: AuthService,
) {
}

ngOnInit(): void {
this.authService.getUserInfo('test').subscribe(res => {
console.log(res);
});
}

}

可以看到,我们直接在组件中的constructor方法中声明我们需要的服务就可以使用这个服务,而不用创建这个服务。


这里我们了解了基本的Angular的Service的声明和注入,在使用上有全局的单例模式和模块或组件的注入模式。篇幅较长,服务的分级注入另写一篇。

参考:Angular.cn Angular中的依赖注入