使用Retrofit 2 请求HTTP

什么是Retrofit

Retrofit是一个基于OkHttp的RESTful HTTP网络请求库,是目前比较流行的HttpClient库之一。它使得开发者可以更方便地与Web服务交互,通过简洁的API接口,实现了将REST API请求转化为Java接口调用的方式。

Retrofit的主要特点如下:

  • 简单易用:Retrofit使用简洁的注解方式定义REST API的接口,支持多种HTTP请求方法(如GET、POST、PUT、DELETE等),并自动将响应结果转换为Java对象。
  • 支持异步请求:Retrofit支持异步网络请求,可以使用RxJava、Kotlin协程等方式实现异步请求,避免在主线程中执行耗时操作。
  • 支持自定义拦截器和转换器:Retrofit可以通过自定义拦截器和转换器实现各种功能,如添加请求头、日志记录、错误处理、JSON解析等。
  • 支持文件上传和下载:Retrofit支持文件上传和下载,可以将文件作为请求体或响应体发送或接收。
  • 支持URL替换和查询参数:Retrofit支持URL替换和查询参数,可以在URL中动态替换参数,或在查询参数中传递参数。
  • 兼容多种序列化库:Retrofit支持多种序列化库,如Gson、Jackson等,可以自动将响应结果转换为Java对象。

Retrofit的使用方式

1、定义一个接口(封装URL地址和数据请求)
2、实例化Retrofit
3、通过Retrofit实例创建接口服务对象
4、接口服务对象调用接口中方法,获得Call对象
5、Call对象执行请求(异步、同步请求)

入门案例

通过GET请求访问https://www.wanandroid.com/banner/json

public interface ApiService {

    /**
     * get无参请求
     * https://www.wanandroid.com/banner/json
     */
    @GET("banner/json")
    Call<ResponseBody> getBanner();
 
}

创建Retrofit实例时需要通过Retrofit.Builder,并调用baseUrl方法设置URL

public class MainActivity {

     public static final String BASE_URL = "https://www.wanandroid.com/";

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        //2.实例化Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .build();

        //3.通过Retrofit实例创建接口服务对象
        ApiService apiService = retrofit.create(ApiService.class);

        //4.接口服务对象调用接口中方法,获得Call对象
        Call<ResponseBody> call = apiService.getBanner();

        //5.Call对象执行请求(异步、同步请求)

        //同步请求:不常用,一般使用异步请求
        //Response<ResponseBody> execute = call.execute();

        //异步请求
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                //onResponse方法是运行在主线程也就是UI线程的,所以我们可以在这里直接更新ui
                if (response.isSuccessful()) {
                    try {
                        String result = response.body().string();
                        log.info("onResponse: {}", result);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                //onFailure方法是运行在主线程也就是UI线程的,所以我们可以在这里直接更新ui
                Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });

        //call.cancel(); //取消
    }

Retrofit注解

请求方式注解

在这里插入图片描述

GET有参请求
public interface ApiService {
/**
* get有参请求
* http://qt.qq.com/php_cgi/news/php/varcache?id=12&page=0&plat=android&version=9724
*/
@GET("/news/php/varcache")
Call<ResponseBody> getNewsInfo(@Query("id") String id,
                               @Query("page") String page,
                               @Query("plat") String plat,
                               @Query("version") String version);
}

public class MainActivity extends AppCompatActivity {

    public static final String BASE_URL = "http://qt.qq.com/php_cgi";

    Retrofit retrofit = new Retrofit.Builder()
      .baseUrl(BASE_URL)
      .build();

    ApiService apiService = retrofit.create(ApiService.class);
  
    Call<ResponseBody> call = apiService.getNewsInfo("12", "0", "android", "9724");
  
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
          if (response.isSuccessful()) {
            try {
              String string = response.body().string();
            } catch (IOException e) {
              e.printStackTrace();
            }
          }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
          Log.e("xyh", "onFailure: " + t.getMessage());
        }
      });
}

@Query 注解:用于Get中指定参数。

