写了几节UI方面的内容,有点累了吧?这节先换点别的东西写。
前面章节基本把应用的总体配置完成了,开始进入具体页面的开发,而这些离不开与数据的交互、与用户的反馈操作等。正所谓“兵马未动,粮草先行”,现在封装下基本的服务。
前面章节我们都是用命令行来操作,如ionic g page person
,现在开始会涉及到很多命令操作,可能有些人会记不住命令,或者记不清关键字,可以像我这样,在IDE上装上插件,我这用的是VS Code,装了插件后,src
目录右键会出现Ionic Generate
的快捷菜单,点击后弹出选择界面,输入名称即可自动创建。
关于IDE插件的,可以查看我另一篇文章开发工具插件。
image.png
TypeScript中,public为默认访问级别,即外部可以访问的,所以如果想控制权限,请手动添加private关键字。常规应用,一般会有通用服务和具体业务服务,而常用的通用服务有如下几个:
一、全局设置服务
ionic g provider config
import { Injectable } from '@angular/core';
import { Headers, RequestOptions } from '@angular/http';
import 'rxjs/add/operator/map';
@Injectable()
export class ConfigProvider {
constructor() {
}
/**
* 获取域名
* @param versionType 版本类型,0:正式环境,1:测试环境,2: 本地
*/
static getDomainInfo(versionType: number = 1): any{
let domain: string;
switch(versionType){
case 0: domain = "http://"; break; //正式环境
case 1: domain = "http://"; break; //测试环境
case 2: domain = ""; break; //本地
default: domain = ""; break;
}
return {domain: domain, versionType: versionType};
}
/**
*获取api地址
*/
static getApiHost(){
return ConfigProvider.getDomainInfo().domain + "";
}
static defaultHeaders = new Headers({'Content-Type': 'application/json', 'Accept': 'application/json'});
static formHeaders = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Accept': 'application/json'});
static uploadHeasers = new Headers({'Content-Type': 'multipart/form-data'});
//
static defaultOptions = new RequestOptions({headers: ConfigProvider.defaultHeaders});
static formOptions = new RequestOptions({headers: ConfigProvider.formHeaders});
static uploadOptions = new RequestOptions({headers: ConfigProvider.uploadHeasers});
}
因为有时需要在几个环境切换服务地址,所以写一个方法方便切换地址;
另外angular默认使用application/json的请求头,有时我们需要根据后台接口来配置请求头,在这就预先配置几个常用的RequestOption,方便按需要随时切换。
二、网络请求服务
ionic g provider common
import 'rxjs/add/operator/retry';
import 'rxjs/add/operator/timeout';
import 'rxjs/add/operator/delay';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import { Headers, Http, RequestOptions } from '@angular/http';
import { ConfigProvider } from './config';
import { Injectable } from '@angular/core';
//处理过的响应数据
export interface IResponseData<T> {
success: boolean;
msg: string;
code?: number;
result?: T; //响应数据
}
@Injectable()
export class CommonProvider {
constructor(public authHttp: Http) {
}
/**
* get方法(isJoinHost是为了兼容获取应用内部数据)
* @param url 请求url
* @param isJoinHost 是否合并到主机地址
*/
get(url: string, isJoinHost: boolean = true) {
url = (isJoinHost && url.indexOf('http') <0) ? ConfigProvider.getApiHost() + encodeURI(url) : encodeURI(url);
return this.authHttp.get(url)
.timeout(60000)
.toPromise()
.then(result => result.json())
.catch(resp => this.handleHttpError(resp));
}
/**
* post方法
* @param url 请求url
* @param data 请求参数
* @param options 请求选项
*/
post(url: string, data: any = {}, options: RequestOptions = ConfigProvider.formOptions) {
url = url.indexOf('http') > -1 ? url : ConfigProvider.getApiHost() + url;
return this.authHttp.post(url, data, options)
.timeout(60000)
.toPromise()
.then(result => result.json())
.catch(resp => this.handleHttpError(resp));
}
/**
* 处理http错误
*/
handleHttpError(resp): IResponseData<any> {
let errMsg = '抱歉,后台服务出错了';
if (resp) {
let msg: string = resp.message;
if (msg && msg.toLowerCase().indexOf('timeout') > -1) {
errMsg = '请求超时,请稍后重试!';
} else {
switch (resp.status) {
case 401: errMsg = '无权限访问,或许登录信息已过期,请重新登录';
case 404: errMsg = '抱歉,后台服务找不到对应接口';
case 0: errMsg = '网络无法连接';
default: break;
}
}
}
return { success: false, msg: errMsg, code: -1, result: null};
}
}
这里只简单的封装了带超时和错误处理的get、post方法。因为数据接口服务往往不会只返回数据,还应带有请求信息,如获取数据为空,可以提示是系统问题、权限问题还是数据本就这样,所以封装了统一响应数据接口。
因为目前大多插件的异步使用Promise,Observable转Promise比较简单,而Promise转Observable比较麻烦,为了更方便集成,所以把官方推荐的Observable方式转成Promise方式,大家可基于Observable优点考虑仍沿用Observable也行。
注意catch里面用了return,表示捕获了异常处理并返回,下次链式调用将进入then,这样每个调用网络请求后的逻辑操作可以全放在then里,省掉写catch的部分。要想下次链式调用再处理异常,就应用Promise.reject继续抛出异常。
三、权限服务
ionic g provider auth
先建个文件备用。
四、缓存服务
ionic g provider cache
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
import { Storage } from '@ionic/storage';
/**
* 用枚举管理key值,防止字符串拼错
*/
export enum CacheKeys {
TOKEN, AUTO_LOGIN, USER_INFO
}
@Injectable()
export class CacheProvider {
constructor(public http: Http, public storage: Storage) {
console.log(CacheKeys[CacheKeys.TOKEN]);
}
}
因为key使用字符串方式,不容易记忆使用,也容易敲错,为了便于管理Key,用枚举来处理。后续补充结合http的缓存请求。
五、工具服务
ionic g provider util
import 'rxjs/add/operator/map';
import { DomSanitizer } from '@angular/platform-browser';
import { Injectable } from '@angular/core';
/*
工具类
Generated class for the UtilProvider provider.
*/
@Injectable()
export class UtilProvider {
constructor(private sanitizer: DomSanitizer) {
}
/**
* 深拷贝
*/
deepCopy(originObj: any): any{
return originObj ? JSON.parse(JSON.stringify(originObj)) : null;
}
/**
* 处理html的安全信任
* @param html raw html
*/
sanitizeHtml(html: string): any{
return this.sanitizer.bypassSecurityTrustHtml(html);
}
}
先实现两个应该要用到的方法,待后续实现功能时再扩展。
这些服务会随着业务功能的开发而补充,服务的每个方法可以不写返回类型(如fun: Promise<any>里的
Promise<any>
),但为了肉眼快速分辨出是异步方法还是普通方法?返回参数是什么类型?我习惯了书写。
晚了,先写到这里。
网友评论