Retrofit

Retrofit

大家都知道 okhttp 是一款由 square 公司开源的 java 版本 http 客户端工具。实际上,square 公司还开源了基于 okhttp 进一步封装的 Retrofit 工具,用来支持通过接口的方式发起 http 请求 。

  1. 官网 : https://square.github.io/retrofit/
  2. github : https://github.com/square/retrofit

maven :

<dependency>
    <scope>compile</scope>
    <groupId>com.squareup.retrofit2</groupId>
    <artifactId>retrofit</artifactId>
    <version>2.9.0</version>
</dependency>

注意: Retrofit 只负责调用接口,测试时还是需要自己提供对应的接口。

hello word

  1. 新建一个接口
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;

public interface ArticleServer {
    // 实际访问 baseUrl/article/{id}
    // 路径中的 {id} 就是借口中的参数 id
    @GET("article/{id}")
    Call<ResponseBody> getArticle(@Path("id") int id);
    
    @GET("article/list")
    Call<ResponseBody> listArticle(@Query("title")String title, @Query("tag")String tag);
}
  1. 使用
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import java.io.IOException;

public class SquareUpApp {

    public static void main(String[] args) throws IOException {
        // 创建 Retrofit 对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://127.0.0.1:8085/")
                .build();
        // 实现前面的接口
        ArticleServer service = retrofit.create(ArticleServer.class);
        
        // 同步调用方法
        Response<ResponseBody> execute = service.getArticle(2).execute();
        System.out.println(execute.code());
        System.out.println(execute.message());
        System.out.println(execute.raw().request().url());
        System.out.println(execute.headers().toString());
        System.out.println(execute.body().string());
    }

}

ps: Call<ResponseBody> article = service.getArticle(2); 实例只可以被 executed 一次,但是也可以通过 clone() 方法生成新的实例来再次调用。

同步调用与异步调用

同步调用:

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://127.0.0.1:8085/")
                .build();
        ArticleServer service = retrofit.create(ArticleServer.class);
        
        // 同步调用方法
        Response<ResponseBody> execute = service.getArticle(2).execute();
        System.out.println(execute.code());
        System.out.println(execute.message());
        System.out.println(execute.raw().request().url());
        System.out.println(execute.headers().toString());
        System.out.println(execute.body().string());

异步调用:

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://127.0.0.1:8085/")
                .build();
        ArticleServer service = retrofit.create(ArticleServer.class);
        
        // 异步调用方法
        service.listArticle("数据", "spring").enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                try {
                    System.out.println(response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                t.printStackTrace();
            }
        });
    }

返回泛型

默认情况下,Retrofit 将 http body 反序列化为 OKhttp 的 ResponseBody。

转换器支持其他类型,其 maven(gradle) 依赖如下:

  1. Gson: com.squareup.retrofit2:converter-gson
  2. Jackson: com.squareup.retrofit2:converter-jackson
  3. Moshi: com.squareup.retrofit2:converter-moshi
  4. Protobuf: com.squareup.retrofit2:converter-protobuf
  5. Wire: com.squareup.retrofit2:converter-wire
  6. Simple XML: com.squareup.retrofit2:converter-simplexml
  7. JAXB: com.squareup.retrofit2:converter-jaxb
  8. Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

使用方法,以 gson 为例:

新建实体:

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Article implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long id;
    private String articleId;
    private String title;
    private String createTime;
    private String updateTime;
    private String tags;
    private Integer replyCount;
    private Integer viewCount;
    private String posters;
}

新建接口:

import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.Query;

import java.util.List;

public interface ArticleServer {
    @GET("article/list")
    Call<List<Article>> listArticle(@Query("title")String title, @Query("tag")String tag);
}

使用

        Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("http://127.0.0.1:8085/")
                .build();
        ArticleServer service = retrofit.create(ArticleServer.class);
        Response<List<Article>> execute = service.listArticle("数据", "spring").execute();
        System.out.println(execute.code());
        System.out.println(execute.message());
        System.out.println(execute.raw().request().url());
        System.out.println(execute.headers().toString());
        System.out.println(execute.body());
        List<Article> body = execute.body();
        System.out.println(body);

