当前位置:   article > 正文

鸿蒙【ArkTS】使用TS装饰器封装网络请求HTTP_arkts 调用java外部接口

arkts 调用java外部接口

HarmonyOS应用开发中,通过HTTP访问网络,可以使用官方提供的@ohos.net.http模块。但是官方提供的直接使用不太好使用,需要封装下才好。这里采用TS的装饰器实现AOP效果 完成前后端接口风格的统一

目录

  • @ohos.net.http (数据请求)官方示例
  • 声明网络权限
  • 封装实现步骤:
    • 一、统一接口请求结果
    • 二、网络请求配置类
    • 三、网络请求核心类 引用官方Api
    • 四、导出对外工具类
    • 五、利用装饰器实现AOP效果
  • 使用示例
  • 实现案例

文档中心:@ohos.net.http (数据请求)
TS装饰器介绍:TypeScript装饰器

实现效果在这里插入图片描述

@ohos.net.http (数据请求)官方示例

// 引入包名
import http from '@ohos.net.http';

// 每一个httpRequest对应一个HTTP请求任务,不可复用
let httpRequest = http.createHttp();
// 用于订阅HTTP响应头,此接口会比request请求先返回。可以根据业务需要订阅此消息
// 从API 8开始,使用on('headersReceive', Callback)替代on('headerReceive', AsyncCallback)。 8+
httpRequest.on('headersReceive', (header) => {
    console.info('header: ' + JSON.stringify(header));
});
httpRequest.request(
    // 填写HTTP请求的URL地址,可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
    "EXAMPLE_URL",
    {
        method: http.RequestMethod.POST, // 可选,默认为http.RequestMethod.GET
        // 开发者根据自身业务需要添加header字段
        header: {
            'Content-Type': 'application/json'
        },
        // 当使用POST请求时此字段用于传递内容
        extraData: {
            "data": "data to send",
        },
        expectDataType: http.HttpDataType.STRING, // 可选,指定返回数据的类型
        usingCache: true, // 可选,默认为true
        priority: 1, // 可选,默认为1
        connectTimeout: 60000, // 可选,默认为60000ms
        readTimeout: 60000, // 可选,默认为60000ms
        usingProtocol: http.HttpProtocol.HTTP1_1, // 可选,协议类型默认值由系统自动指定
    }, (err, data) => {
        if (!err) {
            // data.result为HTTP响应内容,可根据业务需要进行解析
            console.info('Result:' + JSON.stringify(data.result));
            console.info('code:' + JSON.stringify(data.responseCode));
            // data.header为HTTP响应头,可根据业务需要进行解析
            console.info('header:' + JSON.stringify(data.header));
            console.info('cookies:' + JSON.stringify(data.cookies)); // 8+
            // 取消订阅HTTP响应头事件
            httpRequest.off('headersReceive');
            // 当该请求使用完毕时,调用destroy方法主动销毁
            httpRequest.destroy();
        } else {
            console.info('error:' + JSON.stringify(err));
            // 取消订阅HTTP响应头事件
            httpRequest.off('headersReceive');
            // 当该请求使用完毕时,调用destroy方法主动销毁。
            httpRequest.destroy();
        }
    }
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

声明网络权限

使用Stage模型的应用,需要在module.json5配置文件中声明权限。

{
    "module" : {
        "requestPermissions":[
           {
             "name": "ohos.permission.INTERNET"
           }
        ]
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

封装实现步骤:

一、统一接口请求结果

export class ApiResult {
  code : string
  msg ?: string
  data ?: any
}
  • 1
  • 2
  • 3
  • 4
  • 5

二、网络请求配置类

/**
 * <pre>
 * @desc  : 网络请求配置
 * </pre>
 */
export interface RequestOptions {

  /**
   * Request url.
   */
  url?: string;

  /**
   * Request method.
   */
  method?: RequestMethod; // default is GET

  /**
   * Additional data of the request.
   * extraData can be a string or an Object (API 6) or an ArrayBuffer(API 8).
   */
  extraData?: string | Object | ArrayBuffer;

  /**
   * Request url queryParams  .
   */
  queryParams ?: Record<string, string>;

  /**
   * HTTP request header.
   */
  header?: Object; // default is 'content-type': 'application/json'

}

export enum RequestMethod {
  OPTIONS = "OPTIONS",
  GET = "GET",
  HEAD = "HEAD",
  POST = "POST",
  PUT = "PUT",
  DELETE = "DELETE",
  TRACE = "TRACE",
  CONNECT = "CONNECT"
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

三、网络请求核心类 引用官方Api

import http from '@ohos.net.http';
import { RequestOptions } from './RequestOptions';
import { ApiResult } from '../ApiResult/ApiResult';
// 引入弹窗
import PreferenceUtil from '../../utils/PreferenceUtil'
import promptAction from '@ohos.promptAction';
import { LoadingProgressDialog } from '../../utils/LoadingProgressDialog';
import router from '@ohos.router';
/**
 * Http请求器
 */
export class HttpCore {

  loadingDialog: CustomDialogController = new CustomDialogController({
    builder: LoadingProgressDialog(),
    alignment:DialogAlignment.Center,
    autoCancel: true,
    customStyle: true
  });


  /**
   * 发送请求
   * @param requestOption
   * @returns Promise
   */
  request(requestOptions: RequestOptions): Promise<ApiResult> {
    let p = new Promise<ApiResult>(async (resolve, reject) => {
      // 每一个httpRequest对应一个HTTP请求任务,不可复用
      let httpRequest = http.createHttp();
      let token : string = await getToken();
      let promise = httpRequest.request(requestOptions.url, {
        method: requestOptions.method,
        connectTimeout: 60000,
        readTimeout: 60000,
        header:{
          'Content-Type': 'application/json',
          'token': token,
          'client_type': 'HarmonyOS'
        },
        extraData: requestOptions.extraData
      });
      promise.then((data) => {
        //TODO:此处补充数据拆包的操作
        let resultObj = JSON.parse(data.result.toString());
        //弹窗提示接口返回msg
        setTimeout(() => {
          promptAction.showToast({
            message: resultObj.msg
          })
        }, 500);
        //如果业务码为20000 则返回ApiReslut
        if (resultObj.code == 20000) {
          console.log(JSON.stringify(resultObj))
          resolve(resultObj);
        }
        if (resultObj.code == 0){
          router.replaceUrl({
            url: "pages/MainPage/Login"
          }).then(() => {
            console.log('router successful')
          }).catch(err => {
            console.log('router err')
          })
        }
        //如果返回数据包含token信息 则刷新token
        if (resultObj.token != undefined)  {
          PreferenceUtil.putPreference('token',resultObj.token)
        }
      }).catch((err) => {
        //这里做全局异常统一处理  根据Http状态码做出处理
        console.info('error:' + JSON.stringify(err));
        reject(err);
      });
      httpRequest.destroy();
    })
    return p;
  }



}


async function getToken(): Promise<string> {
  return new Promise<string>(async (resolve, reject) => {
    try {
      const data = await PreferenceUtil.getPreference('token');
      if (typeof data === 'string') {
        resolve(data);
      } else {
        reject(new Error('Invalid token'));
      }
    } catch (err) {
      reject(err);
    }
  });

}




export const httpCore = new HttpCore();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105

四、导出对外工具类

import { RequestMethod, RequestOptions } from './RequestOptions';
import { httpCore } from './HttpCore';
import { ApiResult } from '../ApiResult/ApiResult';
/**
 * <pre>
 * @desc       : 对外工具包
 * </pre>
 */
export class HttpUtil {
  private static mInstance: HttpUtil;

  // 防止实例化
  private constructor() {

  }

  static getInstance(): HttpUtil {
    if (!HttpUtil.mInstance) {
      HttpUtil.mInstance = new HttpUtil();
    }
    return HttpUtil.mInstance;
  }

  request (option: RequestOptions): Promise<ApiResult> {
    return httpCore.request(option);
  }

  /**
   * 封装Post网络请求
   * @param option
   * @returns
   */
  Post(option:RequestOptions){
      if(option != null){
        option.method = RequestMethod.POST
      }
      return this.request(option);
  }

  /**
   * 封装Get网络请求
   * @param option
   * @returns
   */
  Get(option:RequestOptions){
    if(option != null){
      option.method = RequestMethod.GET
    }
    return this.request(option);
  }



}

export const httpUtil = HttpUtil.getInstance();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

五、利用装饰器实现AOP效果

import { ApiResult } from '../ApiResult/ApiResult';
import { httpUtil } from '../Http/HttpUtil';
import { RequestOptions } from '../Http/RequestOptions';

/**
 * 利用Map保存参数和值的映射关系  为避免参数名及方法名重复 采用组合Key的方法
 */
type FunParamMapKey = {
  target: Object; //所在类
  methodName: string; //所在方法
  index: number; //参数名索引值
}

let funParamMap = new Map<string, string>();


// @Get注解 拿到url 从函数的@Param拿到参数名及参数值 利用HttpUtil进行网络请求
//Get 需要拼接URl
export function Get(url: string) {
  return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    let URL: string = url;
    let options: RequestOptions = {
      url: URL,
      queryParams: {}
    };
    descriptor.value = async function (...args: any[]) {
      //对于方法中的每一个(methodName,arg)遍历加入到网络请求配置中
      args.forEach((arg, index) => {
        // 通过已知的信息构造组合Key对象
        let obj: FunParamMapKey = { target: target, methodName: methodName, index: index };
        // 通过组合Key(通过对内容的比较而不是值 节省内存)从内存map中获取@Param修饰的内容
        let paramName = funParamMap[JSON.stringify(obj)];
        // 将正确的参数名及值添加至网络请求参数中
        if (typeof paramName !== 'undefined') {
          if (typeof arg === 'string' || typeof arg === 'object' || arg instanceof ArrayBuffer || typeof arg === 'number') {
            options.queryParams[paramName] = arg
          } else {
            console.log('参数类型不对')
            throw new Error(`Invalid parameter type at index ${index}.`);
          }
        }
      });
      //拼接请求参数
      const urlParams = Object.keys(options.queryParams).map(key => `${key}=${options.queryParams[key]}`).join('&')
      console.log('urlParams:', urlParams)
      if (URL.includes("?")) {
        options.url = `${URL}${urlParams}`
      } else {
        options.url = `${URL}?${urlParams}`
      }

      const p = new Promise<ApiResult>((resolve, reject) => {
        httpUtil.Get(options).then((response) => {
          const result: ApiResult = response;
          resolve(result);
        }).catch((error) => {
          reject(error);
        });
      });
      return await p;
    };
  };
}

// @Post注解 拿到url 从函数的@Param拿到参数名及参数值 利用HttpUtil进行Post网络请求
export function Post(url: string) {
  return function (target: any, methodName: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    let options: RequestOptions = {
      url: url,
      extraData: {}
    };
    descriptor.value = async function (...args: any[]) {
      //对于方法中的每一个(methodName,arg)遍历加入到网络请求配置中
      args.forEach((arg, index) => {
        console.log("参数值",JSON.stringify(arg))
        // 通过已知的信息构造组合Key对象
        let obj: FunParamMapKey = { target: target, methodName: methodName, index: index };
        // 通过组合Key(通过对内容的比较而不是值 节省内存)从内存map中获取@Param修饰的内容
        let paramName = funParamMap[JSON.stringify(obj)];
        console.log("参数名:",paramName)
        // 将正确的参数名及值添加至网络请求参数中
        if (typeof paramName !== 'undefined') {
          if (typeof arg === 'string' || typeof arg === 'object' || arg instanceof ArrayBuffer) {
            options.extraData[paramName] = arg;
          } else {
            throw new Error(`Invalid parameter type at index ${index}.`);
          }
        }else {
          //如果获取不到形参名 及未被@Param标记 并且参数的类型是对象
          if (typeof  arg === 'object') {
            options.extraData = JSON.stringify(arg)
          }
        }
      });
      console.log('extraData', JSON.stringify(options.extraData))
      const p = new Promise<ApiResult>((resolve, reject) => {
        httpUtil.Post(options).then((response) => {
          const result: ApiResult = response;
          resolve(result);
        }).catch((error) => {
          reject(error);
        });
      });
      return await p;
    };
  };
}
/**
 * @Param 注解将想要获取的Param添加至内存Map中
 * @param paramName
 * @returns
 */
export function Param(paramName: string) {
  return function (target: any, methodName: string, parameterIndex: number) {
    let obj: FunParamMapKey = { target: target, methodName: methodName, index: parameterIndex };
    funParamMap[JSON.stringify(obj)] = paramName;
  };
}







  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127

使用示例

import { UserEditModel } from '../models/UserEditModel';
import{Post,Get, Param} from './aop/aop'
import { ApiResult } from './ApiResult/ApiResult';
export class UserApi {
  /**
   * 根据用户ID查询用户
   * @param @Param("userId") userId
   * @returns
   */
  @Get("http://localhost:8080/api/user/get")
  getUser(@Param("userId") userId: Number):Promise<ApiResult> {
    return
  }

  /**
   * 获取所有用户
   * @returns
   */
  @Get("http://localhost:8080/api/user/getAllUser")
  getAllUser():Promise<ApiResult> {
    return
  }

  /**
   * 更新用户信息
   * @returns
   */
  @Post("http://localhost:8080/api/user/update")
  updateUser( user : UserEditModel):Promise<ApiResult> {
    return
  }
}
export const  userApi = new UserApi();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
userApi.getAllUser().then((apiResult)=>{
      this.userList = apiResult.data
    })
    
//TODO 加载用户信息
    userApi.getUser(Number(this.userID)).then((apiResult)=>{
      this.user = apiResult.data
    })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

实现案例

gitee项目:鸿蒙前端 简易RBAC管控界面

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/582394
推荐阅读
相关标签
  

闽ICP备14008679号