@QueryMap注解:如果参数过多的话可以使用@QueryMap封装参数,相当于多个@Query

@GET("news/php/varcache")
Call<ResponseBody> getNewsInfo(@QueryMap Map<String, String> map);
Map<String, String> map = new HashMap<>();
map.put("id", "12");
map.put("page", "0");
map.put("plat", "android");
map.put("version", "9724");

Call<ResponseBody> call = apiService.getNewsInfo(map);
POST请求

@FormUrlEncoded:表示请求实体是一个Form表单,每个键值对需要使用@Field注解

/**
* post请求
* FormUrlEncoded:表示请求实体是一个Form表单,每个键值对需要使用@Field注解
* http://qt.qq.com/php_cgi/news/php/update?id=12&page=0&plat=android&version=9724
*/
@FormUrlEncoded
@POST("news/php/update")
Call<ResponseBody> updateGameInfo(@Field("id") String id,
                               @Field("page") String page,
                               @Field("plat") String plat,
                               @Field("version") String version);

多个参数时可以使用,类型@QueryMap

@FormUrlEncoded
@POST("news/php/update")
Call<ResponseBody> updateGameInfo(@FieldMap Map<String, String> map);

POST添加Body

@Body注解:设置请求的请求体

方法一:使用RequestBody

@POST("news/php/send")
Call<ResponseBody> sendNewsInfoByBody(@Body RequestBody Body);
  String json = "";
  RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
  retrofit.create(ApiService.class)
    .sendNewsInfoByBody(body)
    .enqueue(new Callback<ResponseBody>() {
      @Override
      public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {

      }

      @Override
      public void onFailure(Call<ResponseBody> call, Throwable t) {

      }
    });

方法二:直接传入实体,它会自行转化成Json,这个转化方式是GsonConverterFactory定义的。

/**
* 直接传入实体,它会自行转化成Json,这个转化方式是GsonConverterFactory定义的。
*/
@POST("news/php/send")
Call<ResponseBody> sendNewsInfoByBody(@Body ParmasBean bean);
  Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(BASE_URL)
    .addConverterFactory(GsonConverterFactory.create()) //gson转换器
    .build();

  ApiService apiService = retrofit.create(ApiService.class);

  ParmasBean parmasBean= new ParmasBean();
  Call<ResponseBody> call = apiService.sendNewsInfoByBody(parmasBean);

方式3:使用Map集合

@POST("news/php/send")
Call<ResponseBody> sendNewsInfoByBody(@Body Map<String, Object> map);
  Map<String, Object> parmas = new HashMap<>();
  parmas.put("alipay_account", "xx");
  parmas.put("real_name", "xx");
  Call<ResponseBody> call = apiService.getNewsInfoByBody(parmas);
HTTP注解

这些注解分别对应Http的8种请求方法,注解中都是接收一个字符串作为请求路径的一部分,有点像@RequestMapping(),HTTP注解则可以代替以上方法中的任意一个注解,有3个属性:method、path、hasBody:

请求头注解

注解说明
@Headers用于添加固定请求头,可以同时添加多个,通过该注解添加的请求头不会相互覆盖,而是会共同存在
@Header作为方法的参数传入,用于添加不固定值的Header,该注解会更新已有的请求头

@Url注解:用于指定请求的路径,若需要重新定义接口地址,可以使用@Url,将地址以参数的形式传入即可。

/**
 * 若需要重新定义接口地址,可以使用@Url,将地址以参数的形式传入即可。
 */
@GET
Call<List<Activity>> getActivityList(@Url String url, @QueryMap Map<String, String> map);

Headers注解

 /**
  * 使用@Headers添加多个请求头
  * 用于添加固定请求头,可以同时添加多个。通过该注解添加的请求头不会相互覆盖,而是共同存在
  */
  @Headers({
    "User-Agent:android",
    "apikey:123456789",
    "Content-Type:application/json",
  })
  @POST()
  Call<BaseEntity<NewsInfo>> post(@Url String url, @QueryMap Map<String, String> map);

