【網路】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效果圖