Maven环境 :

      <dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.1</version>
</dependency> <dependency>
<groupId>com.squareup.okhttp</groupId>
<artifactId>logging-interceptor</artifactId>
<version>2.7.5</version>
</dependency>

logging-interceptor 是Okhttp拦截器,用于打印 Log 日志。

代码 :

我采用的是实体类请求方式,一般请求都是使用HashMap作为Formbody,我来说一下我这么做的原因 :
1. 如果参数有改动,那么HashMap的 put 方法是不会报错的,而实体类的set会报错,这在代码量大,复杂的时候很容易维护。
2. HashMap 的put需要手动填写Key值,这毫无疑问是影响编码体验和效率的,特别是在请求参数繁杂的情况下。

通用请求工具类 :

public class OkHttpUtil {

    private static OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new LoggingInterceptor()).build();

    public static Response sendPostRequest(String url, Object parameter) throws IOException {

        Map<String, Object> map = ReqUtil.ParameToMap(parameter);

        //动态添加参数
FormBody.Builder params = new FormBody.Builder();
//遍历参数,KV对应。
for (Map.Entry<String, Object> mapping : map.entrySet()) {
params.add(mapping.getKey(), String.valueOf(mapping.getValue()));
} Request request = new Request.Builder()
.url(url)
.post(params.build())
.build(); return okHttpClient.newCall(request).execute();
}
}

这里的 ReqUtil.ParameToMap(parameter) 会对传入的对象进行反射获取所有属性和值并转换成HashMap。

addInterceptor(new LoggingInterceptor()).build() 加入请求日志拦截器。

对象转HashMap ParameToMap 工具类

class ReqUtil {
@SuppressWarnings("unchecked")
static <K, V> Map<K, V> ParameToMap(Object javaBean) {
Map<K, V> ret = new HashMap<K, V>();
try {
Method[] methods = javaBean.getClass().getDeclaredMethods();
for (Method method : methods) {
if (method.getName().startsWith("get")) {
String field = method.getName();
field = field.substring(field.indexOf("get") + 3);
field = field.toLowerCase().charAt(0) + field.substring(1);
Object value = method.invoke(javaBean, (Object[]) null);
ret.put((K) field, (V) (null == value ? null : value));
}
}
} catch (Exception e) {
}
return ret;
}
}

请求拦截器,打印请求信息及 Formbody :

public class LoggingInterceptor implements Interceptor {
private Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class); public Response intercept(Chain chain) throws IOException {
// 这个chain里面包含了request和response,所以你要什么都可以从这里拿
Request request = chain.request(); long t1 = System.nanoTime();// 请求发起的时间
logger.info(String.format("发送请求 %s on %s%n%s", request.url(), chain.connection(), request.headers()));
// logger.info("请求参数:{\n +" + request.body().writeTo(); + "\n}");
StringBuilder bodyLog = new StringBuilder();
if (request.body() instanceof FormBody) {
FormBody body = (FormBody) request.body();
for (int i = 0; i < body.size(); i++) {
bodyLog.append(body.encodedName(i)).append("=").append(body.encodedValue(i)).append(",");
}
bodyLog.delete(bodyLog.length() - 1, bodyLog.length());
logger.info("请求参数:" + bodyLog.toString());
}
// System.out.println(String.format("发送请求 %s on %s%n%s", request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request); long t2 = System.nanoTime();// 收到响应的时间 // 这里不能直接使用response.body().string()的方式输出日志
// 因为response.body().string()之后,response中的流会被关闭,程序会报错,我们需要创建出一
// 个新的response给应用层处理
ResponseBody responseBody = response.peekBody(1024 * 1024); logger.info(String.format("接收响应: [%s] %n返回json:【%s】 %.1fms%n%s", response.request().url(),
responseBody.string(), (t2 - t1) / 1e6d, response.headers())); return response; } }

使用 :

 public static ResponseBody registerUser(RegisterParameter registerParameter) throws IOException {
return OkHttpUtil.sendPostRequest(Origin.register, registerParameter).body();
}

