工作中跟客户端沟通时产生了点问题, 记录一下.
起因
后端有一个接口是这样的
@RequestMapping("android")
public BaseResult android(@RequestBody RequestData requestData) {
}
RequestData.java
package com.junbaor.network.model;
public class RequestData {
private Integer id;
private String name;
// 省略 get set
}
如果使用 http://localhost:8080/android?id=1&name=张三
是调不通的
只能处理 Content-Type 为 application/json 的请求, 需要把参数放在 post 请求体内
{
"id":1,
"name":"张三"
}
问题
客户端使用第一种方式调不通, 告知需把参数转成 json 对象放到请求体内,
反馈说之前都是按照第一种方式调用的接口, 做不到第二种。
解决
后端没有找到优雅的解决方式, 被迫修改接口实现, 之所以继续保留 requestData 是为了兼容其它调用方.
@RequestMapping(value = "android")
public BaseResult android(@RequestBody(required = false) RequestData requestData,
@RequestParam(required = false) Integer id,
@RequestParam(required = false) String name) {
// 处理逻辑时先判断 requestParam 是否有值, 没有的话再从 requestData 取
}
研究 Android
long long ago 写过一点 Android , 不太相信想自己试试。
打听后得知客户端的网络框架是 Retrofit 配合 OkHttp。
开始研究 Android, 安装环境就不说了。
引包
先引入客户端使用的网络框架, 使用的都是最新版, 由于数据是 json 格式再引入 gson 库(虽然不知道他们用的是什么解析库). converter-gson 是 retrofit2 的工具包, 用来把 json 封装成对象.
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.okhttp3:okhttp:3.9.1'
compile 'com.google.code.gson:gson:2.8.2'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
编码
// OkHttp 请求日志拦截器
HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
System.out.println(message);
}
});
logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
// OkHttp 客户端
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(2, TimeUnit.MILLISECONDS)
.addNetworkInterceptor(logInterceptor)
.build();
// 把后台返回的时间戳转成 java.util.Date
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new GsonDateTypeAdapter()).create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://127.0.0.1:8080")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
//请求参数
RequestData requestData = new RequestData();
requestData.setId(1);
requestData.setName("张三");
TestService testService = retrofit.create(TestService.class);
Call testServiceReslut = testService.getTestResult(requestData);
testServiceReslut.enqueue(new Callback<ResponseData>() {
@Override
public void onResponse(Call<ResponseData> call, Response<ResponseData> response) {
System.out.println("响应成功, 数据:" + response.body());
}
@Override
public void onFailure(Call<ResponseData> call, Throwable t) {
System.out.println("响应失败, 原因:" + t.getMessage());
}
});
源码
参见:https://github.com/junbaor/an...
Android 端重点关注:com.junbaor.network.NetworkTest
Server 端重点关注:com.junbaor.network.NetworkApplication
花絮
Gson 时间戳转 Date
GsonDateTypeAdapter.java
package com.junbaor.network.extend;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.util.Date;
/**
* Created by junbaor on 2017/12/13.
*
* 将后台返回的时间戳转成 java.util.Date
* 参见: https://stackoverflow.com/questions/41348055/gson-dateformat-to-parse-output-unix-timestamps
*/
public class GsonDateTypeAdapter extends TypeAdapter<Date> {
@Override
public void write(JsonWriter out, Date value) throws IOException {
if (value == null) {
out.nullValue();
} else {
out.value(value.getTime() / 1000);
}
}
@Override
public Date read(JsonReader in) throws IOException {
if (in != null) {
return new Date(in.nextLong() / 1000);
} else {
return null;
}
}
}
okhttp 日志打印
在网上找到了这个 https://github.com/square/okh...
由于没有 logger 实现, 打印的比较凌乱, 索性把代码拷到项目中以便修改, 用控制台输出实现了 logger 接口
// OkHttp 日志拦截器
HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
System.out.println(message);
}
});
logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
日志效果:
--> POST http://127.0.0.1:8080/android http/1.1
Content-Type: application/json; charset=UTF-8
Content-Length: 24
Host: 127.0.0.1:8080
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: okhttp/3.9.1
{"id":1,"name":"张三"}
--> END POST (24-byte body)
<-- 200 http://127.0.0.1:8080/android (15ms)
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 13 Dec 2017 16:05:49 GMT
{"code":200,"message":"成功","data":{"id":1,"name":"张三","birthday":1513181149729}}
<-- END HTTP (88-byte body)
响应成功, 数据:BaseResult{code=200, message='成功', data=ResponseData{id=1, name='张三', birthday=Sun Jan 18 20:19:41 CST 1970}}