Recently, the project used functions similar to uploading pictures and texts. In the past, they all included file upload functions that encapsulated OkHttp. This time I wanted to change my posture and use Retrofit 2.0 to implement such functions. I thought it was quite simple, but I didn't expect to enter the deep pit. After adjusting several postures in succession, I reported the same error. Then I found a big push for similar articles on the Internet. They were all ambiguous, or were not friendly enough to the multi-parameter format. Finally, I went to read the relevant source code and raised this problem to solve it myself. I will record it here.
1. Define the network request interface
public interface GoodsReturnApiService { @Multipart @POST(Compares.GOODS_RETURN_POST) //This is the address of your post file Observable<GoodsReturnPostEntity> postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map, @Part List<> parts); }
The above defines an interface for uploading file requests. There are several annotations that need to be explained. @Multipart is an annotation specially used for file upload by Retrofit and needs to be used with @POST.
Method postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map, @Part List<> parts) The first parameter uses annotation @PartMap for multi-parameter cases. If it is a single parameter, you can also use annotation @Part.
In the type Map<String, RequestBody>, the first generic String of the Map is the key used for file upload parameter fields. The second generic RequestBody is the Value of the upload parameter field wrapped in OkHttp3. This is also the key to the successful upload of the graphic text. I will talk about it in detail later.
The second parameter uses the annotation @Part for file upload, and multiple files use the collection type List<>, and a single file can use the type. The specific use will be discussed later.
Let me emphasize here that writing the postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map, @Part List<> parts) method parameters is purely a personal habit. You can also directly use a parameter postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map). However, the processing method of RequestBody will also change accordingly. I won't go into details here, I will only introduce the above simple and clear method.
2. Initialize Retrofit
public class HttpRequestClient { public static final String TAG = "HttpRequestClientTAG"; private static Retrofit retrofit; private static OkHttpClient getOkHttpClient() { //Log display level level= ; // Create a new log interceptor HttpLoggingInterceptor loggingInterceptor=new HttpLoggingInterceptor(new () { @Override public void log(String message) { (TAG, message); } }); (level); //Customize OkHttp httpClientBuilder = new OkHttpClient .Builder(); //OkHttp adds interceptor loggingInterceptor (loggingInterceptor); return (); } public static Retrofit getRetrofitHttpClient(){ if(null == retrofit){ synchronized (){ if(null == retrofit){ retrofit = new () .client(getOkHttpClient()) .baseUrl() .addConverterFactory(()) .addCallAdapterFactory(()) .build(); } } } return retrofit; } }
For demonstration, Retrofit encapsulation is relatively simple, so I won’t go into details to view network interception.
3. Initiate a file upload request
private void postGoodsPicToServer(){ Map<String,RequestBody> params = new HashMap<>(); //The following parameters are pseudo-code, and the parameters need to be replaced by the server supported by the server ("type", convertToRequestBody("type")); ("title",convertToRequestBody("title")); ("info",convertToRequestBody("info"); ("count",convertToRequestBody("count")); //To build data, it is also pseudo-code String path1 = () + + ""; String path2 = () + + ""; List<File> fileList = new ArrayList<>(); (new File(path1)); (new File(path2)); List<> partList = filesToMultipartBodyParts(fileList); ().create() .postGoodsReturnPostEntitys(params,partList) .subscribeOn(()) .observeOn(()) .subscribe(new Observer<GoodsReturnPostEntity>() { @Override public void onSubscribe(@NonNull Disposable d) { } @Override public void onNext(@NonNull GoodsReturnPostEntity goodsReturnPostEntity) { } @Override public void onError(@NonNull Throwable e) { } @Override public void onComplete() { } }); }
The above params and fileList are both constructed pseudo-codes and need to be changed according to the business needs of your own project.
The following is the first key to the file upload, and the content-type assignment of the parameter request header (let's call this name, corresponding to the parameter request header when uploading the file Retrofit, the file (picture) request header, and the file (request header) corresponding to the file request header).
private RequestBody convertToRequestBody(String param){ RequestBody requestBody = (("text/plain"), param); return requestBody; }
Because of the () converter, the content-type value of the parameter request header will be assigned by default application/json. If this conversion operation is not performed, such assignment can be viewed in the log interceptor of OKHttp3, which causes the server to not correctly identify the parameters and lead to upload failure. Therefore, a correct value is required for the content-type of the parameter request header: text/plain.
The following is the second key to the file upload successfully. Use the content-type of the file (image) request header to assign the value "image/png" to it using the method filesToMultipartBodyParts() and return the collection.
private List<> filesToMultipartBodyParts(List<File> files) { List<> parts = new ArrayList<>(()); for (File file : files) { RequestBody requestBody = (("image/png"), file); part = ("multipartFiles", (), requestBody); (part); } return parts; }
After all, it is still necessary to assign content-type attributes to the parameter request header and file (picture) request header. Do not let Retrofit assign default values. This is the key.
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.