美文网首页Android开发
Retrofit网络请求参数注解

Retrofit网络请求参数注解

作者: name不是null | 来源:发表于2019-07-04 15:31 被阅读0次

    1.Retrofit介绍

    retrofit是在okhttp的基础上进行封装的,网络请求是通过okhttp实现的。

    具体使用细节可查看retrofit官网

    2.Retrofit注解

    Retrofit通过注解的方式,进行网络请求。根据功能分类,注解可以分为:


    2.1请求方法类:
    编号 名称
    1 GET
    2 POST
    3 PUT
    4 DELETE
    5 PATCH
    6 HEAD
    7 OPTIONS
    8 HTTP

    1.GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、
      HTTP \color{red}{(编号8)}可以代替上面7个
    2.分别对应 HTTP 的请求方法;(最后的HTTP除除外)
    3.接收一个字符串表示接口 path ,与 baseUrl 组成完整的 Url;
    4.可以不指定,结合 @Url 注解使用;
    5.url 中可以使用变量,如 {id} ,并使用 @Path("id") 注解为 {id} 提供值;
    6.对于编号8,HTTP的使用方法如下:
      有 3 个属性:method、path、hasBody

    public interface RetrofitService
    {
        @HTTP(method = "get", path = "new{id}", hasBody = false)
        Call<ResponseBody> getNew(@Path("id") int id);
    }
    
    2.1.1:GET
    • 一个简单的Get请求
    public interface RetrofitService
    {
        // http://192.168.1.102/api/News
        @GET("News")
        Call<NewsBean> getItem();
    }
    
    • URL中有参数的Get请求
    public interface RetrofitService
    {
        // http://192.168.1.102/api/News/1
        // http://192.168.1.102/api/News/{资讯id}
        @GET("News/{newsId}")
        Call<NewsBean> getItem(@Path("newsId") String newsId);
    
        // http://192.168.1.102/api/News/1/类型1
        // http://192.168.1.102/api/News/{资讯id}/{类型}
        @GET("News/{newsId}/{type}")
        Call<NewsBean> getItem(@Path("newsId") String newsId, @Path("type") String type);
    }
    
    • 参数在URL问号之后的Get请求
    public interface RetrofitService
    {
        // http://192.168.1.102/api/News?newsId=1
        // http://192.168.1.102/api/News?newsId={资讯id}
        @GET("News")
        Call<NewsBean> getItem(@Query("newsId") String newsId);
    
        // http://192.168.1.102/api/News?newsId=1&type=类型1
        // http://192.168.1.102/api/News?newsId={资讯id}&type={类型}
        @GET("News")
        Call<NewsBean> getItem(@Query("newsId") String newsId, @Query("type") String type);
    }
    
    • 多个参数在URL问号之后,且个数不确定的Get请求
    public interface RetrofitService
    {
        // http://192.168.1.102/api/News?newsId=1&type=类型1...
        // http://192.168.1.102/api/News?newsId={资讯id}&type={类型}...
        @GET("News")
        Call<NewsBean> getItem(@QueryMap Map<String, String> map);
    
        // http://192.168.1.102/api/News?newsId=1&type=类型1...
        // http://192.168.1.102/api/News?newsId={资讯id}&type={类型}...
        @GET("News")
        Call<NewsBean> getItem(@Query("newsId") String newsId, @QueryMap Map<String, String> map);
    }
    
    2.1.2: POST
    • 需要补全URL,post的数据只有一条reason的Post请求
    public interface RetrofitService
    {
        // http://192.168.1.102/api/Comments/1
        // http://192.168.1.102/api/Comments/{newsId}
        @FormUrlEncoded
        @POST("Comments/{newsId}")
        Call<Comment> reportComment(@Path("newsId") String commentId, @Field("reason") String reason);
    }
    
    • 需要补全URL,问号后加入access_token,post的数据只有一条reason的Post请求
    public interface RetrofitService
    {
        // http://192.168.1.102/api/Comments/1?access_token=1234123
        // http://192.168.1.102/api/Comments/{newsId}?access_token={access_token}
        @FormUrlEncoded
        @POST("Comments/{newsId}")
        Call<Comment> reportComment(
                @Path("newsId") String commentId,
                @Query("access_token") String access_token,
                @Field("reason") String reason);
    }
    
    • 需要补全URL,问号后加入access_token,post一个body(对象)的Post请求
    public interface RetrofitService
    {
        // http://192.168.1.102/api/Comments/1?access_token=1234123
        // http://192.168.1.102/api/Comments/{newsId}?access_token={access_token}
        @POST("Comments/{newsId}")
        Call<Comment> reportComment(
                @Path("newsId") String commentId, 
                @Query("access_token") String access_token, 
                @Body CommentBean bean);
    }
    
    2.1.3:DELETE
    • 需要补全URL的Delete请求
    public interface RetrofitService
    {
        // http://192.168.1.102/api/Comments/1
        // http://192.168.1.102/api/Comments/{commentId}
        @DELETE("Comments/{commentId}")
        Call<ResponseBody> deleteNewsCommentFromAccount(@Path("commentId") String commentId);
    }
    
    • 需要补全URL,问号后加入access_token的Delete请求
    public interface RetrofitService
    {
        // http://192.168.1.102/api/Comments/1?access_token=1234123
        // http://192.168.1.102/api/Comments/{commentId}?access_token={access_token}
        @DELETE("Comments/{commentId}")
        Call<ResponseBody> deleteNewsCommentFromAccount(@Path("commentId") String commentId, @Query("access_token") String access_token);
    }
    
    • 带有body的Delete请求
    public interface RetrofitService
    {
        // http://192.168.1.102/api/Comments
        @HTTP(method = "DELETE",path = "Comments",hasBody = true)
        Call<ResponseBody> deleteCommont(@Body CommentBody body);
    }
    
    2.1.4:PUT
    public interface RetrofitService
    {
        // http://192.168.1.102/api/Accounts/1
        // http://192.168.1.102/api/Accounts/{accountId}
        @PUT("Accounts/{accountId}")
        Call<ExtrasBean> updateExtras(@Path("accountId") String accountId, @Query("access_token") String access_token, @Body ExtrasBean bean);
    }
    
    2.2标记类:
    2.2.1:FormUrlEncoded

    FormUrlEncoded:
    1.用于修饰Field注解和FieldMap注解
    2.使用该注解,表示请求正文将使用表单网址编码。字段应该声明为参数,并用@Field注释或FieldMap注释。使用FormUrlEncoded注解的请求将具”application / x-www-form-urlencoded” MIME类型。字段名称和值将先进行UTF-8进行编码,再根据RFC-3986进行URI编码.

    2.2.2:Multipart

    Multipart:
    1.作用于方法
    2.使用该注解,表示请求体是多部分的。 每一部分作为一个参数,且用Part注解声明

    上传单个文件

    接口

    public interface RetrofitService
    {
        @Multipart
        @POST("/uploadImgs")
        Call<ResponseServer<List<PicResultData>>> uploadSingleImg(@Part("description") RequestBody description, @Part MultipartBody.Part file);
    }
    

    实现

    public void uploadImg(Object pcObj, String fileUrl) 
    {
        File file = new File(fileUrl);
        // 创建 RequestBody,用于封装构建RequestBody
        // RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        RequestBody requestFile = RequestBody.create(MediaType.parse("image/jpg"), file);
    
        // MultipartBody.Part  和后端约定好Key,这里的partName是用file
        MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
    
        // 添加描述
        String descriptionString = "hello, 这是文件描述";
        RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
    
        // 执行请求
        serviceApi.uploadSingleImg(description, body).enqueue(new BaseViewModel.HttpRequestCallback<List<PicResultData>>() 
        {
            @Override
            public void onSuccess(List<PicResultData> result) 
            {
                super.onSuccess(result);
            }
    
            @Override
            public void onFailure(int status, String message) 
            {
                super.onFailure(status, message);
            }
        });
    }
    
    上传多个文件

    接口

    public interface RetrofitService
    {
        @Multipart
        @POST("/uploadImgs")
        Call<ResponseServer<List<PicResultData>>> uploadMultiImgs(@PartMap Map<String, RequestBody> maps);
    }
    

    实现

    public void uploadImgs(Object pcObj, List<String> imgStrs) 
    {
        Map<String, RequestBody> map = new HashMap<>();
        for (String imgUrl : imgStrs) 
        {
            File file = new File(imgUrl);
            // create RequestBody instance from file
            // RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
            RequestBody requestFile = RequestBody.create(MediaType.parse("image/jpg"), file);
            // 注意:file就是与服务器对应的key,后面filename是服务器得到的文件名
            map.put("file\"; filename=\"" + file.getName(), requestFile);
        }
    
        // 执行请求
        serviceApi.uploadMultiImgs(map).enqueue(new BaseViewModel.HttpRequestCallback<List<PicResultData>>() 
        {
            @Override
            public void onSuccess(List<PicResultData> result) 
            {
                super.onSuccess(result);
            }
    
            @Override
            public void onFailure(int status, String message) 
            {
                super.onFailure(status, message);
            }
        });
    }
    
    2.2.3:Streaming

    Streaming:
    1.作用于方法
    2.处理返回Response的方法的响应体,即没有将body()转换为byte []
    3.响应体的数据用流的形式返回
    4.未使用该注解,默认会把数据全部载入内存,之后通过流获取数据也是读取内存中数据,所以返回数据较大时,需要使用该注解

    public interface RetrofitService
    {
        @Streaming
        @GET("/update_apk")
        Call<ResponseServer<News>> downloadFile(@Url String fileUrl);
    }
    
    2.3参数类:
    2.3.1:Headers

    Headers:
    1.作用于方法,用于添加一个或多个请求头
    2.使用 @Headers 注解设置固定的请求头,所有请求头不会相互覆盖,即使名字相同

    定义Headers

    public interface RetrofitService
    {
        // 添加一个请求体
        @Headers("Cache-Control: max-age=640000")
        @GET("/widget/list")
        Call<List<Widget>> widgetList();
    
        // 添加多个请求体
        @Headers({"Accept: application/vnd.yourapi.v1.full+json", "User-Agent: Your-App-Name"})
        @GET("/users/{username}")
        Call<User> getUser(@Path("username") String username)
    }
    

    使用Headers,需要使用拦截器

    private RetrofitHelper()
    {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.addInterceptor(new Interceptor()
        {
            @Override
            public Response intercept(Chain chain) throws IOException
            {
                Request original = chain.request();
    
                Request request = original.newBuilder()
                        .header("User-Agent", "Your-App-Name")
                        .header("Accept", "application/vnd.yourapi.v1.full+json")
                        .method(original.method(), original.body())
                        .build();
    
                return chain.proceed(request);
            }
        });
    
        OkHttpClient client = builder.build();
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL_WEATHER)
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build();
    }
    
    2.3.2:Header

    Header:
    1.作用于方法参数(形参)
    2.使用 @Header 注解动态更新请求头,匹配的参数必须提供给 @Header ,若参数值为 null ,这个头会被省略;当传入一个List或array时,为拼接每个非空的item的值到请求头中
    3.具有相同名称的请求头不会相互覆盖,而是会照样添加到请求头中

    public interface RetrofitService
    {
        @GET("/tasks")
        Call<List<Task>> getTasks(@Header("Content-Range") String contentRange);
    }
    
    2.3.3:Body

    Body:
    1.作用于方法参数(形参)
    2.使用该注解定义的参数不可为null
    3.当发送一个post或put请求,但是又不想作为请求参数或表单的方式发送请求时,使用该注解定义的参数可以直接传入一个实体类,retrofit会通过convert把该实体序列化并将序列化后的结果直接作为请求体发送出去;如果提交的是一个Map,那么作用相当于 @Field

    public interface RetrofitService
    {
        @GET("/users/new")
        Call<ResponseBody> createUser(@Body RequestBody requestBody);
    }
    
    2.3.4:Field

    Field:
    1.作用于方法参数(形参)
    2.发送 Post请求 时提交请求的表单字段,与 @FormUrlEncoded 注解配合使用
    3.用String.valueOf()把参数值转换为String,然后进行URL编码,当参数值为null值时,会自动忽略,如果传入的是一个List或array,则为每一个非空的item拼接一个键值对,每一个键值对中的键是相同的,值就是非空item的值,如: name=张三&name=李四&name=王五,另外,如果item的值有空格,在拼接时会自动忽略,例如某个item的值为:张 三,则拼接后为name=张三.

    public interface RetrofitService
    {
        // 普通参数
        @FormUrlEncoded
        @POST("/users/addphoto")
        Call<List<Repo>> listRepos(@Field("time") long time);
    
        // 固定或可变数组
        @FormUrlEncoded
        @POST("/users/addphoto")
        Call<List<Repo>> listRepos(@Field("name") String... names);
    }
    
    2.3.5:FieldMap

    FieldMap:
    1.作用于方法参数(形参)
    2.表单字段,与 Field、FormUrlEncoded 配合;接受 Map<String, String> 类型,非 String 类型会调用 toString() 方法
    3.map中每一项的键和值都不能为空,否则抛出IllegalArgumentException异常

    public interface RetrofitService
    {
        @FormUrlEncoded
        @POST("/things")
        Call<List<Repo>> things(@FieldMap Map<String, String> params);
    }
    
    2.3.6:Part

    Part:
    1.作用于方法参数(形参)
    2.post请求时,提交请求的表单字段,与 @ Multipart注解 配合
    3.使用该注解定义的参数,参数值可以为空,为空时,则忽略
    4.使用该注解定义的参数类型有以下3种方式可选:
    a, 如果类型是okhttp3.MultipartBody.Part,内容将被直接使用。 省略part中的名称,即 @Part MultipartBody.Part part
    b, 如果类型是RequestBody,那么该值将直接与其内容类型一起使用。 在注释中提供part名称(例如,@Part(“foo”)RequestBody foo)
    c, 其他对象类型将通过使用转换器转换为适当的格式。 在注释中提供part名称(例如,@Part(“foo”)Image photo)

    上传单个文件

    接口

    public interface RetrofitService
    {
        @Multipart
        @POST("/uploadImgs")
        Call<ResponseServer<List<PicResultData>>> uploadSingleImg(@Part("description") RequestBody description, @Part MultipartBody.Part file);
    }
    

    实现

    public void uploadImg(Object pcObj, String fileUrl) 
    {
        File file = new File(fileUrl);
        // 创建 RequestBody,用于封装构建RequestBody
        // RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
        RequestBody requestFile = RequestBody.create(MediaType.parse("image/jpg"), file);
    
        // MultipartBody.Part  和后端约定好Key,这里的partName是用file
        MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
    
        // 添加描述
        String descriptionString = "hello, 这是文件描述";
        RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
    
        // 执行请求
        serviceApi.uploadSingleImg(description, body).enqueue(new BaseViewModel.HttpRequestCallback<List<PicResultData>>() 
        {
            @Override
            public void onSuccess(List<PicResultData> result) 
            {
                super.onSuccess(result);
            }
    
            @Override
            public void onFailure(int status, String message) 
            {
                super.onFailure(status, message);
            }
        });
    }
    
    2.3.7:PartMap

    PartMap:
    1.作用于方法参数(形参)
    2.post请求时,提交请求的表单字段,与 @ Multipart注解 配合
    3.map中每一项的键和值都不能为空,否则抛出IllegalArgumentException异常
    4.使用该注解定义的参数类型有以下2种方式可选:
    a, 如果类型是RequestBody,那么该值将直接与其内容类型一起使用
    b, 其他对象类型将通过使用转换器转换为适当的格式。
    5.携带的参数类型更加丰富,包括数据流,所以适用于 有文件上传 的场景

    上传多个文件

    接口

    public interface RetrofitService
    {
        @Multipart
        @POST("/uploadImgs")
        Call<ResponseServer<List<PicResultData>>> uploadMultiImgs(@PartMap Map<String, RequestBody> maps);
    }
    

    实现

    public void uploadImgs(Object pcObj, List<String> imgStrs) 
    {
        Map<String, RequestBody> map = new HashMap<>();
        for (String imgUrl : imgStrs) 
        {
            File file = new File(imgUrl);
            // create RequestBody instance from file
            // RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
            RequestBody requestFile = RequestBody.create(MediaType.parse("image/jpg"), file);
            // 注意:file就是与服务器对应的key,后面filename是服务器得到的文件名
            map.put("file\"; filename=\"" + file.getName(), requestFile);
        }
    
        // 执行请求
        serviceApi.uploadMultiImgs(map).enqueue(new BaseViewModel.HttpRequestCallback<List<PicResultData>>() 
        {
            @Override
            public void onSuccess(List<PicResultData> result) 
            {
                super.onSuccess(result);
            }
    
            @Override
            public void onFailure(int status, String message) 
            {
                super.onFailure(status, message);
            }
        });
    }
    
    2.3.8:Path

    Path:
    1.作用于方法参数(形参)
    2.在URL路径段中替换指定的参数值。
    3.使用String.valueOf()和URL编码将值转换为字符串。
    4.使用该注解定义的参数的值不可为空参数值默认使用URL编码

    public interface RetrofitService
    {
        @GET("/data/sk/{cityId}.html")
        Call<ResponseBody> getWeatherByCityId(@Path("cityId") String cityId);
    }
    
    2.3.9:Query

    Query:
    1.作用于方法参数(形参)
    2.用于添加查询参数,即请求参数(Query = Url 中 ‘?’ 后面的 key-value)
    3.参数值通过String.valueOf()转换为String并进行URL编码
    4.使用该注解定义的参数,参数值可以为空,为空时,忽略该值,当传入一个List或array时,为每个非空item拼接请求键值对,所有的键是统一的,如: name=张三&name=李四&name=王五.

    public interface RetrofitService
    {
        // 普通参数
        @GET("/list")
        Call<ResponseBody> list(@Query("catrgory") String catrgory);
    
        // 传入一个数组
        @GET("/list")
        Call<ResponseBody> list(@Query("catrgory") String... catrgory);
    
        // 不进行URL编码
        @GET("/search")
        Call<ResponseBody> list(@Query(value="foo", encoded=true) String foo);
    }
    
    2.3.10:QueryMap

    QueryMap:
    1.作用于方法参数(形参)
    2.以map的形式添加查询参数,即请求参数
    3.参数的键和值都通过String.valueOf()转换为String格式
    4.map的键和值默认进行URL编码map中每一项的键和值都不能为空,否则抛出IllegalArgumentException异常

    public interface RetrofitService
    {
        // 使用默认URL编码
        @GET("/search")
        Call<ResponseBody> list(@QueryMap Map<String, String> filters);
    
        // 不使用默认URL编码
        @GET("/search")
        Call<ResponseBody> list(@QueryMap(encoded=true) Map<String, String> filters);
    }
    
    2.3.11:Url

    Url:
    1.作用于方法参数(形参)
    2.直接传入一个请求的 URL变量 用于URL设置

    public interface RetrofitService
    {
        @GET
        Call<ResponseBody> urlAndQuery(@Url String url, @Query("showAll") boolean showAll);
    }
    

    3.参数注解小结:

    1.Map 用来组合复杂的参数;
    2.Query、QueryMap 与 Field、FieldMap 功能一样,生成的数据形式一样;
    Query、QueryMap 的数据体现在 Url 上;
    Field、FieldMap 的数据是请求体;
    3.{占位符}和 PATH 尽量只用在URL的 path 部分,url 中的参数使用 Query、QueryMap 代替,保证接口的简洁;
    4.Query、Field、Part 支持数组和实现了 Iterable 接口的类型, 如 List、Set等,方便向后台传递数组。

    4.注意事项:

    1,以上部分注解真正的实现在ParameterHandler类中,,每个注解的真正实现都是ParameterHandler类中的一个final类型的内部类,每个内部类都对各个注解的使用要求做了限制,比如参数是否可空,键和值是否可空等.
    2,FormUrlEncoded注解和Multipart注解不能同时使用,否则会抛出methodError(“Only one encoding annotation is allowed.”);可在ServiceMethod类中parseMethodAnnotation()方法中找到不能同时使用的具体原因.
    3,Path注解与Url注解不能同时使用,否则会抛出parameterError(p, “@Path parameters may not be used with @Url.”),可在ServiceMethod类中parseParameterAnnotation()方法中找到不能同时使用的具体代码.其实原因也很好理解: Path注解用于替换url路径中的参数,这就要求在使用path注解时,必须已经存在请求路径,不然没法替换路径中指定的参数啊,而Url注解是在参数中指定的请求路径的,这个时候指定请求路径已经晚了,path注解找不到请求路径,更别提更换请求路径中的参数了.
    4,对于FiledMap,HeaderMap,PartMap,QueryMap这四种作用于方法的注解,其参数类型必须为Map的实例,且key的类型必须为String类型,否则抛出异常(以PartMap注解为例):parameterError(p, “@PartMap keys must be of type String: ” + keyType);
    5,使用Body注解的参数不能使用form 或multi-part编码,即如果为方法使用了FormUrlEncoded或Multipart注解,则方法的参数中不能使用Body注解,否则抛出异常parameterError(p, “@Body parameters cannot be used with form or multi-part encoding.”);

    相关文章

      网友评论

        本文标题:Retrofit网络请求参数注解

        本文链接:https://www.haomeiwen.com/subject/htlrhctx.html