【Retrofit】Retrofit原理解析之注解详解篇

学而不思则罔,思而不学则殆


Retrofit系列文章

【Retrofit】Retrofit原理解析之使用篇
【Retrofit】Retrofit原理解析之原理篇
【Retrofit】Retrofit原理解析之注解详解篇
【Retrofit】Retrofit原理解析之设计模式总结篇

粗略看一下,Retrofit定义了总共20多个注解。
在这里插入图片描述

注解总结

注解作用域功能说明
@GET方法发送GET请求-
@POST方法发送POST请求默认必须带有Body,为空则存在长度为0的正文
@Path方法参数实现path拼接http://localhost:3434/retrofit/user/{username} + fish2 = http://localhost:3434/retrofit/user/fish2
@Query方法参数query拼接http://localhost:3434/retrofit/query + ? + id=2 —> http://localhost:3434/retrofit/query?id=2
@QueryMap方法参数query拼接一次拼接多个
@QueryName方法参数query拼接一次拼接多个
@Header方法参数添加请求头一次添加一个
@HeaderMap方法参数添加请求头一次添加多个
@Headers方法添加请求头一次添加多个
@FormUrlEncoded方法表示当前是表单编码不能和@Multipart共存
@Field方法参数提交一个表单必须和@FormUrlEncoded一起使用,一次添加一个,可以多个参数使用该注解
@FieldMap方法参数提交多个表单必须和@FormUrlEncoded一起使用,一次添加多个,可以多个参数使用该注解
@Body方法参数添加正文信息不能和@FormUrlEncoded 和 @Multipart共存,该方法注解只能存在一个
@Multipart方法表示当前是多部分编码不能和@FormUrlEncoded 共存
@Part方法参数一次添加一个正文part必须和@Multipart一起使用,方法参数可以存在多个
@PartMap方法参数一次添加多个正文part必须和@Multipart一起使用,方法参数可以存在多个

注解使用范例

服务端代码:https://github.com/aJanefish/ZyServer

构建Retrofit

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(HttpUrl.get("http://localhost:3434/"))
                .addConverterFactory(Utils.FACTORY)
                .build();

构建Converter.Factory

//Utils 
public class Utils {
    static final Converter.Factory FACTORY =
            new Converter.Factory() {
                @Override
                public @Nullable
                Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
                    if (type == Blog.class) return new DataAdapter();
                    return null;
                }

                @Override
                public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
                    System.out.println("type:" + type + " " + Blog.class);
                    System.out.println("type:" + type + " " + Blog.class);
                    if (type == Blog.class) {
                        return new RequestBodyAdapter();
                    }
                    return null;
                }
            };

    static final class RequestBodyAdapter implements Converter<Blog, RequestBody> {
        @Override
        public RequestBody convert(Blog blog) throws IOException {
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            for (StackTraceElement stackTraceElement : stackTrace) {
                System.out.println(stackTraceElement);
            }
            return RequestBody.create(null, blog.toString());
        }
    }


    static final class DataAdapter implements Converter<ResponseBody, Blog> {
        @Override
        public Blog convert(ResponseBody responseBody) throws IOException {
            String body = responseBody.string();
            // FIXME: 2020/11/16 数据处理
            return new Blog(body);
        }
    }
}

@GET

@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
  /**
   * A relative or absolute path, or full URL of the endpoint. This value is optional if the first
   * parameter of the method is annotated with {@link Url @Url}.
   *
   * <p>See {@linkplain retrofit2.Retrofit.Builder#baseUrl(HttpUrl) base URL} for details of how
   * this is resolved against a base URL to create the full endpoint URL.
   */
  String value() default "";
}
public interface BlogService {
    @GET("retrofit/all.do")
    Call<Blog> getAll();
 }   
    Call<Blog> call = blogService.getAll();

服务端信息:

GET http://localhost:3434/retrofit/all.do?null HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
User-Agent: okhttp/3.14.9

客户端信息:

