在上一讲中 Retrofit(二)、使用Retrofit+OkHttp下载文件并带进度条 中,我们知道如何用Retrofit去下载文件并返回进度。细心的你会发现,其实Retrofit接口enqueue方法,最终也是调用了OkHttp的enqueue方法。这一讲,我们来实现通过Retrofit实现多文件上传并时时监听进度!
一、服务器端
在服务器端新增一个PostFileServlet的Servlet来接收多文件的上传与保存,代码如下:
@WebServlet("/PostFileServlet")
@MultipartConfig
public class PostFileServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public PostFileServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("doPost==");
request.setCharacterEncoding("utf-8");
// 存储路径
String savePath = "D:/huang/upload";
// 把文件写到指定路径
Collection<Part> parts = request.getParts();
Iterator<Part> partIterator= parts.iterator();
while(partIterator.hasNext()){
Part part = partIterator.next();
String heard = part.getHeader("content-disposition");
String fileName = getFileName(heard);
System.out.println(heard);
part.write(savePath + File.separator + fileName);
}
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.print("上传成功");
}
public String getFileName(String header) {
String[] tempArr1 = header.split(";");
String[] tempArr2 = tempArr1[2].split("=");
// 获取文件名,兼容各种浏览器的写法
String fileName = tempArr2[1].substring(tempArr2[1].lastIndexOf("\\") + 1).replaceAll("\"", "");
return fileName;
}
}
启动我们的服务器。
二、Android端
1.在上一讲 Retrofit(二)、使用Retrofit+OkHttp下载文件并带进度条 的RetrofitUtil类中添加以下方法:
public static void postFileProgress(File file,File file2,final ProgressListener listener){
MultipartBody.Builder muBuilder = new MultipartBody.Builder();
muBuilder.addFormDataPart("file",file.getName(), RequestBody.create( MediaType.parse("multipart/form-data"),file));
muBuilder.addFormDataPart("file2",file2.getName(), RequestBody.create( MediaType.parse("multipart/form-data"),file2));
RequestBody originalRequestBody = muBuilder.build();
ProgressRequestBody progressRequestBody = new ProgressRequestBody(originalRequestBody,listener);
InterfaceRetrofit.PostFileRetrofit postFileRetrofit = retrofitBuilder.build().create(InterfaceRetrofit.PostFileRetrofit.class);
postFileRetrofit.postFile(progressRequestBody).enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
}
2.上传文件接口PostFileRetrofit
public interface PostFileRetrofit{
@POST("PostFileServlet")
Call<ResponseBody> postFile( @Body RequestBody partMap);
}
3.ProgressRequestBody代码如:
public class ProgressRequestBody extends RequestBody {
public static final int UPDATE = 0x01;
private RequestBody requestBody;
private ProgressListener mListener;
private BufferedSink bufferedSink;
private MyHandler myHandler;
public ProgressRequestBody(RequestBody body, ProgressListener listener) {
requestBody = body;
mListener = listener;
if (myHandler==null){
myHandler = new MyHandler();
}
}
class MyHandler extends Handler {
public MyHandler() {
super(Looper.getMainLooper());
}
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case UPDATE:
ProgressModel progressModel = (ProgressModel) msg.obj;
if (mListener!=null)mListener.onProgress(progressModel.getCurrentBytes(),progressModel.getContentLength(),progressModel.isDone());
break;
}
}
}
@Override
public MediaType contentType() {
return requestBody.contentType();
}
@Override
public long contentLength() throws IOException {
return requestBody.contentLength();
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
if (bufferedSink==null){
bufferedSink = Okio.buffer(sink(sink));
}
//写入
requestBody.writeTo(bufferedSink);
//刷新
bufferedSink.flush();
}
private Sink sink(BufferedSink sink) {
return new ForwardingSink(sink) {
long bytesWritten = 0L;
long contentLength = 0L;
@Override
public void write(Buffer source, long byteCount) throws IOException {
super.write(source, byteCount);
if (contentLength==0){
contentLength = contentLength();
}
bytesWritten += byteCount;
//回调
Message msg = Message.obtain();
msg.what = UPDATE;
msg.obj = new ProgressModel(bytesWritten,contentLength,bytesWritten==contentLength);
myHandler.sendMessage(msg);
}
};
}
}
4.调用:
RetrofitUtil.postFileProgress(new File(basePath + "/post1.jpg"), new File(basePath+"/post2.jpg"), new ProgressListener() {
@Override
public void onProgress(long currentBytes, long contentLength, boolean done) {
Log.i(TAG, "currentBytes==" + currentBytes + "==contentLength==" + contentLength + "==done==" + done);
int progress = (int) (currentBytes * 100 / contentLength);
refrofit_post_file_progress.setProgress(progress);
}
});
5.服务器端log
doPost==
form-data; name="file"; filename="post1.jpg"
form-data; name="file2"; filename="post2.jpg"
同时在d盘的目录下可看到相应文件:
注:写的比较简单,如果不懂的话,请看源码或参照前几讲!:>