效果 :

Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2dd98b52]
2019-06-03 21:29:28.367 INFO 7884 --- [p-nio-80-exec-3] c.s.g.m.n.r.LoggingInterceptor : 发送请求 https://api.ttlock.com.cn/v3/user/list on null
2019-06-03 21:29:28.367 INFO 7884 --- [p-nio-80-exec-3] c.s.g.m.n.r.LoggingInterceptor : 请求参数:date=1559568568366,clientId=63eb3d5111b443969f4224cb2db65076,endDate=0,pageNo=1,pageSize=10,clientSecret=17a8d3cc6227e79fdeb3ee09f9bf5f8b,startDate=0
2019-06-03 21:29:28.621 INFO 7884 --- [p-nio-80-exec-3] c.s.g.m.n.r.LoggingInterceptor : 接收响应: [https://api.ttlock.com.cn/v3/user/list]
返回json:【{"list":[{"regtime":1559529910000,"userid":"testbl_23"},{"regtime":1559461353000,"userid":"testbl_admin"},{"regtime":1559529920000,"userid":"testbl_admin4"}],"pageNo":1,"pageSize":10,"pages":1,"total":3}】 254.3ms
Server: Tengine
Date: Mon, 03 Jun 2019 13:29:30 GMT
Content-Type: application/json;charset=utf-8
Content-Length: 203
Connection: keep-alive

关于JSON解析嵌套实体类 :

在 Json 解析这方面,JSONObject 是出场率最高的,但JSONObject 处理解析嵌套数据格式的时候就有些差强人意了,比如这种 :

@Data
public class UserPage { private int pageNo;
private int pageSize;
private int pages;
private int total;
private List<User> list; }
{
"list":[
{
"regtime":1559529910000,
"userid":"testbl_23"
},
{
"regtime":1559461353000,
"userid":"testbl_admin"
},
{
"regtime":1559529920000,
"userid":"testbl_admin4"
}
],
"pageNo":1,
"pageSize":10,
"pages":1,
"total":3
}

如果用 JSONObject解析,List<User> 值会是null,而使用Gson则可以完美解析,不愧是Google家的东西,写的真周全。

Okhttp3 网络请求框架与 Gson的更多相关文章

  1. 一步步搭建Retrofit+RxJava+MVP网络请求框架(二),个人认为这次封装比较强大了

    在前面已经初步封装了一个MVP的网络请求框架,那只是个雏形,还有很多功能不完善,现在进一步进行封装.添加了网络请求时的等待框,retrofit中添加了日志打印拦截器,添加了token拦截器,并且对Da ...

  2. Android网络请求框架

    本篇主要介绍一下Android中经常用到的网络请求框架: 客户端网络请求,就是客户端发起网络请求,经过网络框架的特殊处理,让后将请求发送的服务器,服务器根据 请求的参数,返回客户端需要的数据,经过网络 ...

  3. App 组件化/模块化之路——如何封装网络请求框架

    App 组件化/模块化之路——如何封装网络请求框架 在 App 开发中网络请求是每个开发者必备的开发库,也出现了许多优秀开源的网络请求库.例如 okhttp retrofit android-asyn ...

  4. XDroidRequest网络请求框架,新开源

    XDroidRequest 是一款网络请求框架,它的功能也许会适合你.这是本项目的第三版了,前两版由于扩展性问题一直不满意,思考来 思考去还是觉得Google的Volley的扩展性最强,于是借鉴了Vo ...

  5. Flutter学习(7)——网络请求框架Dio简单使用

    原文地址: Flutter学习(7)--网络请求框架Dio简单使用 | Stars-One的杂货小窝 Flutter系列学习之前都是在个人博客发布,感兴趣可以过去看看 网络请求一般APP都是需要的,在 ...

  6. Android 网络请求框架android-async-http问题

    今天通过接口请求服务器的一些app数据,发现一个很奇怪的问题,请求一个链接的时候,通常在第一次请求发起的时候没有什么问题,能很快的拿到数据,但是 往后再去请求的时候就会等待很久,而且最后会请求失败,一 ...

  7. 基于Retrofit+RxJava的Android分层网络请求框架

    目前已经有不少Android客户端在使用Retrofit+RxJava实现网络请求了,相比于xUtils,Volley等网络访问框架,其具有网络访问效率高(基于OkHttp).内存占用少.代码量小以及 ...

  8. Volley网络请求框架的基本用法

    备注: 本笔记是参照了 http://blog.csdn.net/ysh06201418/article/details/46443235  学习之后写下的 简介:  Volley是google官网退 ...

  9. Android网络请求框架AsyncHttpClient实例详解(配合JSON解析调用接口)

    最近做项目要求使用到网络,想来想去选择了AsyncHttpClient框架开进行APP开发.在这里把我工作期间遇到的问题以及对AsyncHttpClient的使用经验做出相应总结,希望能对您的学习有所 ...

随机推荐

  1. Charles抓包工具_基本功能

    一. 安装及破解 1. 安装: 下载地址:http://www.charlesproxy.com/download/,然后进行安装: 2. 破解: 将补丁文件charles.jar复制到安装目录并替换 ...

  2. Ruby中的数值

    数值类型 Ruby中所有数值都是Numeric类的子类对象,数值都是不可变对象. 数值类型的继承关系如下: Integer是整数,Float是浮点数类型,Rational是分数. 对于整数,要么是Fi ...

  3. HDU 5117:Fluorescent(状压DP + 思维)***

    题目链接 题意 给出n个灯,m个开关,每个开关控制一些灯,如果打开这个开关,这个开关控制的灯如果本来灭的就会亮,如果本来亮的就会灭.问在每个开关按下与否的一共2^m情况下,每种状态下亮灯的个数的立方的 ...

  4. NEST 6.X升级到7.X

    升级比对可访问 NEST 6.X升级到7.X 查看 ElasticClient-CreateIndex 升级前代码,NEST版本6.6.0 ICreateIndexResponse response ...

  5. redis RDB 和AOF

    参考文献 Redis源码学习-AOF数据持久化原理分析(0) Redis源码学习-AOF数据持久化原理分析(1) Redis · 特性分析 · AOF Rewrite 分析 深入剖析 redis AO ...

  6. ASP.NET Core系列(一): .NET Core简介及安装开发环境

    大家都知道Java是跨平台的,.NET因为不具有跨平台的特性,被越来越多的开发者诟病,之前有各种间接的跨平台的方案,比如mono.但是由于各种兼容问题,最终 .NET Core出现了,它可以让程序在W ...

  7. xfs 文件系统修复

    pvcreate /dev/sdb1 pvcreate /dev/sdc1 pvcreate /dev/sdd1 vgcreate vg_bricks /dev/sdb1 vgcreate vg_br ...

  8. WinForm控件之【MonthCalendar】

    基本介绍 日期月历控件,顾名思义用来主要用来展示月历,获取年份.月份.日期.时分秒信息等 常设置属性 FirstDayOfWeek:面板展示周期的循序,一周的第一天由从周几开始排列: MaxDate: ...

  9. python函数知识一 函数初始、定义与调用、返回值、参数和函数的好处+菜中菜

    第四章 函数 1.函数初识: def :关键字 -- 定义 函数名:和变量的定义方式一样 (): 用于参数传递,: 形参:函数的定义中()内的是形参 实参:调用的()内是实参 传参:调用时将实参传递给 ...

  10. 个人永久性免费-Excel催化剂功能第18波-在Excel上也能玩上词云图

    这年头数据可视化日新月异,在Excel上做数据分析,最后一步,难免要搞个图表输出高大上一回,微软也深知此道,在Excel2016上更新了一大波图表功能,市场上很耀眼的词云图还是没加进来,虽然在各大的在 ...