Blog{body='{"code":200,"msg":"OK","des":"all.do","data":[{"id":1,"date":"2020-11-15 10:39:13","author":"fish1","title":"retrofit1","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test1"},{"id":2,"date":"2020-11-15 10:39:13","author":"fish2","title":"retrofit2","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test2"},{"id":3,"date":"2020-11-15 10:39:13","author":"fish3","title":"retrofit3","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test3"},{"id":4,"date":"2020-11-15 10:39:13","author":"fish4","title":"retrofit4","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test4"},{"id":5,"date":"2020-11-15 10:39:13","author":"fish5","title":"retrofit5","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test5"},{"id":6,"date":"2020-11-15 10:39:13","author":"fish6","title":"retrofit6","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test6"},{"id":7,"date":"2020-11-15 10:39:13","author":"fish7","title":"retrofit7","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test7"},{"id":8,"date":"2020-11-15 10:39:13","author":"fish8","title":"retrofit8","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test8"},{"id":9,"date":"2020-11-15 10:39:13","author":"fish9","title":"retrofit9","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test9"},{"id":10,"date":"2020-11-15 10:39:13","author":"fish10","title":"retrofit10","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test10"}]}'}

@POST

@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface POST {
  /**
   * A relative or absolute path, or full URL of the endpoint. This value is optional if the first
   * parameter of the method is annotated with {@link Url @Url}.
   *
   * <p>See {@linkplain retrofit2.Retrofit.Builder#baseUrl(HttpUrl) base URL} for details of how
   * this is resolved against a base URL to create the full endpoint URL.
   */
  String value() default "";
}
    @POST("retrofit/all.do")
    Call<Blog> postAll();
    
    Call<Blog> call = blogService.postAll();

服务端信息:

POST http://localhost:3434/retrofit/all.do?null HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Content-Length: 0
Host: localhost:3434
User-Agent: okhttp/3.14.9


注意Content-Length: 0 , 这说明存在正文,只是正文长度为0;这是因为POST默认是有Body的,但是在这个例子中,正文为空,所以框架还是添加了一个长度为0的body.

  Request.Builder get() {
    ...
    RequestBody body = this.body;
    if (body == null) {
      // Try to pull from one of the builders.
      if (formBuilder != null) {
        body = formBuilder.build();
      } else if (multipartBuilder != null) {
        body = multipartBuilder.build();
      } else if (hasBody) {
        // Body is absent, make an empty body.
        body = RequestBody.create(null, new byte[0]);
      }
    }
    ...
    return requestBuilder.url(url).headers(headersBuilder.build()).method(method, body);
  }

客户端信息:

Blog{body='{"code":200,"msg":"OK","des":"all.do","data":[{"id":1,"date":"2020-11-15 10:39:13","author":"fish1","title":"retrofit1","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test1"},{"id":2,"date":"2020-11-15 10:39:13","author":"fish2","title":"retrofit2","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test2"},{"id":3,"date":"2020-11-15 10:39:13","author":"fish3","title":"retrofit3","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test3"},{"id":4,"date":"2020-11-15 10:39:13","author":"fish4","title":"retrofit4","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test4"},{"id":5,"date":"2020-11-15 10:39:13","author":"fish5","title":"retrofit5","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test5"},{"id":6,"date":"2020-11-15 10:39:13","author":"fish6","title":"retrofit6","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test6"},{"id":7,"date":"2020-11-15 10:39:13","author":"fish7","title":"retrofit7","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test7"},{"id":8,"date":"2020-11-15 10:39:13","author":"fish8","title":"retrofit8","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test8"},{"id":9,"date":"2020-11-15 10:39:13","author":"fish9","title":"retrofit9","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test9"},{"id":10,"date":"2020-11-15 10:39:13","author":"fish10","title":"retrofit10","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test10"}]}'}

@Path

@Documented
@Retention(RUNTIME)
@Target(PARAMETER)
public @interface Path {
  String value();

  /**
   * Specifies whether the argument value to the annotated method parameter is already URL encoded.
   */
  boolean encoded() default false;
}
    @GET("retrofit/user/{username}")
    Call<Blog> getByName(@Path("username") String username);
    
    Call<Blog> call = blogService.getByName("fish1");
    Call<Blog> call = blogService.getByName("fish2");

http://localhost:3434/retrofit/user/{username} + fish2 = http://localhost:3434/retrofit/user/fish2

服务端信息:

GET http://localhost:3434/retrofit/user/fish1?null HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
User-Agent: okhttp/3.14.9

GET http://localhost:3434/retrofit/user/fish2?null HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
User-Agent: okhttp/3.14.9

客户端信息:

Blog{body='{"code":200,"msg":"OK","des":"path fish1","data":[{"id":1,"date":"2020-11-15 10:39:13","author":"fish1","title":"retrofit1","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test1"}]}'}
Blog{body='{"code":200,"msg":"OK","des":"path fish2","data":[{"id":2,"date":"2020-11-15 10:39:13","author":"fish2","title":"retrofit2","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test2"}]}'}

