抛弃床的温暖,只为了它丨云库一款跑在鸿蒙系统上的应用丨篇二 原创 精华
前文再续,章节上篇。
在篇一,对整个项目要做什么,达到什么样的效果等做了简单的分析。本节将从服务端API约定、登录(没有注册,登录即注册)流程、长连接、华为云对象存储OBS基本概念介绍等对整个项目的技术层面做详细的介绍。
本节内容摘要:
1、约定服务端API返回结构
2、登录流程
3、华为云对象存储OBS介绍
4、HAP输入手机号获取验证码
约定服务端API返回结构
封装一个好的返回结构,使得我们在处理数据的时候能够减少各种拆解。因此在初期搭建完服务端项目后,首要做的是封装一套合理的返回数据结构,使API返回结构体大体相似。
1)使用Java Enum枚举类,将公用的返回错误进行封装,比如请求接口成功,请求接口失败,登录验证成功等等。
package com.ming.harmonyos.photokit.conf;
/**
 * 枚举类对象
 */
public enum StatusCode {
    //公共
    SUCCESS(200, "成功"),
    FAILED(9999, "失败"),
    UNKNOWN_ERROR(9998, "未知异常"),
    SYSTEM_ERROR(9997, "系统异常"),
    REQUEST_PARAMETER_ERROR(1001, "请求参数错误"),
    REQUEST_ACCESS_TOKEN_ERROR(1002, "请求参数token值错误"),
    //手机号校验
    CHECK_CELL_PHONE_NUM_ERROR(2001, "手机号码输入错误"),
    LOGIN_VALID_CODE_ERROR(2002, "登录验证码错误"),
    LOGOUT_ERROR(2003, "退出失败"),
    LOGOUT_AUTH_ERROR(2004, "退出失败,token不存在");
    /**
     * 状态码
     */
    private int code;
    /**
     * 状态消息
     */
    private String message;
    StatusCode(int code, String message) {
        this.code = code;
        this.message = message;
    }
    public int getCode() {
        return code;
    }
    public String getMessage() {
        return message;
    }
}
2)、封装一套API返回的数据结构
我目前使用的有两种,一种是以true|false做请求状态,另一种是以数字的形式做请求状态。两种各有千秋,第一种相对第二种的话要做到具体的异常定位需要在返回消息中加入异常码。本项目只是简单的示例项目,因此我选择第二种,这种方便控制。
package com.ming.harmonyos.photokit.conf;
import lombok.Data;
import java.io.Serializable;
/**
 * 返回结果类统一封装
 */
@Data
public class ApiResultInfo<T> implements Serializable {
    /**
     * 状态码
     */
    private Integer code;
    /**
     * 消息
     */
    private String message;
    /**
     * 数据对象
     */
    private T data;
    public ApiResultInfo() {
    }
    public ApiResultInfo(Integer code, String message, T data) {
        this();
        setCode(code);
        setMessage(message);
        setData(data);
    }
    public static <T> ApiResultInfo<T> getFailedInstant(Integer code, String message, T data) {
        return new ApiResultInfo<>(code, message, data);
    }
    public static <T> ApiResultInfo<T> getInstant(T data) {
        return new ApiResultInfo<>(StatusCode.SUCCESS.getCode(),
                StatusCode.SUCCESS.getMessage(), data);
    }
}
3)示例接口
这里只是一个登录(同时也是注册)接口,其他接口暂时未公开。
接口信息
接口地址:http://xxx/yunku/login.do 
请求示例:http://xxx/yunku/login.do 
支持协议:HTTP/HTTPS 
请求方式:POST 
返回格式:UTF8 JSON
请求参数
| 名称 | 类型 | 必填 | 示例值/默认值 | 说明 | 
| _cellPhoneNum | String | 是 | 13800000000 | 注册登录手机号 | 
| _validCode | String | 是 | 546655 | 获取的短信验证码 | 
返回示例
{
    "code": 200,
    "msg": "success",
    "data": {
        "authCode": "xxxxxx",
        "userInfo": {
            "iId": 1,
            "sPhone": "13800000000",
            "sNickName": "yx_13800000000",
           "sPath": "http://xxxx/yx_default.png",
           "dVolume": 20,
           "dUsedVolume": 5,
           "tEdit": "2021-01-20" 
        }
    }
}
返回参数
| 名称 | 类型 | 示例值 | 说明 | 
| authCode | String | d20a3965-5eb8-484b-84ea-e1e4d755a223 | 授权码 | 
| iId | int | 1 | 用户标识码 | 
| sPhone | String | 13800000000 | 手机号(也称账号) | 
| sNickName | String | yx_13800000000 | 昵称(可修改,默认yx_手机号组合) | 
| sPath | String | http://xxx/yx_default.png | 头像(可修改,默认yx_default.png) | 
| dVolume | Double | 20 | 存储容量总量 | 
| dUsedVolume | Double | 5 | 已使用存储容量 | 
| tEdit | DateTime | 2021-01-20 | 注册日期 | 
登录流程
登录即注册,用户第一次登录,验证通过后将用户信息以key-value的形式存入到Redis缓存中。如果是再次登录则存入新值,用户缓存有效期7天。

