zoukankan      html  css  js  c++  java
  • android移动开发学习笔记(二)神奇的Web API

    本次分两个大方向去讲解Web Api,1、如何实现Web Api?2、如何Android端如何调用Web Api?对于Web Api是什么?有什么优缺点?为什么用WebApi而不用Webservice?这些问题都不去解答,百度一下,关于这方面的资料很多,就不再去啰嗦。

    一、如何在web端实现WebApi

    (1)如何新建一个WebApi?

    在上一章中,讲到我们项目用的是.net 4.5,开发工具是Visual Studio 2012,在Visual Studio 2012中新建MVC4项目,选择Web API,然后项目生成,如下图一、图二、图三所示, 和普通的MVC项目相比,它继承了ApiController,然后我们运行一下项目,在浏览器里输入http://localhost:56091/api/values/get?id=5,如图四所示,即成功调用了项目默认写的Get方法实例,有数据返回即表示调用成功!

    data-cke-saved-src=/uploadfile/Collfiles/20140905/20140905091104233.png

    (图一)

    data-cke-saved-src=/uploadfile/Collfiles/20140905/20140905091105234.png

    (图二)

    data-cke-saved-src=/uploadfile/Collfiles/20140905/20140905091105235.png

    (图三)

    data-cke-saved-src=/uploadfile/Collfiles/20140905/20140905091105236.png

    (图四)

    (2)Get和Post数据?

    (2.1) Get方法

    具体什么是Get就不再啰嗦了,可以自己百度查看, 使用 [HttpGet]标识,当然也可以不用加,只需要方法名用Get开头,Get方法是使用Url参数传递的,不能接收实体参数,如:http://localhost:56091/api/values/get?id=5,id即是参数,当然也可以多参数,如:http://localhost:56091/api/values/get?id=5&name=tim ,默认参数使用[FromUri]

    Get是有长度限制的,参数不能过多,而且参数暴露在外面,容易被人很方便的截取。

    (2.2)Post方法

    使用 [HttpPost]方式传递,当然也可以不用加,只需要方法名用Post开头,Post方法可以使用Url传递参数,也可以用Body传递参数,默认参数使用[FromUri],可以加[FromBody]接收body里传递的参数,但是有问题的是,我使用[FromBody]方式,参数为空,根本接收不动值,上网查了资料,很多人遇到问题,不知道是不是Web Api本身的问题,无奈只好使用下面最原始的方式了,获取Body的值了。

    1
    2
    3
    4
    5
    6
    7
    HttpContextBase context = (HttpContextBase)Request.Properties[MS_HttpContext];//获取传统context
    HttpRequestBase request = context.Request;//定义传统request对象
    string name = request.Form.Keys[0];
    if (name == null)
    {
        name = request.Form[0];
    }

    另外Post的方法不能直接在浏览器里敲地址获取数据,调试起来不是很方便,所以用了一个工具,火狐浏览器可以安装一个插件,叫Poster,如下图六所示,测试起来很方便。

     

    data-cke-saved-src=/uploadfile/Collfiles/20140905/20140905091105237.png

    (图五)

    data-cke-saved-src=/uploadfile/Collfiles/20140905/20140905091105238.png

    (图六)

    (3)Json数据格式?

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。

    Json数据格式传输是目前接口数据传输主流,本次我们的项目也是使用Json格式数据,我们所有的接口参数都是统一的参数名,后面跟的是Json格式字符串,如:http://localhost:8010/api/MobileInfo/Get_Welcome? params=JsonString,这是接口的调用,接口返回结果也是Json格式。

    如下图七所示,使用Newtonsoft.Json类库,这是VS项目集成的类库,可以很方便的使用JsonConvert.SerializeObject(value)方法,将object对象转换为Json格式。

    data-cke-saved-src=/uploadfile/Collfiles/20140905/20140905091106239.png

    (图七)

    1
    2
    3
    //step2:参数反序列化
    T transferObj = default(T);
    transferObj = Newtonsoft.Json.JsonConvert.DeserializeObject<t>(JsonString);</t>

    (4) 路由的配置

    如下图八所示,默认路由配置是这样,只会找到Controller,不用根据Action去分配地址,所以相同Controller下只会找到Get方法或Post方法,不管你方法名是否相同,这样很明显不能满足我们的需求,如果想以Action去标识地址,就用下面代码配置:

    1
    2
    3
    4
    5
    config.Routes.MapHttpRoute(
        name: CommonApi,
        routeTemplate: api/{controller}/{action}/{id},
        defaults: new { id = RouteParameter.Optional }
    );

    data-cke-saved-src=/uploadfile/Collfiles/20140905/20140905091106240.png

    (图八)

    二、如何在Android端调用WebApi

    (1)调用web Api的Get方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public void getAnnouncement(final Object reqTag, final WSAnnouncementListCb cb) {
     
         //需要调用WebApi的Url地址  参数用UTF-8编码        String url = Constants.WEB_BASE_URL
                + MobileInfo/Get_AnnouncementList?JsonString=
                + Utils.getEncodingParamsString((Object) UserManager.getInstance()
                        .getLoginedUserInfo());
     
        //使用Request对象,请求数据  Mdthod.Get WsAnnouncementListRsp.class接收结果的对象实体类        GsonRequest<wsannouncementlistrsp> gsonRequest = new GsonRequest<wsannouncementlistrsp>(
                Method.GET, url, WSAnnouncementListRsp.class,
                new Response.Listener<wsannouncementlistrsp>() {
                    @Override
                    public void onResponse(WSAnnouncementListRsp rsp) {
                //返回的Json格式数据,经过反序列化后的对象实体                        if (cb != null) {
                            cb.onResponse(Utils.stringToInteger(rsp.message.ResultCode), rsp);
                        }
                    }
     
                }, errorListener(true));
     
        gsonRequest.setRequestTag(reqTag);
     
        RequestManager.addRequest(gsonRequest, reqTag);
    }</wsannouncementlistrsp></wsannouncementlistrsp></wsannouncementlistrsp>

    Android反序列化Json的方法:

    当然下面代码中包含判断Token是否过期,过期之后重新登录,因为判断Token是否过期是每个App接口都可能要考虑的事情,所以就没有删除,以供大家参考。

    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
    //Response的时候,返回解析后的对象
     protected Response<t> parseNetworkResponse(NetworkResponse response) {
            try {
     
                //接收到的Json格式数据字符串
                String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                //如果有转义字符就替换她
                json = json.substring(1, json.length() - 1);
                json = json.replace(\, );
                Log.I(L, Response type: + mClazz.getName() + Parsed Json Buffer:  + json);
                 
                //反序列化Json数据
                WSBaseResponse baseResponse = (WSBaseResponse) mGson.fromJson(json, mClazz);
                //判断Token是否过期
                if (Utils.stringToInteger(baseResponse.message.ResultCode) == Constants.ERR_TOKEN_INVALID) {
    //                Log.I(L, get token status: + UserManager.getInstance().getTokenStatus());
    //                if (UserManager.getInstance().getTokenStatus() != TOKEN_STATUS.TOKEN_GETTING) {
    //                    Log.I(L,set token status: + TOKEN_STATUS.TOKEN_EXPIRED);
    //                    UserManager.getInstance().setTokenStatus(TOKEN_STATUS.TOKEN_EXPIRED);
    //                }
     
                    synchronized (GsonRequest.class) {
                        if (UserManager.getInstance().getTokenStatus() != TOKEN_STATUS.TOKEN_GETTING) {
                            Log.I(L,  relogin ...);
                                                
                            RequestManager.addCachedRequest(this);
     
                            UserManager.getInstance().relogin(new OnLoginListener() {
     
                                @Override
                                public void onLogin(int result, String message) {
                                    if (result == UserManager.LOGIN_RESULT_OK) {
                                        Log.I(L, Login suceesss);
                                         
                                        UserManager.getInstance().setTokenStatus(TOKEN_STATUS.TOKEN_OK);
                                       
                                         
                                    } else {
                                        Log.I(L,Login failed...);
                                        // Show login activity
                                        UserManager.getInstance().setTokenStatus(TOKEN_STATUS.TOKEN_FAIL);
                                        MyActivityManager.getInstance().finishAllActivity();
                                        showLoginActivity();
                                    }
                                }
                            });
                        } else {
                            //
                            Log.I(L, prepare resend request);
                           // reSendRequest();
                            RequestManager.addCachedRequest(this);
                        }
     
                    }
     
                    return Response.error(new TokenExpiredError());
                } else {
     
                    //返回泛型对象
                    return Response.success((T) baseResponse/*
                                                             * mGson.fromJson(json,
                                                             * mClazz)
                                                             */,
                            HttpHeaderParser.parseCacheHeaders(response));
                }
     
            } catch (UnsupportedEncodingException e) {
                Log.E(L, response parse error: + mClazz.getName());
                return Response.error(new ParseError(e));
            } catch (JsonSyntaxException e) {
                Log.E(L, response parse error: + mClazz.getName());
                return Response.error(new ParseError(e));
            }
        }
    </t>

    (2)调用web Api的Post方法

    放在Url里的和Get方法一样调用,只是传参的时候,把Method.Get改为Method.Post方式,

    因此主要讲Post的Body方法

    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
    public void updateUserInfo(final Object reqTag, final WSUpdateUserInfoReq req,
            final WSUpdateUserInfoCb cb) {
     
        setUserIdAndTokenForReq(req);
     
        // post Url不带任何参数
        String url = Constants.WEB_BASE_URL + MobileInfo/Save_EmployeeInfo;
    //req是参数
        GsonRequest<wscommonrsp> gsonRequest = new GsonRequest<wscommonrsp>(
                Method.POST, url,Utils.getEncodingParamsString((Object) req), WSCommonRsp.class,
                null, new Response.Listener<wscommonrsp>() {
                    @Override
                    public void onResponse(WSCommonRsp rsp) {
                        if (cb != null) {
                            cb.onResponse(Utils.stringToInteger(rsp.message.ResultCode), rsp);
                        }
                    }
     
                }, errorListener(true));
     
        gsonRequest.setRequestTag(reqTag);
     
        RequestManager.addRequest(gsonRequest, reqTag);
     
    }</wscommonrsp></wscommonrsp></wscommonrsp>

    以上就是App接口的实现和接口在Android中的调用方法,我提供的都是一些伪代码,主要是讲解功能实现的思想和用到哪些重要的类方法。下章则正式学习Android开发,看一个零基础的菜鸟如何快速上手做开发的。

  • 相关阅读:
    laravel blog 一
    dede:channelartlist currentstyle高亮显示
    dede调用导航/幻灯
    rmp 安装LNMP环境
    无极分类之子孙树、父辈树
    创始人 密码
    mysql报错显示法文解决办法
    渐变色背景
    laravel sendmail
    工作流系统webservice服务
  • 原文地址:https://www.cnblogs.com/yzycoder/p/6084139.html
Copyright © 2011-2022 走看看