Retrofit是一款基于OKHttp的restful的网络请求框架。支持异步和同步请求,看到异步有么有两眼放光,服务器开发者可能会吐槽说:view层和后端服务之间通过ajax异步请求,你这异步有nuan用? 咳咳!Android用啊!大家可以看到很多入门教程都是针对android。但是,但是retrofit实在是太好用了,而且你怎么确定你一定不会用到异步的应用场景(当然你可以自己写线程)。retrofit通过接口注解,扩展性非常好,支持多种数据格式json,xml,string,protobuf,以及基于okhttp哦!赶紧抛弃你的httpclinet,来拥抱retrofit。
这里不做概念及入门介绍,完全陌生的请看官方文档。
下面的样例来让你快速使用在自己的项目中而不是学习。下面的样例只讲,get,post/json,看完该样例,对于什么上传文件,form表单等绝对的轻车熟路。
项目使用meavn进行管理,引入retrofit2.0,及okhttp3.0
<dependency>
<groupId>com.squareup.retrofit2groupId>
<artifactId>retrofitartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>com.squareup.retrofit2groupId>
<artifactId>converter-gsonartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>com.squareup.retrofit2groupId>
<artifactId>converter-scalarsartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>com.squareup.retrofit2groupId>
<artifactId>converter-simplexmlartifactId>
<version>2.0.2version>
dependency>
<dependency>
<groupId>com.squareup.okhttp3groupId>
<artifactId>logging-interceptorartifactId>
<version>3.2.0version>
dependency>
老生常谈,retrofit依然是使用动态代理,只需要实现接口,仅此而已。业务分层,代码扩展性好。
package com.ccycc.retrofit.network.infs;
import com.ccycc.retrofit.vo.ReqVo;
import com.ccycc.retrofit.vo.RespVo;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface TestService {
// 接口1
@GET("ccycc88/article/details/79759172")
Call getCsdn();
//接口2
@GET("ccycc88/article/details/{userID}")
Call getCsdn(@Path(value = "userID") String id);
//接口3
@GET("ccycc88/article/details/79759172")
Call getCsdnBody();
//接口4
@POST("admin/v1/transformIncomeDetail")
Call postJson(@Body ReqVo vo);
//接口5
@GET("cgi-bin/token?grant_type=client_credential")
Call getAccessToken(@Query("appid") String appid, @Query("secret") String secret);
//接口6
@Headers({"Content-Type: application/json","Accept: application/json"})
@POST("cgi-bin/message/custom/send")
Call sendMessage(@Query("access_token") String accessToken, @Body RequestBody body);
}
无聊,因此为每个接口起了别名。
接口中@Path什么时候用? 如接口2,请求地址为:…/ccycc88/article/details/{userID} == …/ccycc88/article/details/123
接口中@Query什么时候用? 如接口5, 请求地址为: …/cgi-bin/token?grant_type=client_credential == cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret。
@Path用于请求地址中的一部分,@Query用于请求参数。
为什么会有接口1样例?因为苦苦找了好久都没找到如何返回字符串样例。
于是为大家提供两种返回字符串的两种方式如:接口1和接口3。
咳!那最最最最最常用的restful风格呢?
见接口4与接口6。
package com.ccycc.retrofit.vo;
/**
*请求对象
*/
public class ReqVo {
private int pageNum = -1;
private int displayNum = -1;
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getDisplayNum() {
return displayNum;
}
public void setDisplayNum(int displayNum) {
this.displayNum = displayNum;
}
}
package com.ccycc.retrofit.vo;
import java.util.List;
//响应对象
public class RespVo {
private int errorCode = -1;
private String errorMsg = null;
private Data data = null;
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
public class Data{
int totalNum = -1;
List rows = null;
public int getTotalNum() {
return totalNum;
}
public void setTotalNum(int totalNum) {
this.totalNum = totalNum;
}
public List getRows() {
return rows;
}
public void setRows(List rows) {
this.rows = rows;
}
public class Row{
String balanceType = null;
long memberId = -1l;
String model = null;
int perIncome = -1;
String transferId = null;
String transferTime = null;
String username = null;
public String getBalanceType() {
return balanceType;
}
public void setBalanceType(String balanceType) {
this.balanceType = balanceType;
}
public long getMemberId() {
return memberId;
}
public void setMemberId(long memberId) {
this.memberId = memberId;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public int getPerIncome() {
return perIncome;
}
public void setPerIncome(int perIncome) {
this.perIncome = perIncome;
}
public String getTransferId() {
return transferId;
}
public void setTransferId(String transferId) {
this.transferId = transferId;
}
public String getTransferTime() {
return transferTime;
}
public void setTransferTime(String transferTime) {
this.transferTime = transferTime;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
}
}
//请求参数
{
"pageNum":1,
"displayNum":1
}
//响应结果
{
"data": {
"rows": [
{
"balanceType": "换机事件",
"memberId": 10134,
"model": "2014812",
"perIncome": 1,
"transferId": "152213107396210134866042021636589",
"transferTime": "2018-03-27 14:27:54",
"username": "凡安才"
}
],
"totalNum": 8
},
"errorCode": 0,
"errorMsg": ""
}
上面的例子看到接口4实际是将请求的转换为ReqVo对象,将结果转换为RespVo对象。
而接口6中实际是直接设定好请求体(body)。为什么会这样写呢?心酸啊!想到前一阵做微信公共号开发,微信的响应正常和异常返回的结果各种五花八门,我有心定义对象,有时间吗?说到微信公共号,不得不赞的是公共号自身的安全机制,非常好,现在公司都向公共号的这种安全处理靠拢,后期详细介绍。
下面看看这些接口是如何被调用。
package com.ccycc.retrofit;
import java.io.IOException;
import com.ccycc.retrofit.network.infs.TestService;
import com.ccycc.retrofit.vo.ReqVo;
import com.ccycc.retrofit.vo.RespVo;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;
/**
* Hello world!
*
*/
public class App
{
//private String url = "https://blog.csdn.net/";
private String url = "http://pcadmin.51kuaihj.com/";
public static void main( String[] args )
{
App app = new App();
//app.retrofitStringASync();
//app.retrofitStringTwice();
//app.retrofitStringBody();
app.retrofitRest();
}
/**
* 同步请求
* 响应String 结果
*/
public void retrofitStringSync() {
//设置数据格式的转换工厂为ScalarsConverterFactory 及可返回字符串数据
Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient()).baseUrl(url)
.addConverterFactory(ScalarsConverterFactory.create()).build();
//动态代理生成代理对象 test
TestService test = retrofit.create(TestService.class);
Call call = test.getCsdn();
//同步请求 execute
try {
Response response = call.execute();
String body = response.body();
System.out.println(body);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 异步请求
* 响应String
*/
public void retrofitStringASync() {
Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient()).baseUrl(url)
.addConverterFactory(ScalarsConverterFactory.create()).build();
//动态代理生成代理对象 test
TestService test = retrofit.create(TestService.class);
Call call = test.getCsdn();
//异步请求
call.enqueue(new Callback() {
public void onResponse(Call call, Response response) {
// TODO Auto-generated method stub
String body = response.body();
System.out.println(body);
}
public void onFailure(Call call, Throwable t) {
// TODO Auto-generated method stub
}
});
}
public void retrofitStringCommonArgs() {
Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient()).baseUrl(url)
.addConverterFactory(ScalarsConverterFactory.create()).build();
//动态代理生成代理对象 test
TestService test = retrofit.create(TestService.class);
//通过参数请求
Call call = test.getCsdn("79759172");
//同步请求
try {
Response response = call.execute();
String body = response.body();
System.out.println(body);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
*多次请求
*/
public void retrofitStringTwice() {
Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient()).baseUrl(url)
.addConverterFactory(ScalarsConverterFactory.create()).build();
//动态代理生成代理对象 test
TestService test = retrofit.create(TestService.class);
Call call = test.getCsdn();
//如果需要多次请求,必须要clone 一新对象
Call call2 = call.clone();
//同步请求
try {
Response response = call.execute();
String body = response.body();
//System.out.println(body);
System.out.println("-------------------------------------");
System.out.println(call2.execute().body());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void retrofitStringBody() {
Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient()).baseUrl(url)
.build();
//动态代理生成代理对象 test
TestService test = retrofit.create(TestService.class);
Call call = test.getCsdnBody();
//同步请求
try {
//这里通过返回 okhttp.responebody来获取响应体中的内容
Response response = call.execute();
String body = response.body().string();
System.out.println(body);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void retrofitRest() {
//restful风格/json,需要转换工厂GsonConverterFactory
Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient()).baseUrl(url)
.addConverterFactory(GsonConverterFactory.create()).build();
//动态代理生成代理对象 test
TestService test = retrofit.create(TestService.class);
ReqVo vo = new ReqVo();
vo.setDisplayNum(1);
vo.setPageNum(1);
Call call = test.postJson(vo);
//同步请求
try {
Response response = call.execute();
RespVo vo2 = response.body();
System.out.println(vo2.getData().getRows().get(0).getBalanceType());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void retrofitRestBody() {
Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient()).baseUrl(url)
.addConverterFactory(GsonConverterFactory.create()).build();
//动态代理生成代理对象 test
TestService test = retrofit.create(TestService.class);
String json ="{\r\n" +
" \"pageNum\":1,\r\n" +
" \"displayNum\":1\r\n" +
"}";
//将json串直接放入请求体中
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json);
Call call = test.sendMessage("12345", body);
//同步请求
try {
Response response = call.execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
retrofit 很简单,是不是可以带你装逼,带你飞。关于https,代理了,添加证书了等问题,仅仅需要修改一下okhttp仅此而已,后面介绍。理解了上面的代码,哪些表单了,文件上传了还有何难度?
在这个json + restful横流的世界,是时候用retrofit了。