请求实例

动态路径请求:

@GET("group/{id}/articles")
Call<List<Article>> groupList(@Path("id") int groupId);

查询参数:

@GET("group/{id}/articles")
Call<List<Article>> groupList(@Path("id") int groupId, @Query("sort") String sort);

多个查询参数:

@GET("group/{id}/articles")
Call<List<Article>> groupList(@Path("id") int groupId, @Query("sort") String sort, @Query("tag") String tag);

查询参数作为 map:

@GET("group/{id}/articles")
Call<List<Article>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);

固定参数值:

@GET("article/list?sort=desc")
Call<List<Article>> groupList(@Path("id") int groupId, @Query("title") String title);

body

@POST("article/save")
Call<Article> saveArticle(@Body Article article);

带 header 的请求

固定值的单个 header:

    @Headers("Cache-Control: max-age=640000")
    @POST("article/save")
    Call<Article> saveArticle(@Body Article article);

固定值的多个 header:

    @Headers({
            "Accept: application/vnd.github.v3.full+json",
            "User-Agent: Retrofit-Sample-App"
    })
    @POST("article/save")
    Call<Article> saveArticle(@Header("token") String token, @Body Article article);

变量单个 header:

    @POST("article/save")
    Call<Article> saveArticle(@Header("token") String token, @Body Article article); 

变量多个 header:

    @POST("article/save")
    Call<Article> saveArticle(@HeaderMap Map<String, String> headers, @Body Article article);

变量和固定值混合使用:

    @Headers({
            "Accept: application/vnd.github.v3.full+json",
            "User-Agent: Retrofit-Sample-App"
    })
    @POST("article/save")
    Call<Article> saveArticle(@HeaderMap Map<String, String> headers, @Body Article article);

表单

使用表单:

    @FormUrlEncoded
    @POST("article/update")
    Call<Article> updateArticle(@Field("id") Long id, @Field("title") String first, @Field("tags") String tags);

上传文件

接口:

注意: 文件的 @Part 注解不要带参数,不然会报错。

    @POST("article/uploadFile")
    @Multipart
    Call<ResponseBody> uploadFile(@Part("title") RequestBody title, @Part("tags") RequestBody tags, @Part MultipartBody.Part file);

实现:

        Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("http://127.0.0.1:8085")
                .build();
        ArticleServer service = retrofit.create(ArticleServer.class);
        RequestBody title = RequestBody.create(MediaType.parse("text/plain"), "测试标题");
        RequestBody tags = RequestBody.create(MediaType.parse("text/plain"), "spring");
        RequestBody file = RequestBody.create(MediaType.parse("application/octet-stream"), new File("D:\\pdf\\123456.png"));
        // myFile 对应接口中接收文件的参数名
        MultipartBody.Part filePart = MultipartBody.Part.createFormData("myFile", "123456.png", file);
        Response<ResponseBody> execute = service.uploadFile(title, tags, filePart).execute();
        System.out.println(execute.code());

自定义 Converter

retrofit2.Converter<F, T> 接口:

public interface Converter<F, T> {
  //  实现从 F(rom) 到 T(o)的转换
  T convert(F value) throws IOException;

  /** Creates {@link Converter} instances based on a type and target usage. */
  // 用于向 Retrofit 提供相应 Converter 的工厂
  abstract class Factory {
    // 处理响应体 - 如果不能处理返回 null
    /**
     * Returns a {@link Converter} for converting an HTTP response body to {@code type}, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for
     * response types such as {@code SimpleResponse} from a {@code Call<SimpleResponse>}
     * declaration.
     */
    public @Nullable Converter<ResponseBody, ?> responseBodyConverter(
        Type type, Annotation[] annotations, Retrofit retrofit) {
      return null;
    }

    // 对 Part、PartMap、Body 注解的处理
    /**
     * Returns a {@link Converter} for converting {@code type} to an HTTP request body, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for types
     * specified by {@link Body @Body}, {@link Part @Part}, and {@link PartMap @PartMap} values.
     */
    public @Nullable Converter<?, RequestBody> requestBodyConverter(
        Type type,
        Annotation[] parameterAnnotations,
        Annotation[] methodAnnotations,
        Retrofit retrofit) {
      return null;
    }