华为云对象存储OBS介绍
对象存储服务(Object Storage Service,OBS)提供海量、安全、高可靠、低成本的数据存储能力,可供用户存储任意类型和大小的数据。适合企业备份/归档、视频点播、视频监控等多种数据存储场景。我们这里只是用于存储多媒体文件。
对于现阶段,我们只需要了解OBS的桶、对象两个概念。桶是存储对象的容器,对象是数据存储的基本单位。可以对应我们系统的文件管理来看,桶相当于磁盘,比如D盘,在D盘根目录下只能存在一个同类型的文件,而对象就相当于文件夹中的文件。
而云库中,用于可以通过HAP创建多个云库(桶),在云库中上传多媒体文件。
HAP输入手机号获取验证码
这也是云库HAP的主页面,启动云库HAP后,进入应用首先看到的界面。对于登录页面,大体都是一样的,录入框和交互按钮是页面主要呈现的组件,额外会添加一些Image和Text组件,这里我们仅使用下表中罗列的组件来构建页面。
| 组件类别 | 名称 | 说明 | 
| 布局 | DirectionalLayout(线性布局)、DependentLayout(相对位置布局) | |
| 控件 | TextField、Button、Image(可选) | 其中Image组件用于显示云库HAP logo | 
<?xml version="1.0" encoding="utf-8"?>
<DependentLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:background_element="#FFFFFF">
    <Image
        ohos:id="$+id:logo"
        ohos:height="100vp"
        ohos:width="100vp"
        ohos:image_src="$media:logo"
        ohos:horizontal_center="true"/>
    <Text
        ohos:id="$+id:hello"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text="欢迎走近云库"
        ohos:top_margin="40vp"
        ohos:left_margin="20vp"
        ohos:right_margin="20vp"
        ohos:text_size="30fp"
        ohos:below="$+id:logo"/>
    <TextField
        ohos:id="$+id:phoneNum"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:hint="请输入手机号..."
        ohos:text_size="20fp"
        ohos:text_alignment="vertical_center"
        ohos:top_margin="10vp"
        ohos:left_margin="20vp"
        ohos:right_margin="20vp"
        ohos:top_padding="16vp"
        ohos:bottom_padding="16vp"
        ohos:basement="#E1E1D2"
        ohos:text_input_type="pattern_number"
        ohos:below="$+id:hello"/>
    <Button
        ohos:id="$+id:get_valid_code_btn"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:text="获取验证码"
        ohos:text_size="20fp"
        ohos:bottom_margin="20vp"
        ohos:left_margin="20vp"
        ohos:right_margin="20vp"
        ohos:top_padding="12vp"
        ohos:bottom_padding="12vp"
        ohos:align_parent_bottom="true"
        ohos:text_color="#F2F2F2"
        ohos:background_element="$graphic:background_disabled"/>
</DependentLayout>

Button button = (Button) findComponentById(ResourceTable.Id_get_valid_code_btn);
TextField inputPhoneNum = (TextField) findComponentById(ResourceTable.Id_phoneNum);
inputPhoneNum.setTextInputType(InputAttribute.PATTERN_NUMBER);
inputPhoneNum.addTextObserver(new Text.TextObserver() {
    @Override
    public void onTextUpdated(String s, int i, int i1, int i2) {
        if (s.length() == 11) {
            //TODO 判断是否输入的是正确的手机号, 排除输入汉字、标点符号、英文字母等不是数字情况
            ShapeElement shapeElement = new ShapeElement(getContext(), ResourceTable.Graphic_background_login);
            button.setBackground(shapeElement);
            button.setClickable(true);
        } else {
            ShapeElement shapeElement = new ShapeElement(getContext(), ResourceTable.Graphic_background_disabled);
            button.setBackground(shapeElement);
            button.setClickable(false);
        }
    }
});
button.setClickedListener(l -> {
    if (l.isClickable()) {
        //TODO 执行获取验证码接口,返回数据成功后跳转到验证码输入页面
    }
});
由于后端程序还未部署到服务器上,这里接口调用暂时还未编写。后续整个项目公开后,可以查看具体源码,敬请期待!!!
欲知验证码如何输入,且看下节篇目。





















被标题吸引来的。。
难道不是内容吗?
看了标题 以为是篇水文,没想到,料还很足!!!
不能水,一水就刹不住了 😄
因为鸿蒙目前不支持
补充一下手机号最多只输入11位的方法:
👍👍👍