Header注解

 /**
 * @Header注解:
 */
@GET("mobile/active")
Call<BaseEntity<NewsInfo>> get(@Header("token") String token, @Query("id") int activeId);

请求参数注解

请求参数注解已经在上面的案例中进行了介绍,这里进行简单的总结:

请求参数注解说明
@Body多用于Post请求发送非表达数据,根据转换方式将实例对象转化为对应字符串传递参数,比如使用Post发送Json数据,添加GsonConverterFactory则是将body转化为json字符串进行传递
@Filed多用于Post方式传递参数,需要结合@FromUrlEncoded使用,即以表单的形式传递参数
@FiledMap多用于Post请求中的表单字段,需要结合@FromUrlEncoded使用
@Part用于表单字段,Part和PartMap与@multipart注解结合使用,适合文件上传的情况
@PartMap用于表单字段,默认接受类型是Map<String,RequestBody>,可用于实现多文件上传
@Path用于Url中的占位符
@Query用于Get请求中的参数
@QueryMap与Query类似,用于不确定表单参数
@Url指定请求路径

项目代码实践

Get请求

获取人员信息service:

    @Autowired
    private OpenApi openApi;

    public UserMeta getUserFromOpenApi(String name) throws BondingException {
        OpenApiResult<UserMeta> result;
        try {
            result = openApi.getUserFromOpenApi(name).execute().body();
            log.info("getUserFromOpenApi, name: {}, result: {}", name, result);
        } catch (Exception e) {
            log.error("getUserMetaFromOpenApi error", e);
            throw new Exception(RELY_SERVICE_BUSY);
        }
        if (result == null || result.getStatus() != SUCCESS_STATUS) {
            throw new Exception(RELY_SERVICE_BUSY);
        }
      

HTTP接口,通过@Path注解可以给URL动态赋值:

public interface OpenApi {

    /**
     * 获取人员信息
     */
    @GET("/v2/user/user/{username}")
    Call<OpenApiResult<UserMeta>> getUserFromOpenApi(@Path("username") String username);
  
}

根据用户名模糊查询公司员工信息,返回前N条数据service:

public class IHRService {

    @Autowired
    private OpenApi openApi;

    public JSONArray getUserInfoList(String username, int limit) throws BondingException {
        try {
            JsonArray result =
                    openApi.getUserMetaFromOpenApi(username, limit).execute().body();
            JSONArray responseJson = new Gson().fromJson(result, JSONArray.class);
            return responseJson;
        } catch (Exception e) {
            log.error("getUserInfoList error", e);
            throw new Exception(RELY_SERVICE_BUSY);
        }
    }
}

HTTP接口,通过@Query接口传递GET中参数:

public interface OpenApi {

    @GET("/v1/person")
    Call<JsonArray> getUserMetaFromOpenApi(
            @Query("name") String name,
            @Query("limit") int limit);
  
}

批量查询Team任务信息service:

    /**
     * 批量查询任务信息(包含状态)
     */
    public Map<String, String> batchGetTask(List<String> taskIdList, String operator)
            throws BondingException {
        Map<String, String> resultMap = new HashMap<>();
        try {
            String url = "external/task/taskInfos?operator="
                    + operator + "&taskIds=" + String.join("&taskIds=", taskIdList);
            OpenApiResult<List<TaskInfoResult>> result = openApi.batchGetTaskInfo(url).execute().body();
            if (result == null || result.getStatus() != SUCCESS_STATUS) {
                throw new Exception(RELY_SERVICE_BUSY);
            }
            result.getResult().forEach(taskBaseModel -> {
                TaskBaseModel baseModel = taskBaseModel.getTaskBaseModel();
                resultMap.put(baseModel.getTaskId(), baseModel.getStatusPhase());
            });
            return resultMap;
        } catch (Exception e) {
            log.error("batchGetTask error", e);
            throw new Exception(RELY_SERVICE_BUSY);
        }
    }

HTTP接口,通过@Url注解可以直接指定接口路径:

public interface OpenApi {

    /**
     * 批量查询任务信息(包含状态)
     */
    @GET
    Call<OpenApiResult<List<TaskInfoResult>>> batchGetTaskInfo(@Url String url);
  
}

POST请求

HTTP接口,@Header注解用户增加Header,@Body注解用于POST请中的请求体

public interface OpenApi {

    /**
     * 新增某个角色对用户的授权
     */
    @POST("/api/roles/{roleCode}/users")
    Call<OpenApiResult<String>> addUsersForRole(
            @Header("AMC-User-Type") String type,
            @Path("roleCode") String roleCode,
            @Body List<String> authUserList);
  
}

HTTP接口,@Headers注解用于添加固定请求头,可以同时添加多个:

public interface OpenApi {

    /**
     * 批量获取人员信息
     */
    @POST("/openapi/v2/usernames")
    @Headers({"Content-Type: application/json;charset=utf-8"})
    Call<OpenApiResult<List<UserMeta>>> batchGetUserMetaFromOpenApi(@Body List<String> userNameList);
  
}

DELETE请求

HTTP接口,@DELETE注解默认情况下是不能够有Body的,如果想要有Body的DELETE请求,需要通过@HTTP注解的方式:

public interface OpenApi {

    /**
     * 取消某个角色对某用户的授权
     */
    @HTTP(method = "DELETE", path = "/api/roles/{roleCode}/users", hasBody = true)
    Call<OpenApiResult<String>> revokeUsersForRole(
            @Header("type") String type,
            @Path("roleCode") String roleCode,
            @Body List<String> authUserList);
  
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Boot与Retrofit2可以很好地结合使用,以方便地进行网络请求。下面是使用Spring Boot和Retrofit2的基本步骤: 1. 添加依赖:在项目的pom.xml文件中添加以下依赖: ```xml <dependencies> <!-- Spring Boot Starter Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Retrofit2 --> <dependency> <groupId>com.squareup.retrofit2</groupId> <artifactId>retrofit</artifactId> <version>2.9.0</version> </dependency> <!-- Retrofit2 Gson Converter --> <dependency> <groupId>com.squareup.retrofit2</groupId> <artifactId>converter-gson</artifactId> <version>2.9.0</version> </dependency> </dependencies> ``` 2. 创建Retrofit实例:在Spring Boot的配置类中,使用`@Bean`注解创建一个Retrofit实例,并配置相关参数,如接口的基本URL、Gson转换器等。 ```java import okhttp3.OkHttpClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; @Configuration public class RetrofitConfig { @Bean public Retrofit retrofit() { OkHttpClient client = new OkHttpClient.Builder() // 可以添加自定义的OkHttpClient配置 .build(); return new Retrofit.Builder() .baseUrl("http://api.example.com/") // 设置接口的基本URL .client(client) .addConverterFactory(GsonConverterFactory.create()) // 设置Gson转换器 .build(); } } ``` 3. 创建API接口:定义一个接口,用于描述请求的方法和参数。 ```java import retrofit2.Call; import retrofit2.http.GET; public interface ApiService { @GET("users") Call<List<User>> getUsers(); } ``` 4. 使用Retrofit发起请求:在需要使用网络请求的地方,通过依赖注入的方式获取Retrofit实例,并调用接口方法发起请求。 ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import retrofit2.Call; import retrofit2.Response; import java.io.IOException; import java.util.List; @Service public class UserService { @Autowired private Retrofit retrofit; public List<User> getUsers() throws IOException { ApiService apiService = retrofit.create(ApiService.class); Call<List<User>> call = apiService.getUsers(); Response<List<User>> response = call.execute(); if (response.isSuccessful()) { return response.body(); } else { throw new IOException("请求失败:" + response.code()); } } } ``` 这样就可以在Spring Boot项目中使用Retrofit2进行网络请求了。注意要根据实际需求进行配置和调整,例如添加拦截器、设置超时时间等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程芝士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值