@Query

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Query {
  /** The query parameter name. */
  String value();

  /**
   * Specifies whether the parameter {@linkplain #value() name} and value are already URL encoded.
   */
  boolean encoded() default false;
}
    @GET("retrofit/query")
    Call<Blog> query(@Query("id") String id);
    
    Call<Blog> call = blogService.query("2");
    Call<Blog> call = blogService.query("2");
  1. http://localhost:3434/retrofit/query + ? + id=2 —> http://localhost:3434/retrofit/query?id=2
  2. http://localhost:3434/retrofit/query + ? + id=4 —> http://localhost:3434/retrofit/query?id=4

服务端信息:

GET http://localhost:3434/retrofit/query?id=2 HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
User-Agent: okhttp/3.14.9


GET http://localhost:3434/retrofit/query?id=4 HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
User-Agent: okhttp/3.14.9

客户端信息:

Blog{body='{"code":200,"msg":"OK","des":"path fish2","data":{"id":2,"date":"2020-11-15 10:39:13","author":"fish2","title":"retrofit2","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test2"}}'}
Blog{body='{"code":200,"msg":"OK","des":"path fish2","data":{"id":4,"date":"2020-11-15 10:39:13","author":"fish4","title":"retrofit4","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test4"}}'}

@QueryMap

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface QueryMap {
  /** Specifies whether parameter names and values are already URL encoded. */
  boolean encoded() default false;
}
    @GET("retrofit/query")
    Call<Blog> queryMap(@QueryMap Map<String, String> map);

            HashMap<String, String> map = new HashMap<>();
            map.put("id", "2");
            map.put("name", "zy");
            map.put("age", "28");
            Call<Blog> call = blogService.queryMap(map);

服务端信息:

GET http://localhost:3434/retrofit/query?name=zy&id=2&age=28 HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
User-Agent: okhttp/3.14.9

客户端信息:

Blog{body='{"code":200,"msg":"OK","des":"path fish2","data":{"id":2,"date":"2020-11-15 10:39:13","author":"fish2","title":"retrofit2","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test2"}}'}

@QueryName

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface QueryName {
  /** Specifies whether the parameter is already URL encoded. */
  boolean encoded() default false;
}
    @GET("retrofit/query")
    Call<Blog> queryName(@QueryName List<String> query);

    @GET("retrofit/query")
    Call<Blog> queryName(@QueryName String... query);
    
            List<String> list = new ArrayList<>();
            list.add("id=2");
            list.add("name=zy");
            list.add("age=28");
            list.add("type=list");
            Call<Blog> call1 = blogService.queryName(list);
            Call<Blog> call2 = blogService.queryName("id=2", "name=zy", "age=28", "type=strings");

服务端信息:

GET http://localhost:3434/retrofit/query?id%3D2&name%3Dzy&age%3D28&type%3Dlist HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
User-Agent: okhttp/3.14.9

GET http://localhost:3434/retrofit/query?id%3D2&name%3Dzy&age%3D28&type%3Dstrings HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
User-Agent: okhttp/3.14.9

客户端信息:

Blog{body='{"code":200,"msg":"OK","des":"path fish2"}'}
Blog{body='{"code":200,"msg":"OK","des":"path fish2"}'}

@Header

@Documented
@Retention(RUNTIME)
@Target(PARAMETER)
public @interface Header {
  String value();
}
    @GET("retrofit/query?id=4")
    Call<Blog> header(@Header("NAME-TAG") String zy, @Header("AGE-TAG") String age, @Header("Accept-Language") String lang);

    Call<Blog> call = blogService.header("zy", "28", "zh-CN");

服务端信息:

GET http://localhost:3434/retrofit/query?id=4 HTTP/1.1
AGE-TAG: 28
Accept-Encoding: gzip
Accept-Language: zh-CN
Connection: keep-alive
Host: localhost:3434
NAME-TAG: zy
User-Agent: okhttp/3.14.9

客户端信息:

Blog{body='{"code":200,"msg":"OK","des":"path fish2","data":{"id":4,"date":"2020-11-15 10:39:13","author":"fish4","title":"retrofit4","address":"https://gitee.com/zhangyuwxf/retrofit.git","content":"http test4"}}'}