    // 对 Field、FieldMap、Header、Path、Query、QueryMap 注解的处理
    /**
     * Returns a {@link Converter} for converting {@code type} to a {@link String}, or null if
     * {@code type} cannot be handled by this factory. This is used to create converters for types
     * specified by {@link Field @Field}, {@link FieldMap @FieldMap} values, {@link Header @Header},
     * {@link HeaderMap @HeaderMap}, {@link Path @Path}, {@link Query @Query}, and {@link
     * QueryMap @QueryMap} values.
     */
    public @Nullable Converter<?, String> stringConverter(
        Type type, Annotation[] annotations, Retrofit retrofit) {
      return null;
    }
    ...
  }
}

想从 Call 转换为自定义的 Call 那么泛型的 F 和 T 则分别对应 ResponseBody 和 String,那么新建自定义 Converter 如下:

import okhttp3.ResponseBody;
import retrofit2.Converter;
import java.io.IOException;

public class MyConverter implements Converter<ResponseBody, String> {
    public static final MyConverter INSTANCE = new MyConverter();
    @Override
    public String convert(ResponseBody value) throws IOException {
        return value.string();
    }
}

还需要一个 Factory 来向 Retrofit 注册自定义的 MyConverter :

import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

public class MyFactory extends Converter.Factory {
    public static final MyFactory INSTANCE = new MyFactory();
    public static MyFactory create() {
        return INSTANCE;
    }
    // 只关实现从ResponseBody 到 String 的转换,所以其它方法可不覆盖
    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        if (type == String.class) {
            return MyConverter.INSTANCE;
        }
        // 其它类型不处理,返回null就行
        return null;
    }
}

定义测试接口:

    @GET("article/list")
    Call<String> listJson(@Query("title") String title, @Query("tag") String tag);

使用 Factory 测试:

        Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(MyFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("http://127.0.0.1:8085/")
                .build();
        ArticleServer service = retrofit.create(ArticleServer.class);
        Response<String> execute = service.listJson("数据", "spring").execute();
        System.out.println(execute.code());
        System.out.println(execute.message());
        System.out.println(execute.raw().request().url());
        System.out.println(execute.headers().toString());
        System.out.println(execute.body());
        String body = execute.body();
        System.out.println(body);

注意: addConverterFactory() 是有先后顺序的,如果有多个 ConverterFactory 都支持同一种类型,那么就是只有第一个才会被使用,而 GsonConverterFactory 是不判断是否支持的,所以这里交换了顺序还会有一个异常抛出,原因是类型不匹配。只要返回值类型的泛型参数就会由 MyConverter 处理,不管是 Call 还是 Observable

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Retrofit是一个非常流行的网络请求库,支持HTTP和HTTPS协议。在使用Retrofit进行HTTPS请求时,需要进行一些配置,以确保请求的安全性。下面是使用Retrofit进行HTTPS请求的步骤: 1.在build.gradle文件中添加RetrofitOkHttp依赖: ```gradle implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.okhttp3:okhttp:4.9.0' ``` 2.创建OkHttpClient实例,并配置TLS: ```java OkHttpClient.Builder builder = new OkHttpClient.Builder(); ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) .tlsVersions(TlsVersion.TLS_1_2) .cipherSuites( CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) .build(); builder.connectionSpecs(Collections.singletonList(spec)); OkHttpClient client = builder.build(); ``` 3.创建Retrofit实例,并将OkHttpClient实例传入: ```java Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://example.com/") .client(client) .build(); ``` 4.创建API接口,并使用@HTTPS注解指定请求的HTTPS证书: ```java public interface ApiService { @GET("/") @HTTPS(certificates = "cert.pem") Call<String> get(); } ``` 5.发送HTTPS请求: ```java ApiService apiService = retrofit.create(ApiService.class); Call<String> call = apiService.get(); Response<String> response = call.execute(); String result = response.body(); ``` 需要注意的是,以上步骤只是简单介绍了如何使用Retrofit进行HTTPS请求,实际使用中还需要根据具体情况进行配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值