任务 6.2 云笔记 - 云端存储数据(3)

三、实现ServerNoteRepository

ServerNoteRepository作为新的数据仓库实现类,它通过访问服务端的各个操作接口来实现数据的提交和获取。我们仍然使用okhttp3开源框架来完成这些基于HTTP协议的网络操作。


3.1 修改HttpHelper类

首先打开帮助类HttpHelper,向里面添加相关的常量和URL获取方法。
增加如下的常量定义:

    private static final String NOTE_URL = HTTP_PREFIX + "note.php";
    private static final String SAVE_NOTE_URL = NOTE_URL + "?p=save";
    private static final String FIND_NOTE_URL = NOTE_URL + "?p=find&id=";
    private static final String FIND_ALL_NOTE_URL = NOTE_URL + "?p=findall";

    private static final String NOTEBOOK_URL = HTTP_PREFIX + "notebook.php";
    private static final String SAVE_NOTEBOOK_URL = NOTEBOOK_URL + "?p=save";
    private static final String FIND_NOTEBOOK_URL = NOTEBOOK_URL + "?p=find&id=";
    private static final String FIND_ALL_NOTEBOOK_URL = NOTEBOOK_URL + "?p=findall";

增加如下的方法:

    // 获取保存笔记页面地址
    public static String getSaveNoteUrl() {
        return SAVE_NOTE_URL;
    }
    // 获取根据id查找笔记页面地址
    public static String getFindNoteUrl(long id) {
        return FIND_NOTE_URL + id;
    }
    // 获取查找全部笔记页面地址
    public static String getFindAllNoteUrl() {
        return FIND_ALL_NOTE_URL;
    }

    // 获取保存笔记本页面地址
    public static String getSaveNotebookUrl() {
        return SAVE_NOTEBOOK_URL;
    }
    // 获取根据id查找笔记本页面地址
    public static String getFindNotebookUrl(long id) {
        return FIND_NOTEBOOK_URL + id;
    }
    // 获取查找全部笔记本页面地址
    public static String getFindAllNotebookUrl() {
        return FIND_ALL_NOTEBOOK_URL;
    }

3.2 完成ServerNoteRepository类

3.2.1 增加构造方法以获取Context对象

为ServerNoteRepository类增加Context类型的成员,并为其创建构造方法,从外界接收一个Context对象进行初始化:

    private Context context;
    public ServerNoteRepository(Context context) {
        this.context = context;
    }

3.2.2 构造单例模式

仍然按照基于本地数据库的NoteRepository的方式构造成单例。向ServerNoteRepository类中添加如下代码:

    private static ServerNoteRepository sInstance;

    //获取单例对象
    public static ServerNoteRepository getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new ServerNoteRepository(context);
        }
        return sInstance;
    }

3.2.3 getAllNotes()