@HeaderMap

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface HeaderMap {}
    @GET("retrofit/query?id=4")
    Call<Blog> headerMap(@HeaderMap Map<String, String> map);
    
            HashMap<String,String> map = new HashMap<>();
            map.put("Accept","ext/plain");
            map.put("Accept-Charset","utf-8");
            map.put("NAME-TAG","zy");
            Call<Blog> call = blogService.headerMap(map);

服务端信息:

GET http://localhost:3434/retrofit/query?id=4 HTTP/1.1
Accept: ext/plain
Accept-Charset: utf-8
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
NAME-TAG: zy
User-Agent: okhttp/3.14.9

@Headers

@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface Headers {
  String[] value();
}
    @GET("retrofit/query?id=4")
    @Headers({"X-Foo: Bar", "X-Ping: Pong", "NAME: zy"})
    Call<Blog> headers();
    
    Call<Blog> call = blogService.headers();

服务端信息:

GET http://localhost:3434/retrofit/query?id=4 HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Host: localhost:3434
NAME: zy
User-Agent: okhttp/3.14.9
X-Foo: Bar
X-Ping: Pong

@FormUrlEncoded + @Field

@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface FormUrlEncoded {}

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Field {
  String value();

  /** Specifies whether the {@linkplain #value() name} and value are already URL encoded. */
  boolean encoded() default false;
}
    @POST("retrofit/login")
    @FormUrlEncoded
    Call<Blog> login(@Field("username") String username, @Field("password") String password, @Field("tag") String tag);

    Call<Blog> call = blogService.login("zhangyu", "123456", "tag+" + System.currentTimeMillis());

服务端信息:

POST http://localhost:3434/retrofit/login?null HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Content-Length: 56
Content-Type: application/x-www-form-urlencoded
Host: localhost:3434
User-Agent: okhttp/3.14.9

username=zhangyu&password=123456&tag=tag%2B1606047792882

@FormUrlEncoded + @FieldMap

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface FieldMap {
  /** Specifies whether the names and values are already URL encoded. */
  boolean encoded() default false;
}

    @POST("retrofit/login")
    @FormUrlEncoded
    Call<Blog> fieldMap(@FieldMap Map<String, String> map);
    
            HashMap<String, String> map = new HashMap<>();
            map.put("id", "2");
            map.put("name", "zy");
            map.put("age", "28");
            Call<Blog> call = blogService.fieldMap(map);

服务端信息:

POST http://localhost:3434/retrofit/login?null HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Content-Length: 19
Content-Type: application/x-www-form-urlencoded
Host: localhost:3434
User-Agent: okhttp/3.14.9

name=zy&id=2&age=28

@Body

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Body {}
    @POST("retrofit/add")
    Call<Blog> addBlog(@Body Blog blog);
    
    Call<Blog> call = blogService.addBlog(new Blog("I am clint Blog!"));

服务端信息:

POST http://localhost:3434/retrofit/add?null HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Content-Length: 29
Host: localhost:3434
User-Agent: okhttp/3.14.9

Blog{body='I am clint Blog!'}

@Multipart + @Part

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Part {
  /**
   * The name of the part. Required for all parameter types except {@link
   * okhttp3.MultipartBody.Part}.
   */
  String value() default "";
  /** The {@code Content-Transfer-Encoding} of this part. */
  String encoding() default "binary";
}
    @Multipart
    @POST("retrofit/register")
    Call<Blog> registerUser(@Part MultipartBody.Part part, @Part("username") RequestBody username, @Part("password") RequestBody password);
 
            File file = new File("samples/build.gradle");
            RequestBody photoRequestBody = RequestBody.create(MediaType.parse("text/plain"), file);
            MultipartBody.Part photo = MultipartBody.Part.createFormData("fileName", "build.gradle", photoRequestBody);

            Call<Blog> call = blogService.registerUser(photo, RequestBody.create(null, "abc"), RequestBody.create(null, "123"));

服务端信息:

POST http://localhost:3434/retrofit/register?null HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Content-Length: 1002
Content-Type: multipart/form-data; boundary=f39f975d-5f5f-4d74-83e6-f7f8947ce749
Host: localhost:3434
User-Agent: okhttp/3.14.9

--f39f975d-5f5f-4d74-83e6-f7f8947ce749
Content-Disposition: form-data; name="fileName"; filename="build.gradle"
Content-Type: text/plain
Content-Length: 495

apply plugin: 'java-library'

