Retrofit 2.0 单文件、多文件上传

来源:互联网 发布:手机怎么破解网络限制 编辑:程序博客网 时间:2024/06/05 10:26

最近项目空档期,学习了一下Retrofit 2.0文件上传,在网上查了好多资源,也踩了好多坑,还好经过努力,Retrofit2.0单文件、多文件上传的一个小demo弄出来了,记录下来方便以后自己查阅使用。

依赖:

compile 'com.android.support:appcompat-v7:24.2.0'compile 'com.squareup.retrofit2:retrofit:2.0.2'compile 'com.squareup.retrofit2:converter-gson:2.0.2'compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'

使用Retrofit 2.0 上传文件,需要使用:Part & PartMap。

<span style="font-family:Microsoft YaHei;font-size:18px;">@Part,@PartMap:用于POST文件上传 其中@Part MultipartBody.Part代表文件,@Part(“key”) RequestBody代表参数 需要添加@Multipart表示支持文件上传的表单,Content-Type: multipart/form-data</span>

一、单文件上传:

@Multipart@POST("UploadServer")Call<BaseResponse<String>> upload(@Part("description") RequestBody description,                                  @Part MultipartBody.Part file);
我们用这种方法提交单文件,下面是这个借口的使用方法:

创建Api类获取FileUploadService:

public class Api {    private static FileUploadService SERVICE;    private static final String BASE_URL = "http://192.168.1.100:8080/UploadFileServer/";    public static FileUploadService getDefault() {        if(SERVICE == null) {            OkHttpClient client = new OkHttpClient.Builder().build();            SERVICE = new Retrofit.Builder()                    .baseUrl(BASE_URL)                    .addConverterFactory(GsonConverterFactory.create())                    .client(client)                    .build().create(FileUploadService.class);        }        return SERVICE;    }}
activity里调用接口:

