简介
Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,OkHttp现在已经得到Google官方认可,大量的app都采用OkHttp做网络请求,其源码详见OkHttp Github。
Retrofit2主要作用是简化了Java发送http请求的代码,通过规约,自动进行映射,全程都是java对象结构,包括请求消息和返回消息,不用用户再进行繁琐的转化。
json-server
使用json-server提供接口返回,模拟一个http服务器,可以接收一个Http请求,并提供预制的返回值。具体使用方法可以参考另一篇文章
json-server 详解
设置响应数据库
新建db.json:
{
"weather": {
"code": 200,
"msg": "成功!",
"data": {
"yesterday": {
"date": "3日星期日",
"high": "高温 10℃",
"fx": "北风",
"low": "低温 1℃",
"fl": "<![CDATA[<3级]]>",
"type": "小雨"
},
"city": "临沂",
"aqi": null,
"forecast": [{
"date": "4日星期一",
"high": "高温 9℃",
"fengli": "<![CDATA[<3级]]>",
"low": "低温 0℃",
"fengxiang": "东南风",
"type": "阴"
},
{
"date": "5日星期二",
"high": "高温 14℃",
"fengli": "<![CDATA[<3级]]>",
"low": "低温 1℃",
"fengxiang": "北风",
"type": "阴"
},
{
"date": "6日星期三",
"high": "高温 12℃",
"fengli": "<![CDATA[3-4级]]>",
"low": "低温 3℃",
"fengxiang": "东北风",
"type": "晴"
},
{
"date": "7日星期四",
"high": "高温 11℃",
"fengli": "<![CDATA[<3级]]>",
"low": "低温 0℃",
"fengxiang": "东南风",
"type": "晴"
},
{
"date": "8日星期五",
"high": "高温 11℃",
"fengli": "<![CDATA[<3级]]>",
"low": "低温 0℃",
"fengxiang": "东北风",
"type": "阴"
}
],
"ganmao": "天凉,昼夜温差较大,较易发生感冒,请适当增减衣服,体质较弱的朋友请注意适当防护。",
"wendu": "8"
}
}
}
设置请求路由过滤器
新建router.json:
{
"/weather/*": "/weather"
}
启动json-server
启动json-server,并指定端口号3004
json-server --routes router.json db.json -p 3004
\{^_^}/ hi!
Loading db.json
Loading router.json
Done
Resources
http://localhost:3004/weather
Other routes
/weather/* -> /weather
Home
http://localhost:3004
java端发送请求步骤
引入依赖框架
maven的相关配置:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<scope>provided</scope>
<version>2.7</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-gson</artifactId>
<version>2.4.0</version>
</dependency>
创建请求接口
Retrofit 将我们的 HTTP API 转换成一个 接口形式,所以我们第一步定义一个 interface:
import retrofit2.Call;
import retrofit2.http.GET;
public interface HttpService {
/**
* 动态指定查询条件
* @Query("字段")
* */
@GET("weatherApi")
Call<WeatherInfoModel> getWeatherInfo();
}
@GET("weatherApi")
表明是个GET请求,并且路径是/weatherApi
Call<WeatherInfoModel> getWeatherInfo()
getWeatherInfo() 入参表示发送请求的参数,这里为空,说明请求路径中的问号后面没有参数。
返回值类型为WeatherInfoModel
表示返回的数据可以映射为WeatherInfoModel
。
Call是固定用法
数据解析bean
底层采用Gson数据解析bean,因此可以使用相关的标签
package Retrofit;
import java.util.List;
import com.google.gson.annotations.SerializedName;
public class WeatherInfoModel {
public String code;
@SerializedName("message")
public String message; //成员为基础类型
@SerializedName("data")
public WeatherInfo weatherInfo; //成员为一个对象
public class WeatherInfo {
@SerializedName("yesterday") //对应返回的json响应中的字段
public DayWeatherInfo yesterdayWeatherInfo; //自定义java对象的字段名称
public String city;
public String aqi;
@SerializedName("forecast")
public List<DayWeatherInfo> forecastWeatherInfo; //数组结构
@SerializedName("ganmao")
public String hint;
public String wendu;
}
public class DayWeatherInfo {
public String date;
public String high;
public String fx;
public String low;
public String fl;
public String type;
}
@Override
public String toString() {
return "城市: " + weatherInfo.city + ", 天气:" + weatherInfo.forecastWeatherInfo.get(0).type
+ ", " + weatherInfo.forecastWeatherInfo.get(0).high + ", "
+ weatherInfo.forecastWeatherInfo.get(0).low + ", 提醒:" + weatherInfo.hint;
}
}
发送请求
package Retrofit;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class test {
public static void main(String[] args) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:3004/weather/")
.addConverterFactory(GsonConverterFactory.create()).build(); //将域名传入构造一个Retrofit
HttpService mHttpService = retrofit.create(HttpService.class); //传入接口类型,构建一个HttpService 实例
Call<WeatherInfoModel> call = mHttpService.getWeatherInfo(); //调用接口对应的方法
call.enqueue(new Callback<WeatherInfoModel>() { //调用了enqueue方法去异步请求http
public void onResponse(Call<WeatherInfoModel> call, Response<WeatherInfoModel> response) { //响应的回调函数
if (response.body().code.equals("200")) {
System.out.println(response.body().toString());
} else {
}
}
public void onFailure(Call<WeatherInfoModel> call, Throwable t) {
}
});
}
}
执行结果:
城市: 临沂, 天气:阴, 高温 9℃, 低温 0℃, 提醒:天凉,昼夜温差较大,较易发生感冒,请适当增减衣服,体质较弱的朋友请注意适当防护。
注解分类
1.请求方法注解
GET、POST、PUT、DELETE、HEAD、PATCH、OPTIONS、HTTP
对应HTTP的七种请求方法,HTTP可替换前面的七种
2.标记类注解
ForMUrlEncoded、Multipart、Streaming
- @ForMUrlEncoded 注解来标明这是一个表单请求
- @Streaming 代表响应的数据以流的形式返回,如果不使用他则默认会把全部数据加载到内存,所以下周大文件时需要加上这个注解
- @Multipart 上传文件
3.参数类注解
Header、Headers、Body、Path、Field、FieldMap、Part、PartMap、Query、QueryMap等 - @Path 动态的配置URL地址
- @Query 动态指定查询条件
- @QueryMap 动态指定查询条件组
- @Field 传输数据类型键值对
- @Body 传输数据类型JSON字符串
- @Part 单个文件上传
- @PartMap 多个文件上传
- @Header 消息报头
例子:
单个查询条件:
如果city值是beijing
weatherApi?city=beijing
@GET("weatherApi")
Call<WeatherInfoModel> getWeatherInfo(@Query("city") String city);
动态指定查询条件
如果map是{“city”:“beijing”,“county”:“China”}
结果是 /weatherApi?city=beijing&county=China
@GET("weatherApi")
Call<WeatherInfoModel> getWeatherInfo(@QueryMap Map<String,String> params);
动态的配置URL地址,动态指定查询条件
如果path值是weatherApi,city值是beijing
/weatherApi?city=beijing
@GET("{path}")
Call<WeatherInfoModel> getWeatherInfo(@Path ("path") String path, @Query("city") String city);
传输数据类型为键值对,注解来标明这是一个表单请求
@FormUrlEncoded
@POST("weatherApi")
Call<WeatherInfoModel> postWeatherInfo(@Field("city") String city);
传输数据类型为JSON字符串
@POST("weatherApi")
Call<WeatherInfoModel> postWeatherInfo(@Body CityBody body);
常见问题:
1.baseUrl must end in /: http:
Exception in thread "main" java.lang.IllegalArgumentException: baseUrl must end in /: http://localhost:3004/weather
at retrofit2.Retrofit$Builder.baseUrl(Retrofit.java:515)
at retrofit2.Retrofit$Builder.baseUrl(Retrofit.java:458)
at Retrofit.test.main(test.java:13)
我们看下本文例子http://localhost:3004/weather/
,url结尾需要加上/,否则会报上述错误。