dependencies {
  implementation project(':retrofit')
  implementation project(':retrofit-mock')
  implementation project(':retrofit-converters:moshi')
  implementation project(':retrofit-converters:gson')
  implementation project(':retrofit-converters:simplexml')
  implementation project(':retrofit-adapters:rxjava')
  implementation deps.mockwebserver
  implementation deps.guava
  implementation deps.jsoup
  compileOnly deps.findBugsAnnotations
}

--f39f975d-5f5f-4d74-83e6-f7f8947ce749
Content-Disposition: form-data; name="username"
Content-Transfer-Encoding: binary
Content-Length: 3

abc
--f39f975d-5f5f-4d74-83e6-f7f8947ce749
Content-Disposition: form-data; name="password"
Content-Transfer-Encoding: binary
Content-Length: 3

123
--f39f975d-5f5f-4d74-83e6-f7f8947ce749--

----------------------------------------------

@Multipart + @PartMap

@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface PartMap {
  /** The {@code Content-Transfer-Encoding} of the parts. */
  String encoding() default "binary";
}
    @Multipart
    @POST("retrofit/register")
    Call<Blog> registerUser(@PartMap Map<String, RequestBody> params);


            RequestBody requestBody1 = RequestBody.create(MediaType.parse("text/plain"), new File("samples/build.gradle"));
            RequestBody requestBody2 = RequestBody.create(MediaType.parse("text/plain"), new File("samples/src/main/java/com/example/test/PartMapTest.java"));
            
            HashMap<String, RequestBody> hashMap = new HashMap<>();
            hashMap.put("part1", requestBody1);
            hashMap.put("part2", requestBody2);
            hashMap.put("part3", RequestBody.create(null, "zy"));
            Call<Blog> call = blogService.registerUser(hashMap);

服务端信息:

POST http://localhost:3434/retrofit/register?null HTTP/1.1
Accept-Encoding: gzip
Connection: keep-alive
Content-Length: 2616
Content-Type: multipart/form-data; boundary=95335199-4456-48d3-b076-eadfdfe4a9c5
Host: localhost:3434
User-Agent: okhttp/3.14.9

--95335199-4456-48d3-b076-eadfdfe4a9c5
Content-Disposition: form-data; name="part1"
Content-Transfer-Encoding: binary
Content-Type: text/plain
Content-Length: 495

apply plugin: 'java-library'

dependencies {
  implementation project(':retrofit')
  implementation project(':retrofit-mock')
  implementation project(':retrofit-converters:moshi')
  implementation project(':retrofit-converters:gson')
  implementation project(':retrofit-converters:simplexml')
  implementation project(':retrofit-adapters:rxjava')
  implementation deps.mockwebserver
  implementation deps.guava
  implementation deps.jsoup
  compileOnly deps.findBugsAnnotations
}

--95335199-4456-48d3-b076-eadfdfe4a9c5
Content-Disposition: form-data; name="part2"
Content-Transfer-Encoding: binary
Content-Type: text/plain
Content-Length: 1588

package com.example.test;

import okhttp3.*;
import retrofit2.Call;
import retrofit2.Converter;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.http.*;

import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

public class PartMapTest {


    public static void main(String[] args) {

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(HttpUrl.get("http://localhost:3434/"))
                .addConverterFactory(Utils.FACTORY)
                .build();

        BlogService blogService = retrofit.create(BlogService.class);
        try {

            RequestBody requestBody1 = RequestBody.create(MediaType.parse("text/plain"), new File("samples/build.gradle"));
            RequestBody requestBody2 = RequestBody.create(MediaType.parse("text/plain"), new File("samples/src/main/java/com/example/test/PartMapTest.java"));

            HashMap<String, RequestBody> hashMap = new HashMap<>();
            hashMap.put("part1", requestBody1);
            hashMap.put("part2", requestBody2);
            hashMap.put("part3", RequestBody.create(null, "zy"));
            Call<Blog> call = blogService.registerUser(hashMap);

            Response<Blog> response = call.execute();
            Blog blog = response.body();
            System.out.println(blog);
        } catch (IOException e) {
            //e.printStackTrace();
        }


    }


}

--95335199-4456-48d3-b076-eadfdfe4a9c5
Content-Disposition: form-data; name="part3"
Content-Transfer-Encoding: binary
Content-Length: 2

zy
--95335199-4456-48d3-b076-eadfdfe4a9c5--

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值