这里应当访问对应的获取全部笔记记录的接口,并提供当前email账号。对返回的结果(JSON)进行解析,得到笔记对象列表。在编写代码如下:

    @Override
    public ArrayList<Note> getAllNotes() {
        ArrayList<Note> notes = new ArrayList<>();

        String email = Utils.getUserEmail(context);
        // 当前并没有登录
        if (TextUtils.isEmpty(email)) {
            return notes;
        }

        OkHttpClient client = new OkHttpClient();
        // 创建包含email账号的表单,
        FormBody.Builder fb = new FormBody.Builder();
        FormBody formBody = fb.add("email", email)
                .build();
        // 创建获取全部笔记的请求
        Request request = new Request.Builder()
                .url(HttpHelper.getFindAllNoteUrl())
                .post(formBody)
                .build();
        Call call = client.newCall(request);
        try {
            // 执行请求并返回结果
            Response response = call.execute();
            if (response != null) {
                String json = response.body().string();
                if (!TextUtils.isEmpty(json)) {
                    JSONObject jo = new JSONObject(json);
                    int code = jo.optInt("code", 0);
                    if (code == 1) {
                        JSONArray array = jo.optJSONArray("noteList");
                        // 逐个解析出获取到的笔记,并插入列表
                        for (int i = 0; i < array.length(); i++) {
                            JSONObject jnote = array.getJSONObject(i);
                            long id = jnote.optLong("id");
                            String title = jnote.optString("title");
                            String content = jnote.optString("content");
                            long createTime = jnote.optLong("createTime");
                            long notebookId = jnote.optLong("notebookId");
                            Note note = new Note(id, title, content, createTime, notebookId);
                            notes.add(note);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return notes;
    }

3.2.4 saveNote()

在这里,要将参数传来的Note对象信息提交到服务器端并存储。成功后将返回新存储的笔记的id。将此id设置给被保存的note对象并作为方法返回值。
编写代码如下:

    @Override
    public Note saveNote(Note note) {
        String email = Utils.getUserEmail(context);
        if (note == null || TextUtils.isEmpty(email)) {
            return note;
        }

        OkHttpClient client = new OkHttpClient();
        // 创建包含被保存笔记信息和email账号的表单,
        FormBody.Builder fb = new FormBody.Builder();
        FormBody formBody = fb.add("email", email)
                .add("title", note.getTitle())
                .add("content", note.getContent())
                .add("createTime", String.valueOf(note.getCreateTime()))
                .add("notebookId", String.valueOf(note.getNotebookId()))
                .build();
        // 创建保存笔记的请求
        Request request = new Request.Builder()
                .url(HttpHelper.getSaveNoteUrl())
                .post(formBody)
                .build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();
            if (response != null) {
                String json = response.body().string();
                if (!TextUtils.isEmpty(json)) {
                    JSONObject jo = new JSONObject(json);
                    int code = jo.optInt("code", 0);
                    if (code == 1) {    // 提交成功
                        long id = jo.optLong("id");
                        if (id <= 0) {
                            return null;
                        }
                        note.setId(id);
                    } else {    // 保存失败,返回null
                        return null;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return note;
    }

3.2.4 getNote()

这里根据参数指定的笔记id提交服务器查询,在根据返回的数据生成笔记对象。编写代码如下:

    @Override
    public Note getNote(long noteId) {
        // 检查登录状态及参数合法性
        String email = Utils.getUserEmail(context);
        if (noteId <= 0 || TextUtils.isEmpty(email)) {
            return null;
        }

        OkHttpClient client = new OkHttpClient();
        // 创建包含email账号的表单,
        FormBody.Builder fb = new FormBody.Builder();
        FormBody formBody = fb.add("email", email)
                .build();
        // 创建查找笔记的请求
        Request request = new Request.Builder()
                .url(HttpHelper.getFindNoteUrl(noteId))
                .post(formBody)
                .build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();
            if (response != null) {
                String json = response.body().string();
                if (!TextUtils.isEmpty(json)) {
                    JSONObject jo = new JSONObject(json);
                    int code = jo.optInt("code", 0);
                    if (code == 1) {    // 提交成功
                        JSONObject jnote = jo.optJSONObject("note");
                        long id = jnote.optLong("id");
                        String title = jnote.optString("title");
                        String content = jnote.optString("content");
                        long createTime = jnote.optLong("createTime");
                        long notebookId = jnote.optLong("notebookId");
                        return new Note(id, title, content, createTime, notebookId);
                    } else {    // 保存失败,返回null
                        return null;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }


        return null;
    }

3.2.5 saveNotebook()

向服务器提交并保存参数给出的笔记本对象。与保存笔记对象思路基本一致。编写代码如下:

    @Override
    public Notebook saveNotebook(Notebook notebook) {
        String email = Utils.getUserEmail(context);
        if (notebook == null || TextUtils.isEmpty(email)) {
            return notebook;
        }

        OkHttpClient client = new OkHttpClient();
        // 创建包含被保存笔记本信息和email账号的表单,
        FormBody.Builder fb = new FormBody.Builder();
        FormBody formBody = fb.add("email", email)
                .add("name", notebook.getName())
                .build();
        // 创建保存笔记本的请求
        Request request = new Request.Builder()
                .url(HttpHelper.getSaveNotebookUrl())
                .post(formBody)
                .build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();
            if (response != null) {
                String json = response.body().string();
                if (!TextUtils.isEmpty(json)) {
                    JSONObject jo = new JSONObject(json);
                    int code = jo.optInt("code", 0);
                    if (code == 1) {    // 提交成功
                        long id = jo.optLong("id");
                        if (id <= 0) {
                            return null;
                        }
                        notebook.setId(id);
                    } else {    // 保存失败,返回null
                        return null;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return notebook;
    }

3.2.6 getAllNotebooks()

编写代码如下:

    @Override
    public ArrayList<Notebook> getAllNotebooks() {
        ArrayList<Notebook> notebooks = new ArrayList<>();

        String email = Utils.getUserEmail(context);
        // 当前并没有登录
        if (TextUtils.isEmpty(email)) {
            return notebooks;
        }

        OkHttpClient client = new OkHttpClient();
        // 创建包含email账号的表单,
        FormBody.Builder fb = new FormBody.Builder();
        FormBody formBody = fb.add("email", email)
                .build();
        // 创建获取全部笔记本的请求
        Request request = new Request.Builder()
                .url(HttpHelper.getFindAllNotebookUrl())
                .post(formBody)
                .build();
        Call call = client.newCall(request);
        try {
            // 执行请求并返回结果
            Response response = call.execute();
            if (response != null) {
                String json = response.body().string();
                if (!TextUtils.isEmpty(json)) {
                    JSONObject jo = new JSONObject(json);
                    int code = jo.optInt("code", 0);
                    if (code == 1) {
                        JSONArray array = jo.optJSONArray("notebookList");
                        // 逐个解析出获取到的笔记本,并插入列表
                        for (int i = 0; i < array.length(); i++) {
                            JSONObject jnote = array.getJSONObject(i);
                            long id = jnote.optLong("id");
                            String name = jnote.optString("name");
                            Notebook nb = new Notebook(id, name);
                            notebooks.add(nb);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return notebooks;
    }

3.2.7 getNotebook()

这里同样根据给出的id获取笔记本,实际上我们目前没有用到这个方法。为了使架构完备,还是补齐它的实现:

    @Override
    public Notebook getNotebook(long notebookId) {
        // 检查登录状态及参数合法性
        String email = Utils.getUserEmail(context);
        if (notebookId <= 0 || TextUtils.isEmpty(email)) {
            return null;
        }

        OkHttpClient client = new OkHttpClient();
        // 创建包含email账号的表单,
        FormBody.Builder fb = new FormBody.Builder();
        FormBody formBody = fb.add("email", email)
                .build();
        // 创建查找笔记的请求
        Request request = new Request.Builder()
                .url(HttpHelper.getFindNotebookUrl(notebookId))
                .post(formBody)
                .build();
        Call call = client.newCall(request);

        try {
            Response response = call.execute();
            if (response != null) {
                String json = response.body().string();
                if (!TextUtils.isEmpty(json)) {
                    JSONObject jo = new JSONObject(json);
                    int code = jo.optInt("code", 0);
                    if (code == 1) {    // 提交成功
                        JSONObject jnote = jo.optJSONObject("note");
                        long id = jnote.optLong("id");
                        String name = jnote.optString("name");
                        return new Notebook(id, name);
                    } else {    // 保存失败,返回null
                        return null;
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }


        return null;
    }

3.2.8 修改对笔记本数据访问的调用

在任务6.1中实现的笔记本功能相对比较草率,忽略了对耗时操作的处理。我们来进行修正。
打开NotebooksActivity类。找到其中的onNewNotebook()方法,按如下的方式改写这个方法:

    public void onNewNotebook(View view) {
        // 创建编辑框对象
        final EditText notebookNameEdit = new EditText(this);
        AlertDialog.Builder builder = new AlertDialog.Builder(this)
                .setTitle(R.string.new_notebook)
                .setView(notebookNameEdit)  // 将编辑框对象加入对话框
                .setNegativeButton("取消", null)
                .setPositiveButton("确认", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        final String name = notebookNameEdit.getEditableText().toString();
                        if (!TextUtils.isEmpty(name)) {
                            // 异步方式处理笔记本数据提交
                            AsyncTask<Void, Void, Notebook> task = new AsyncTask<Void, Void, Notebook>() {
                                @Override
                                protected Notebook doInBackground(Void... voids) {
                                    Notebook nb = new Notebook(0, name);
                                    nb = NoteRepositoryFactory.getNoteRepository(getApplicationContext()).saveNotebook(nb);
                                    return nb;
                                }

                                @Override
                                protected void onPostExecute(Notebook notebook) {
                                    if (notebook != null) {
                                        // 插入成功,刷新笔记本列表
                                        asyncLoadNotebooks();
                                    } else {
                                        // 插入失败,提示用户
                                        Toast.makeText(NotebooksActivity.this, "保存笔记本失败", Toast.LENGTH_SHORT).show();
                                    }
                                }
                            };
                            task.execute();
                        }
                    }
                });
        builder.show();
    }

同时找到以下代码:

ArrayList<Notebook> nbs = NoteDAO.getInstance(NotebooksActivity.this.getApplicationContext()).queryAllNotebooks();

将其替换为:

ArrayList<Notebook> nbs = NoteRepositoryFactory.getNoteRepository(getApplicationContext()).getAllNotebooks();

3.2.9 在NoteRepositoryFactory中增加对ServerNoteRepository的支持

打开工厂类NoteRepositoryFactory,按如下代码改写getNoteRepository()方法:

    public static INoteRepository getNoteRepository(Context context) {
        switch (BuildConfig.USE_TEST_REPO) {
            case "test":
                return TestNoteRepository.getInstance();
            case "database":
                return NoteRepository.getInstance(context);
            case "server":
                return ServerNoteRepository.getInstance(context);
        }
        return null;
    }

3.2.10 修改build.gradle脚本

打开build.gradle文件,找到如下的区域:

    buildTypes {
     ...   
    }

改写为如下形式:

    buildTypes {

        debug {
            buildConfigField "String", "USE_TEST_REPO", '"server"'
        }

        release {
            buildConfigField "String", "USE_TEST_REPO", '"server"'
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        repoTest {
            buildConfigField "String", "USE_TEST_REPO", '"test"'
        }
    }

到此为止,基本的服务器端数据存储访问就完成了,可以运行程序体验效果。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,300评论 8 265
  • 记住:你面试的最终和最佳目标是为了获得这份工作。认清了这一点,你才能理解和体会我要说的以下几点。 一、面试前的准备...
    富姐姐阅读 696评论 0 18
  • 谁还坐在往事的船头 水尾 尝尽 苦尽甘来 谁的眼泪还连着 黄河 长江 凝似银河天上来 为什么是 拒绝 拒绝 华丽的...
    江城妖怪阅读 237评论 0 0
  • 海莎分享1 《精进》 世界上没有轻而易举的答案 周密地思考问题并不容易,有几个原因。一是我们总偏好特殊事件。比如一...
    杨啥啥阅读 155评论 0 0
  • 眼前絮絮雨滴,幕后细细连线。 落雨无力痛击疲惫的身体。 我已幻不清是现在还是过去。 苦涩的一半一半,无法替代的安逸...
    辞穷先生阅读 338评论 0 0