1. 程式人生 > >【網路】app(retorfit2+RxJava)+javaweb(伺服器) retrofit2官方文件實踐

【網路】app(retorfit2+RxJava)+javaweb(伺服器) retrofit2官方文件實踐

tjstudy:寫在前面,開發環境

app環境:
android studio 2.1.1
minSdkVersion 14
targetSdkVersion 23

javaweb server 環境:
MyEclipse 10
jdk 1.6

一 、最基本的標記

@GET @POST 標記:網路訪問方式的最基本標記
指定訪問方式,一般會寫入訪問地址,如果是獲取的資料,還可以進行排序。
建議:base_url,最好以/結尾 @GET @POST裡面的地址不以/開頭。

@GET("users/list ")
@POST("users/list?dort=asc")

二 、POST 和GET方式,通用retorfit 標記

POST GET 通用:@Path @Query @QueryMap @Header
兩者通用的標記:主要是指使用使用@POST 和@GET方式都能夠接收到資料資訊,顯示效果差不多,實際開發中,根據要求使用的網路方式來進行選擇
下面演示的效果大多為@GET,POST方式直接將GET 換成POST 查看了即可。

1 、 @Path:指定訪問路徑

@GET("{name}/UploadParam")
Observable<ResponseBody> test(@Path("name")String name);

動態傳入的String 會取代{name}作為新的訪問地址
這個時候訪問的地址就是,base_url+name+/UploadParam

這裡寫圖片描述

2 、@Query :提交引數—-不是表單提交,只是普通提交

@GET("servlet/UploadParam")
Observable<ResponseBody> testQuery(@Query("name") String name);

伺服器結果:

這裡寫圖片描述

3 、@QueryMap:是@Query的集合形式,能夠攜帶更多的引數

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

只需要將要攜帶的引數都put到Map集合裡面,傳進來就可以了。

4 、@Header :在網路訪問中新增Header資訊

@Headers({
        "appkey:tjstudy _ 2016 10 23"
})
@GET("servlet/HeaderTest")
Observable<ResponseBody> testHeader(@Query("name") String name);

伺服器結果:

這裡寫圖片描述

@Header 也可以直接放到實際請求引數中,效果和上面一致

@GET("servlet/HeaderTest")
Observable<ResponseBody> testHeader(@Header(“appkey”) 
String appkey,@Query("name") String name);

三、必須POST方式(@body @FormUrlEncoded @Multipart)

使用GET方式 + 上面的任意標記 都會報錯。並且這三個標記不能混合使用,否則會報錯。

1、@Body:上傳一個物件

@POST("servlet/TestBody")
Observable<ResponseBody> testBody(
       @Body User user
);

伺服器結果:

這裡寫圖片描述

是否可以上傳兩個物件?
在上述程式碼中添加了另一個User,直接報錯…..貌似只能上傳一個物件

2、@FormUrlEncoded:表單提交 和@Field 配對,訪問過程中,引數中至少有一個@Field

@FormUrlEncoded
@POST("servlet/TestFormUrlEncodes")
Observable<ResponseBody> testFormUrlEncoded(
        @Field("param1") String first,
        @Field("param2") String last
);

伺服器結果:

這裡寫圖片描述

@FormUrlEncoded 標記的方法中,至少要有一個引數是@Field 標記的引數,否則會報錯。人家是配對的,別拆散他們。其他的引數可以是其他的標記,例如:@Query (雖然沒必要,但是至少這種情況不會報錯)。

3、@Multipart:檔案等上傳 和@Part 配對 訪問過程中,引數中至少有一個@Part

RequestBody 可以封裝什麼樣的型別,@Multipart就能將這樣型別的資料上傳到伺服器。RequestBody可以封裝文字,圖片檔案,音訊檔案等。

這裡列舉的是圖片檔案
伺服器怎麼接收檔案,這裡使用fileupload 來接收(需要引入fileupload相關包commons-fileupload-1.3和commons-io-1.2 可在程式碼中找到)。主要程式碼:

