1.文件上傳
主要使用RequestBody
和MultipartBody.Builder
兩個對象
1.1 上傳一個40M視頻
OkHttp
版本為 3.5
Activity代碼:
上傳主要用到一個MultipartBody.Builder
來添加文件犀呼,addFormDataPart()
方法里面對請求頭做些封裝抡驼,一般不用再自己添加請求頭信息
class UploadActivity extends AppCompatActivity {
private Platform mPlatform;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upload);
mPlatform = Platform.get();
init();
}
private void init() {
Button button = (Button) findViewById(R.id.upload_activity_bt_img);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
uploadTextFile();
}
});
}
/**
* 上傳一個40M的視頻文件
*/
private void uploadTextFile() {
String filePath = Environment.getExternalStorageDirectory()
+ File.separator + Strings.FILE_PATH + File.separator + Strings.FILE_NAME;
File file = new File(filePath);
if (file.exists()) {
OkHttpClient okHttpClient = new OkHttpClient.Builder().connectTimeout(10, TimeUnit.SECONDS).build();
//MediaType 為全部類型
final MediaType mediaType = MediaType.parse("application/octet-stream");
//根據(jù)文件類型争占,將File裝進(jìn)RequestBody中
RequestBody fileBody = RequestBody.create(mediaType, file);
//將fileBody添加進(jìn)MultipartBody
RequestBody requestBody = new MultipartBody.Builder()
.addFormDataPart("file", Strings.FILE_NAME, fileBody)
.build();
//Request請求對象
Request request = new Request.Builder().post(requestBody).url(Urls.UPLOAD_URL).build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, final IOException e) {
mPlatform.execute(new Runnable() {
@Override
public void run() {
ToastUtils.show(UploadActivity.this, e.getMessage());
}
});
}
@Override
public void onResponse(Call call, final Response response) throws IOException {
//請求結(jié)果
ResponseBody responseBody = null;
try {
//獲取請求結(jié)果 ResponseBody
responseBody = response.body();
//獲取字符串
final String info = responseBody.string();
mPlatform.execute(new Runnable() {
@Override
public void run() {
ToastUtils.show(UploadActivity.this, info);
}
});
} catch (Exception e) {//發(fā)生異常砰盐,失敗回調(diào)
e.printStackTrace();
} finally {//記得關(guān)閉操作
if (null != responseBody) {
responseBody.close();
}
}
}
});
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Handler handler = new Handler(Looper.getMainLooper());
handler.removeCallbacksAndMessages(null);
}
}
上傳的文件封裝進(jìn)RequestBody
中闷袒,創(chuàng)建RequestBody
需要用到MediaType
封裝帶有文件的RequestBody
可以直接通過使用MutipartBody.Builder
來添加給Request
:
new MultipartBody.Builder().addFormDataPart("file", Strings.FILE_NAME, fileBody).build()
1.2 上傳進(jìn)度
直接使用了Toast
來顯示當(dāng)前進(jìn)度
上傳進(jìn)度需要重寫RequestBody
1.2.1 ProgressRequestBody
public class ProgressRequestBody extends RequestBody {
private File mFile;
private MediaType mMediaType;
private UploadProgress mUploadProgress;
public ProgressRequestBody(File mFile, MediaType mMediaType, UploadProgress mUploadProgress) {
this.mFile = mFile;
this.mMediaType = mMediaType;
this.mUploadProgress = mUploadProgress;
}
@Override
public long contentLength() throws IOException {
return mFile.length();
}
@Override
public MediaType contentType() {
return mMediaType;
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
long max = contentLength();
long current = 0;
Source source = Okio.source(mFile);
Buffer buffer = new Buffer();
for (long readCount; (readCount = source.read(buffer, 1024 * 8)) != -1; current += readCount) {
sink.write(buffer, readCount);
int progress = (int) (100 * current / max);
mUploadProgress.progress(progress);
}
}
public interface UploadProgress {
void progress(int progress);
}
}
重寫RequestBody
的3個方法,重點是writeTo(BufferedSink sink)
方法岩梳,根據(jù)當(dāng)前的已寫字節(jié)數(shù)來計算已經(jīng)上傳的百分比
里面用到了Okio
-
Sink
用來寫囊骤,相當(dāng)于OutputStream
-
Source
用來讀,相當(dāng)于InputStream
-
Buffer
蒋腮,緩沖淘捡,Okio
高效讀寫的關(guān)鍵
OKio
需要單獨再進(jìn)行學(xué)習(xí)
1.2.2 使用
只需要將1.1
中的fileBody
,使用ProgressRequestBody
替換即可
// RequestBody fileBody = RequestBody.create(mediaType, file);
RequestBody fileBody = new ProgressRequestBody(file, mediaType, new ProgressRequestBody.UploadProgress() {
@Override
public void progress(final int progress) {
mPlatform.execute(new Runnable() {
@Override
public void run() {
ToastUtils.show(UploadActivity.this, progress + "%");
}
});
}
});
Okio
的讀寫操作不在UI
線程池摧,不可直接更新UI
上傳多個文件,只需要將多個文件分別都封裝進(jìn)RequestBody
中激况,多次使用MultipartBody.Builder()
的addFormDataPart()
方法都加入上傳任務(wù)中就可以
new MultipartBody.Builder()
.addFormDataPart("file", fileName1, fileBody1)
.addFormDataPart("file", fileName2, fileBody2)
...
.addFormDataPart("file", fileNameX, fileBodyX)
.build();
Okio
作彤,OkHttp
真的是超級好用膘魄,超級強(qiáng)大
2. 后臺Web應(yīng)用代碼
自己學(xué)習(xí)寫了一段最基礎(chǔ)的上傳后臺部分的代碼
- 添加
apache
的commons-fileupload
的Maven
依賴 - 重寫
doPost()
方法 - 在
web.xml
,添加Servlet
映射
OKHttpServlet
public class OKHttpServlet extends HttpServlet {
private ServletFileUpload mServletFileUpload;
/*
* 初始化 ServletFileUpload
*/
private void initUp() {
if (null == mServletFileUpload) {
File file
= (File) getServletContext().getAttribute("javax.servlet.context.tempdir");
mServletFileUpload = new ServletFileUpload(new DiskFileItemFactory(
DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD, file
));
mServletFileUpload.setFileSizeMax(1024L * 1024 * 100);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
initUp();
resp.setHeader("Content-Type", "text/html;charset=utf-8");//指定編碼
Map<String, List<FileItem>> fileItemListMap = mServletFileUpload.parseParameterMap(req);
for (Map.Entry<String, List<FileItem>> entry : fileItemListMap.entrySet()) {
List<FileItem> fileItemList = entry.getValue();
if (!fileItemList.isEmpty()) {
for (FileItem fileItem : fileItemList) {
if (!fileItem.isFormField()) {//取非表單屬性 竭讳,也就是文件
String fileName =
FilenameUtils.getName(new String(fileItem.getName().getBytes(), "utf-8"));
InputStream inputStream = fileItem.getInputStream();
File file = new File(Stirngs.FILE_PATH, fileName);
FileOutputStream fileOutputStream = new FileOutputStream(file);
byte[] bytes = new byte[1024 * 8];
int len;
while ((len = inputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, len);
fileOutputStream.flush();
}
fileOutputStream.close();
PrintWriter writer = resp.getWriter();
writer.print(fileName + " ----> ok!!!!!");//成功 创葡,返回個響應(yīng)
writer.flush();
}
}
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
自己動手豐衣足食,代碼雖爛绢慢,但這樣不用使用別人的接口來實現(xiàn)上傳了灿渴,哈哈
3. 最后
有錯誤,請指出
共勉 :)