xUtils封装一个网络工具类
2017-05-03 13:15
393 查看
如果让你实现这样一个需求:封装一个网络工具类,用于项目的基础网络请求。然后实现如下调用:
从上面我们可以看出,网络框架工具类首先在BaseActivity里面创建得到,然后子Activity实现BaseActivity来拿到这个httpUtils来进行网络请求操作,然后通过传入请求方式、请求的JavaBean对象、请求参数、请求的Url,再定义了一个response接口,实现三个返回方法来拿到数据,在当前的activity进行UI更改操作。
下面我们就来封装这样的一个网络请求工具类。先定义成员变量:
这里,我们定义了网络请求的类型和网络返回的解析类型,最后就是看是否需要缓存Json,后面这个HttpHandler是xUtils的网络处理类,为了让大家快速的掌握xUtils网络请求,大家可以移步到xUtils源码解析。
然后呢?我们知道每一个公司都会有自己的服务器,你去做安卓开发,也不可能让你单独搞一台服务器,所以我们需要搞清楚,我们的网络请求方式及和服务器之间的通讯协议之间的传参是怎么样的,每个公司都是不一样的,所以这个是网络框架搭建比较繁琐的一个流程,建立Http请求需要三次握手,这个三次握手的每一次握手其实都做了很多事情,TCP协议的三次握手和四次挥手。
参考:http://blog.csdn.net/changcsw/article/details/52103640
有些人说三次握手和四次挥手我怎么感觉不到?那是因为三次握手和四次挥手是发生在传输层协议的,Http协议是Tcp的上层协议,我们访问网络请求,只知道拿到一个链接,在基础的Socket网络通讯中可能还需要一个端口,然后就拿到网络请求返回的状态码做操作,是接触不到三次握手和四次挥手.
然后又有人说那网络请求需要传的头部信息和Cookie是因为什么呢?
上面我们提到,每个公司都会有自己的服务器,我们的手机需要请求这样的服务器拿数据,服务器自然需要一些校验机制对一些敏感信息进行加密或者校验,来确定请求的合法性。
有了请求方法、请求参数,我们在调用时再传入Url、数据Bean、再传入一个数据返回的接口接受数据就可以了:
接下来我们就来看看基础的网络请求方式:
好了,基础的网络请求方法实现了!我们可以想到的就是数据的解析和下面的数据加密的网络请求方式的封装。
加密请求,比如RSA非对称加密,如何获取服务器返回的私钥,并保存好,然后在拿出来解析数据,并加密数据返回给服务器的呢?还有就是这个RSA私钥的过期时间限制等。
获取服务器的RSA密钥
到这里,我们的网络请求工具类就封装完成了。我们只需要按照需求传参,当然里面也用到了可变参数、泛型、反射拿到数据Bean对象等操作。
所以我接下来为大家整理了这些Java高级特性用法:
Java反射机制
Java泛型
Java泛型方法
Java泛型通配符解释
/** *这个网络工具类使用了xUtils框架包实现网络请求,我们要做到就是再封装一层。 */ newHttp.getObject(newHttp.GET, Banner.class, null,String.format(HttpUrl.NEW_AD, "app_open"),new onReuslt<Banner>() { @Override public void onSuccess( final Banner result) { // TODO Auto-generated method stub IDouKouApp.resultOk(new onOptions() { @Override public void isok() { // TODO 自动生成的方法存根 if(result.getBanners() != null && result.getBanners().size()>0){ open_banners = result.getBanners().get(0); Glide.with(IDouKouActivity.this).load(open_banners.getSrc()); } } @Override public void isNO() { // TODO 自动生成的方法存根 LogUtils.e("进入首页时显示广告界面接口失败>>>>>>>>>>>>"); } }); } @Override public void onFaild(int errCord, String errMsg) { // TODO Auto-generated method stub LogUtils.e("广告接口失败:" + errCord); } @Override public void onLoadCatch(String json) { // TODO Auto-generated method stub } }); /** * 异常拦截机制回调,定义在application类中,用于拦截网络返回的异常信息 * @param options */ public static void resultOk(onOptions options){ try { options.isok(); } catch (Exception e) { // TODO: handle exception options.isNO(); e.printStackTrace(); } }
从上面我们可以看出,网络框架工具类首先在BaseActivity里面创建得到,然后子Activity实现BaseActivity来拿到这个httpUtils来进行网络请求操作,然后通过传入请求方式、请求的JavaBean对象、请求参数、请求的Url,再定义了一个response接口,实现三个返回方法来拿到数据,在当前的activity进行UI更改操作。
下面我们就来封装这样的一个网络请求工具类。先定义成员变量:
/** * 网络请求方法的 常量 */ public final int POST = 100; public final int PUT = 200; public final int GET = 300; public final int DELETE = 400; public final int HEAD = 500; /** * 解析类型 */ private final int LIST = 1; private final int OBJECT = 2; private final int STRING = 0; /** * 是否缓存json */ public boolean isCache = false; private HttpHandler<String> startHandler;
这里,我们定义了网络请求的类型和网络返回的解析类型,最后就是看是否需要缓存Json,后面这个HttpHandler是xUtils的网络处理类,为了让大家快速的掌握xUtils网络请求,大家可以移步到xUtils源码解析。
然后呢?我们知道每一个公司都会有自己的服务器,你去做安卓开发,也不可能让你单独搞一台服务器,所以我们需要搞清楚,我们的网络请求方式及和服务器之间的通讯协议之间的传参是怎么样的,每个公司都是不一样的,所以这个是网络框架搭建比较繁琐的一个流程,建立Http请求需要三次握手,这个三次握手的每一次握手其实都做了很多事情,TCP协议的三次握手和四次挥手。
参考:http://blog.csdn.net/changcsw/article/details/52103640
有些人说三次握手和四次挥手我怎么感觉不到?那是因为三次握手和四次挥手是发生在传输层协议的,Http协议是Tcp的上层协议,我们访问网络请求,只知道拿到一个链接,在基础的Socket网络通讯中可能还需要一个端口,然后就拿到网络请求返回的状态码做操作,是接触不到三次握手和四次挥手.
然后又有人说那网络请求需要传的头部信息和Cookie是因为什么呢?
上面我们提到,每个公司都会有自己的服务器,我们的手机需要请求这样的服务器拿数据,服务器自然需要一些校验机制对一些敏感信息进行加密或者校验,来确定请求的合法性。
/** * 获取包含规则的头信息请求对象 * @return */ private RequestParams getHeaderRequestParams() { RequestParams params = new RequestParams(); // 平台信息 params.addHeader("PlatForm", android.os.Build.MODEL); // 系统-版本号 params.setHeader("System", "Android" + android.os.Build.VERSION.RELEASE); // 唯一标示符 if(getShared().getString("uuid",true) == null){ regist(new onNetWork() { @Override public void accessNetwork() { // TODO Auto-generated method stub //单纯的注册(不做任何操作); } }); } params.addHeader("UUID", getShared().getString("uuid",true)); // 应用版本号 params.addHeader("Version", IDouKouApp.getVerName()); params.addHeader("Accept", "application/json"); return params; } /** * 将Map集合转换成 Xtuils请求参数对象 * RequestParams是xUtils的一个参数封装类,我们需要拿它来传递参数 * @param params * @return */ private RequestParams getParamas(Map<String, String> params,int method) { RequestParams rquestParames = getHeaderRequestParams(); if (params != null) { for (Map.Entry<String, String> flag : params.entrySet()) { if (method == GET) { rquestParames.addQueryStringParameter(flag.getKey(),flag.getValue()); } else { rquestParames.addBodyParameter(flag.getKey(),flag.getValue()); } } } return rquestParames; } /** * 获取加密请求的参数 * @param params * @param method * @return */ private RequestParams getSecurityParamas(Map<String, String> params,int method) { RequestParams rquestParames = getHeaderRequestParams(); if (params != null) { JSONObject json = new JSONObject(); for (Map.Entry<String, String> flag : params.entrySet()) { try { json.put(flag.getKey(), flag.getValue()); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } try { json.put("stamp", System.currentTimeMillis()/1000); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } String aesKey = getShared().getString("aes_key",true); if(aesKey != null){ String body = AES.encrypt(json.toString(), aesKey); if (method == GET) { rquestParames.addQueryStringParameter("body",body); } else { rquestParames.addBodyParameter("body",body); } }else{ LogUtils.e("加密参数失败"); } } return rquestParames; }
有了请求方法、请求参数,我们在调用时再传入Url、数据Bean、再传入一个数据返回的接口接受数据就可以了:
/** * 对象结果处理接口 * @param <T> * @method onSuccess 访问网络成功方法 * @method onFailure 访问网络失败方法 * @method onStart 开始访问网络方法 */ public interface onReuslt<T> { void onLoadCatch(String json); void onSuccess(T result); void onFaild(int errCord, String errMsg); }
接下来我们就来看看基础的网络请求方式:
/** * 非加密的网络请求方法 * @param method 请求类型 * @param clazz 解析类型 * @param params 参数(可以为null) * @param url 请求的URL * @param result 返回传入的clazz对象(如果clazz为 String类型,则不解析 返回服务器结果) */ private <T> void request(final int method, final Class<?> clazz,final int type, final Map<String, String> params, final String url, final onReuslt<T> result) { loadLcaoJson(url,clazz, type,result); HttpUtils http = new HttpUtils(); com.lidroid.xutils.HttpUtils.sHttpCache.clear(); RequestParams requestParams = getParamas(params, method); startHandler = http.send(getMethod(method), url, requestParams, new RequestCallBack<String>() { @Override public void onFailure(HttpException arg0, String arg1) { // TODO Auto-generated method stub result.onFaild(arg0.getExceptionCode(), arg1); } @SuppressWarnings("unchecked") @Override public void onSuccess(ResponseInfo<String> arg0) { LogUtils.i("服务器json:" + arg0.result); result.onSuccess((T) parserJson(url,arg0.result, clazz,type, false)); } }); } /** * 加密方式访问网络请求 底层 为Xutils; * @author zhangye * @param <T> * @param method 请求方式 * @param url请求地址URL * @params context 上下文对象 * @param params 请求参数(此方法会加密参数) * @param result 结果处理接口 */ private <T> void SecurityReqeust(final int method,final Class<?> clazz, final int type,final Map<String, String> params, final String url, final onReuslt<T> result) { loadLcaoJson(url,clazz, type,result); // 异步加载参数 loadAesKey(new onNetWork() { @Override public void accessNetwork() { RequestParams rquestParames = getSecurityParamas(params, method); /** * 发起网络请求 */ com.lidroid.xutils.HttpUtils.sHttpCache.clear(); com.lidroid.xutils.HttpUtils http = new com.lidroid.xutils.HttpUtils(); /** * 连接超时时间 */ http.configSoTimeout(5 * 1000); http.configTimeout(5 * 1000); startHandler = http.send(getMethod(method), url, rquestParames, new RequestCallBack<String>() { /** * 请求失败操作处理 */ @Override public void onFailure(HttpException arg0,String arg1) { result.onFaild(arg0.getExceptionCode(), arg1); } /** * 请求成功操作处理 */ @SuppressWarnings("unchecked") @Override public void onSuccess(ResponseInfo<String> arg0) { LogUtils.i("服务器JSON:"+arg0.result); try { JSONObject json = new JSONObject(arg0.result); if(!json.isNull("state")){ if(json.getString("state").equals("outdated") || getShared().getString("aes_key", true) == null){ regist(new onNetWork(){ @Override public void accessNetwork() { // TODO Auto-generated method stub SecurityReqeust(method, clazz, type, params, url, result); } }); }else{ if((T) parserJson(url,arg0.result,clazz, type, true) == null){ result.onFaild(200, json.toString()); }else{ result.onSuccess((T) parserJson(url,arg0.result,clazz, type, true)); } } } } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 请求之前操作处理 */ @Override public void onStart() { super.onStart(); } }); } }); } /** * 发起请求(并解析成对象) * @param method * @param clazz * @param params * @param url * @param result */ public <T> void getObject(final int method, final Class<?> clazz,final Map<String, String> params, final String url, final onReuslt<T> result) { request(method, clazz, OBJECT, params, url, result); } /** * 发起请求(并解析成集合) * @param method * @param clazz * @param params * @param url * @param result */ public <T> void getList(final int method, final Class<?> clazz,final Map<String, String> params, final String url, final onReuslt<T> result) { request(method, clazz, LIST, params, url, result); } /** * 发起请求(直接返回Json字符串) * @param method * @param params * @param url * @param result */ public <T> void getString(final int method,final Map<String, String> params, final String url,final onReuslt<T> result) { request(method, String.class, STRING, params, url, result); } /** * 加密请求并解析成对象 * @param method 请求方式 * @param clazz 类型 * @param params 请求参数 * @param url 请求URL * @param result 回调接口 */ public <T> void getSecurityObject(final int method,final Class<?> clazz, final Map<String, String> params, final String url, final onReuslt<T> result) { SecurityReqeust(method, clazz, OBJECT, params, url, result); } /** * 加密请求并解析成集合 * @param method 请求方式 * @param clazz 类型 * @param params 请求参数 * @param url 请求URL * @param result 回调接口 */ public <T> void getSecurityList(final int method,final Class<?> clazz, final Map<String, String> params, final String url, final onReuslt<T> result) { SecurityReqeust(method, clazz, LIST, params, url, result); } /** * 加密请求并返回json字符串 * @param method 请求方式 * @param clazz 类型 * @param params 请求参数 * @param url 请求URL * @param result 回调接口 */ public <T> void getSecurityString(final int method,final Map<String, String> params,final String url, final onReuslt<T> result) { SecurityReqeust(method, String.class, STRING, params, url, result); }
好了,基础的网络请求方法实现了!我们可以想到的就是数据的解析和下面的数据加密的网络请求方式的封装。
/** * 解析方法 * @param json JSON串 * @param clazz 类型 * @return clazz类型的对象 */ @SuppressWarnings("unchecked") public <T> T parserJson(String url,String json, Class<?> clazz, int type,boolean isEncryption) { LogUtils.d("服务器返回的JSON:"+json); if (json != null && !json.equals("")) { try { JSONObject jsonObj = new JSONObject(json); /** * 判断是否是加密结果 */ String body = jsonObj.toString(); String aeskey = getShared().getString("aes_key",true); if (isEncryption) { body = jsonObj.getString("body"); body = AES.decrypt(body, aeskey); /** * 存储JSON(不存储非解析类型的json) */ if(type != STRING && isCache){ getShared().setString(url,body, false); } LogUtils.e("解密后的JSON:"+body); if (type == OBJECT) { return (T) JSON.parseObject(body, clazz); } if (type == LIST) { return (T) JSON.parseArray(body, clazz); } if (type == STRING) { return (T) body; } } else { /** * 存储JSON(不存储非解析类型的json) */ if(type != STRING && isCache){ getShared().setString(url, body, false); } if (type == OBJECT) { return (T) JSON.parseObject(jsonObj.toString(), clazz); } if (type == LIST) { return (T) JSON.parseArray(jsonObj.toString(), clazz); } if (type == STRING) { return (T) jsonObj.toString(); } } } catch (JSONException e) { LogUtils.e("错误的JSON:" + json); } catch (Exception e){ LogUtils.e("解析错误:" + json); } } return null; } /** * 读取本地JSON * @param <T> * @param clazz * @param type */ private <T> void loadLcaoJson(final String url,final Class<?> clazz,final int type,final onReuslt<T> result){ IDouKouApp.resultOk(new onOptions() { @Override public void isok() { // TODO Auto-generated method stub String json = getShared().getString(url,false); LogUtils.i("类型"+clazz.getSimpleName()+"加载本地JSON缓存:"+json); if(json != null){ result.onLoadCatch(json); } } @Override public void isNO() { // TODO Auto-generated method stub } }); } /** * 判断请求方式 * @author zhangye * @param method * @return */ private HttpMethod getMethod(int method) { HttpMethod xmethod = HttpMethod.POST; if (method == PUT) { xmethod = HttpMethod.PUT; } else if (method == POST) { xmethod = HttpMethod.POST; } else if (method == GET) { xmethod = HttpMethod.GET; } else if (method == DELETE) { xmethod = HttpMethod.DELETE; } return xmethod; }
加密请求,比如RSA非对称加密,如何获取服务器返回的私钥,并保存好,然后在拿出来解析数据,并加密数据返回给服务器的呢?还有就是这个RSA私钥的过期时间限制等。
/** * 网络获取时间回调接口,得到百度服务器的时间毫秒值 * @author zhangye */ private interface onTime { void onGetTime(Long time); }
获取服务器的RSA密钥
/** * 得到服务器的AES_KEY,结果处理接口 * @author zhangye * @date 2015年4月1日 17:57:02 */ private void loadAesKey(final onNetWork network) { /** * 获取网络时间后进行判断操作 */ getNetTime(new onTime() { @Override public void onGetTime(Long time) { /** * 得到上次获取密钥的时间 */ long oldTime = getShared().getLong("key_time"); LogUtils.d("得到上次获取密钥的时间:" + oldTime); /** * 判断密钥是否为空或过期 2592000 代表间隔为一个月 */ if (getShared().getString("aes_key",true) == null || ((time - oldTime) / 1000) > 2592000 || getShared().getString("uuid",true) == null) { /** * 与服务器交换密钥并执行后续网络请求 */ regist(network); } else { /** * 直接发起网络请求 */ network.accessNetwork(); } } }); } /** * 跟服务器端交换密钥 * @author zhangye * @param network 结果处理接口 * @desc 保证获取密钥之前,不会进行其他网络操作; */ private void regist(final onNetWork network) { getNetTime(new onTime() { @Override public void onGetTime(final Long time) { /** * 生成public,private密钥 */ Map<String, String> keys = RSA.genNewKeys(SharedUtils.NEW_RSA); /** * 生成随机UUID */ getShared().setString("uuid", IDouKouApp.getRadomUUID(),true); /** * 初始化Xutils网络请求参数 */ RequestParams params = getHeaderRequestParams(); params.addBodyParameter("uuid", getShared().getString("uuid",true)); params.addBodyParameter("public_key",keys.get(RSA.PUBLIC_KEY_NAME)); /** * 发起网络请求 交换public密钥并附带UUID */ com.lidroid.xutils.HttpUtils http = new com.lidroid.xutils.HttpUtils(); /** * 需要修改URL */ startHandler = http.send(HttpMethod.POST, HttpUrl.NEW_BIN_REGIST, params, new RequestCallBack<String>() { @Override public void onFailure(HttpException arg0,String arg1) { LogUtils.e("网络错误:" + arg1); } @Override public void onSuccess(ResponseInfo<String> arg0) { String resetCode = ""; LogUtils.d("与服务器交换密钥结果:" + arg0.result); JSONObject jsonObject; try { jsonObject = new JSONObject(arg0.result); if (!jsonObject.isNull("state")) { resetCode = jsonObject.getString("state"); } if (resetCode.equals("OK")) { getShared().setLong("key_time", time); getShared().setString("aes_key",RSA.decrypt(jsonObject.getString("aes_key"), SharedUtils.NEW_RSA),true); network.accessNetwork(); } else { /** * 验证失败操作 {} */ } } catch (JSONException e) { e.printStackTrace(); } } }); } }); }
到这里,我们的网络请求工具类就封装完成了。我们只需要按照需求传参,当然里面也用到了可变参数、泛型、反射拿到数据Bean对象等操作。
所以我接下来为大家整理了这些Java高级特性用法:
Java反射机制
Java泛型
Java泛型方法
Java泛型通配符解释
相关文章推荐
- linux网络编程之System V 信号量(一):封装一个信号量集操作函数的工具
- swift-自己封装的一个网络工具
- linux网络编程之System V 信号量(一):封装一个信号量集操作函数的工具
- 一个用于网络的工具函数库
- iReaper_1.2_release 下载MSDN WebCast网络讲座的一个好工具
- cocos2d-x封装一个转码的工具解决中文乱码可以直接拖过去用通用跨平台
- block传值以及利用block封装一个网络请求类
- 一个基于http协议的访问网络的封装类
- 封装的工具类(网络获取Json,图片,下载图片,下载Mp3,下载视频)
- 介绍一个监控网卡及网络流量的好工具NICSTAT
- wget用法wget是一个从网络上自动下载文件的自由工具。它支持HTTP,HTTPS和FTP协议,可以使用HTTP代理.
- 安卓学习-其他-http网络工具-用了xutils
- 一个网络爱好者网络工具(完善中) 推荐
- java封装的jad1.5.8g反编译工具(java如何打开一个选择框)
- 推荐一个很好用的网络备份工具Dropbox。
- 分享一个好用的免费查找PCB封装尺寸的软件工具
- 一个用于网络的工具函数库
- 71%的网络攻击都与同一个黑客工具包有关
- Wireshark:一个好用的网络数据包查看工具
- 开源自己用python封装的一个Windows GUI(UI Automation)自动化工具,支持MFC,Windows Forms,WPF,Metro,Qt