PrintWriter pw = response.getWriter();
        // 建立檔案專案工廠物件
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 設定檔案上傳路徑
        File uploadDir = new File(this.getServletContext().getRealPath(
                "/upload/"));// 設定檔案上傳的路徑為專案名/upload/
        System.out.println("檔案上傳的路徑=" + uploadDir);
        if (!uploadDir.exists()) {// 如果改資料夾不存在就建立
            uploadDir.mkdirs();
        }
        // 獲取系統預設的臨時檔案儲存路徑,該路徑為Tomcat根目錄下的temp資料夾
        String temp = System.getProperty("java.io.tmpdir");
        // 設定緩衝區大小為 5M
        factory.setSizeThreshold(1024 * 1024 * 5);
        // 設定臨時資料夾為temp
        factory.setRepository(new File(temp));
        // 用工廠例項化上傳元件,ServletFileUpload 用來解析檔案上傳請求
        ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
        try {
            List<FileItem> list = servletFileUpload.parseRequest(request);
            System.out.println("檔案的個數=" + list);
            for (FileItem fileItem : list) {
                if(fileItem==null){
                    System.out.println("獲取到的檔案是空的");
                    break;
                }
                File file = new File(uploadDir, fileItem.getFieldName()+".png");
                if (!file.exists()) {// 檔案不存在才建立
                    fileItem.write(file);// 儲存檔案
                    System.out.println("檔名:" + file.getName());
                }
            }
            pw.write("{\"message\":\"上傳成功\"}");
            System.out.println("{\"message\":\"上傳成功\"}");
        } catch (Exception e) {
            pw.write("{\"message\":\"上傳失敗\"}");
            System.out.println("{\"message\":\"上傳失敗\"}");
        }
1)、@Mutipart + RequestBody上傳單檔案
File imageFile = new File(Environment.getExternalStorageDirectory().getPath(),"123.png");
RequestBody imageRequestBody = RequestBody.create(MediaType.parse("image/png"), imageFile);
@Multipart
@POST("servlet/TestMultipart")
Observable<ResponseBody> testSingleMultipart(
        @Part("photo") RequestBody image
);

伺服器結果:

這裡寫圖片描述

2)、@Mutipart + RequestBody上傳單檔案 和引數

由於這裡上傳的檔案和接收的路徑都是一樣的,在新操作之前,需要先把已經上傳的檔案刪除。

@Multipart
@POST("servlet/TestSingleMultipartParam")
Observable<ResponseBody> testSingleMultipartParam(
        @Part("photo") RequestBody image,
        @Query("des") String des
);

不能使用@FormUrlEncoded提交引數,使用會報錯
伺服器結果:

這裡寫圖片描述

3)、@Mutipart + RequestBody上傳多檔案和引數
@Multipart
@POST("servlet/TestMultipartMoreFile")
Observable<ResponseBody> testMoreMultipartParam(
        @Part("photo1") RequestBody image1,
        @Part("photo2") RequestBody image2,
        @Query("des") String des
);

原始檔只是一張圖片
伺服器結果:

這裡寫圖片描述

4)、@PartMap 上傳檔案和引數
@Multipart
@POST("servlet/TestPostMultipartBodyPart")
Observable<ResponseBody> testMultipartBodyMap(
        @Query("des") String des,
        @PartMap Map<String, RequestBody> images
);

伺服器結果:

這裡寫圖片描述

5)、@Multipart 檔案上傳的另外一種方式——MultipartBody.Part

注意MultipartBody是okhttp3的一個方法,在okhttp2裡面不存在。這裡使用的是Retrofit2 所以自帶的是Okhttp3
它和RequestBody的關係:

File file = new File(Environment.getExternalStorageDirectory()
            .getAbsolutePath() + "123.png");
RequestBody requestBody =
            RequestBody.create(MediaType.parse("image/png"), file);
//引數1 陣列名,引數2 檔名。
MultipartBody.Part photo1part = 
            MultipartBody.Part.createFormData("pic1", "pic2", requestBody1);

MultipartBody.part 其實就是對RequestBody的封裝

@Multipart
@POST("servlet/TestPostMultipartBodyPart")
Observable<ResponseBody> testMultipartBody(
        @Part("photo1") RequestBody image1,
        @Part MultipartBody.Part image2,
        @Query("des")String des

);

這裡使用的是兩種上傳方式
伺服器結果:

這裡寫圖片描述

疑惑:明明直接使用ResponseBody 就能完成檔案上傳,為什麼還要使用MultipartBody.part? 根據目前接觸的網路訪問操作,疑惑未解決。
//todo 為什麼呢?

另外:怎麼下載檔案?操作比較簡單
下載檔案主要是對流的操作,伺服器將流寫入到ResponseBody裡面返回到客戶端就好了。客戶端獲取到流,然後進行操作。

四、完整demo

app效果圖

這裡寫圖片描述