private void uploadMonofile(String filename){    //先创建 service    FileUploadService service = Api.getDefault();    //构建要上传的文件    File file = new File(filename);    RequestBody requestFile =            RequestBody.create(MediaType.parse("application/otcet-stream"), file);    MultipartBody.Part body =            MultipartBody.Part.createFormData("aFile", file.getName(), requestFile);    String descriptionString = "This is a description";    RequestBody description =            RequestBody.create(                    MediaType.parse("multipart/form-data"), descriptionString);    Call<BaseResponse<String>> call = service.upload(description, body);    call.enqueue(new Callback<BaseResponse<String>>() {        @Override        public void onResponse(Call<BaseResponse<String>> call,                               Response<BaseResponse<String>> response) {            System.out.println("success");            Logger.e("success:" + response.body().getResultMessage());        }        @Override        public void onFailure(Call<BaseResponse<String>> call, Throwable t) {            t.printStackTrace();            Logger.e("error:" + t.getMessage());        }    });}

第二、多文件上传:

定义一个上传的网络请求Service:

/** * 通过 List<MultipartBody.Part> 传入多个part实现多文件上传 * @param parts 每个part代表一个 * @return 状态信息 */@Multipart@POST("UploadServer")Call<BaseResponse<String>> uploadFilesWithParts(@Part() List<MultipartBody.Part> parts);/** * 通过 MultipartBody和@body作为参数来实现多文件上传 * @param multipartBody MultipartBody包含多个Part * @return 状态信息 */@POST("UploadServer")Call<BaseResponse<String>> uploadFileWithRequestBody(@Body MultipartBody multipartBody);

由上可知,有两种方式实现上传

  • 使用@Multipart注解方法,并用@Part注解方法参数,类型是List<okhttp3.MultipartBody.Part>
  • 不使用@Multipart注解方法,直接使用@Body注解方法参数,类型是okhttp3.MultipartBody

可以看到,无论方法参数类型是MultipartBody.Part还是MultipartBody,这些类都不是Retrofit的类,而是okhttp实现上传的源生类。

写好service接口后,来看看怎么构造MultipartBody
可以写一个方法,用于把File对象转化成MultipartBody:

public static MultipartBody filesToMultipartBody(List<File> files) {    MultipartBody.Builder builder = new MultipartBody.Builder();    for (File file : files) {        // TODO: 16-4-2  这里为了简单起见,没有判断file的类型        RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);        builder.addFormDataPart("aFile", file.getName(), requestBody);    }    builder.setType(MultipartBody.FORM);    MultipartBody multipartBody = builder.build();    return multipartBody;}
或者把File转化成MultipartBody.Part:

public static List<MultipartBody.Part> filesToMultipartBodyParts(List<File> files) {    List<MultipartBody.Part> parts = new ArrayList<>(files.size());    for (File file : files) {        // TODO: 16-4-2  这里为了简单起见,没有判断file的类型        RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);        MultipartBody.Part part = MultipartBody.Part.createFormData("aFile", file.getName(), requestBody);        parts.add(part);    }    return parts;}
在Activity里调用接口

private void uploadMultifile(ArrayList<File> mFileList) {    MultipartBody body = MultipartBuilder.filesToMultipartBody(mFileList);    Api.getDefault().uploadFileWithRequestBody(body)            .enqueue(new Callback<BaseResponse<String>>() {                @Override                public void onResponse(Call<BaseResponse<String>> call, Response<BaseResponse<String>> response) {                    Logger.e("onResponse--" + response.body().getResultMessage());                    if (response.isSuccessful()) {                        BaseResponse<String> body = response.body();                        Logger.e("onResponse----success" );                    } else {                        Log.d(TAG,"上传失败");                        Logger.e("onResponse----fail" );                    }                }                @Override                public void onFailure(Call<BaseResponse<String>> call, Throwable t) {                    Logger.e("onResponse----onFailure"+ t.getMessage());                }            });}
至此客户端核心代码基本完成,

服务器核心代码:

需要用到两个重要的jar:commons-fileupload-1.2.1.jar   commons-io-1.4.jar

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("有文件提交");
// 设置response的编码格式
response.setHeader("Content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("utf-8");


// 创建文件项目工厂对象
DiskFileItemFactory factory = new DiskFileItemFactory();


// 设置文件上传路径
// String upload = this.getServletContext().getRealPath("/");
String upload = "D:/aa/image/";

// 获取系统默认的临时文件保存路径,该路径为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);


// 解析结果放在List中
try {
List<FileItem> list = servletFileUpload.parseRequest(request);


for (FileItem item : list) {
String name = item.getFieldName();
InputStream is = item.getInputStream();


System.out.println("the current name is " + name);


if (name.contains("aFile")) {
try {
inputStream2File(is, upload + "\\" + /*
* System.
* currentTimeMillis
* () +
*/item.getName());
} catch (Exception e) {
e.printStackTrace();
}
} else {
String key = item.getName();
String value = item.getString();
System.out.println(key + "---" + value);
}
}


// out.write("success");
Gson gson = new Gson();
ResponseData data = new ResponseData<String>(200, "成功", "上传了文件");
String gsonStr = gson.toJson(data);


System.out.println("响应数据::" + gsonStr);
response.getWriter().print(gsonStr);
} catch (FileUploadException e) {
e.printStackTrace();
System.out.println("failure");
}
PrintWriter out = response.getWriter();
out.flush();
out.close();
}


// 流转化成字符串
public static String inputStream2String(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = -1;
while ((i = is.read()) != -1) {
baos.write(i);
}
return baos.toString();
}


// 流转化成文件
public static void inputStream2File(InputStream is, String savePath)
throws Exception {
System.out.println("the file path is  :" + savePath);
File file = new File(savePath);
InputStream inputSteam = is;
BufferedInputStream fis = new BufferedInputStream(inputSteam);
FileOutputStream fos = new FileOutputStream(file);
int f;
while ((f = fis.read()) != -1) {
fos.write(f);
}
fos.flush();
fos.close();
fis.close();
inputSteam.close();


}


至此一个Retrofit 2.0 上传单文件、多文件的小demo就完成了

注意:Retrofit 2.0 依赖不要使用:'com.squareup.retrofit2:retrofit:2.0.0-beta4'  beta版,说多了都是泪啊。

参考:

http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=1117

http://www.chenkaihua.com/2016/04/02/retrofit2-upload-multipart-files.html

还有参考其他的,不过忘记了。sorry!尴尬


源码下载






0 0
原创粉丝点击