目前的圖片上傳方式有很多種绑嘹,其中比較常見的好像都是跟阿里有關(guān)的唧席,跟阿里相關(guān)其中我們直接拿到阿里的key等信息钾军,直接進(jìn)行jar包的集成進(jìn)行上傳娄涩,但是這樣對(duì)于三方的key等信息容易泄漏窗怒,這里不建議使用,接下來(lái)就是對(duì)于表單的上傳蓄拣,這里也是可以直接上傳到阿里的服務(wù)器的扬虚,首先我們需要定義兩個(gè)參數(shù),對(duì)于我們所獲取到的照片進(jìn)行定義
private String headPath;//本地圖片地址
private String imageUrl = "";
然后需要接口先給我們返回到阿里的相關(guān)信息球恤,像文件夾辜昵、路徑地址等這些信息,然后同時(shí)我們需要對(duì)于表單上傳的一些參數(shù)進(jìn)行定義
String boundary = "---------------------------265001916915724";
String lineEnd = "\r\n";
String urlServer = "";
String key = "";
DataOutputStream dos = null;
HashMap<String, String> map = new HashMap<>();
HttpURLConnection connection = null;
FileInputStream fin = null;
int bytesAvailable, bufferSize, bytesRead;
int maxBufferSize = 1 * 1024 * 512;
byte[] buffer = null;
之后就是表單直接上傳到阿里服務(wù)的功能了咽斧,這里我們需要將接口獲取到阿里相關(guān)的信息進(jìn)行轉(zhuǎn)換路鹰、存放到上傳的參數(shù)當(dāng)中
//OssBean 是我們獲取到的接口信息封裝類贷洲,其中包含了我們所需要的阿里的各種信息
private void doGet(OssBean response) throws Exception {
urlServer = response.getHost();
key = response.getKey();
imageUrl = response.getUrl();
map.put("OSSAccessKeyId", response.getAccess_key_id());
map.put("policy", response.getPolicy());
map.put("Signature", response.getSignature());
map.put("key", response.getKey());
map.put("x-oss-security-token", response.getSts_token());
try {
Looper.prepare();
URL url = new URL(urlServer);
connection = (HttpURLConnection) url.openConnection();
//允許向URL流中讀寫數(shù)據(jù)
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(true);
//啟動(dòng)post方法
connection.setRequestMethod("POST");
//設(shè)置請(qǐng)求頭內(nèi)容
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "text/plain");
// 偽造請(qǐng)求頭
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
// 開始偽造POST Data里面的數(shù)據(jù)
dos = new DataOutputStream(connection.getOutputStream());
fin = new FileInputStream(headPath);
Log.e("圖片上傳", "開始上傳images");
// 開始連接
connection.connect();
//--------------------開始偽造上傳images.jpg的信息-----------------------------------
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
String string = "--" + boundary + "\r\n";
dos.write(string.getBytes());
String one = "Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n";//map key
dos.write(one.getBytes());
String tw = entry.getValue() + "\r\n";//map value
dos.write(tw.getBytes());
}
int last = key.lastIndexOf("/");
String keyEnd = key.substring(last + 1);//key值后
String fileMeta = "--" + boundary + lineEnd +
"Content-Disposition: form-data; name=\"file\"; filename=\"" + keyEnd + "\"" + lineEnd +
"Content-Type: image/jpeg" + lineEnd + lineEnd;
// 向流中寫入fileMeta
dos.write(fileMeta.getBytes());
// 取得本地圖片的字節(jié)流收厨,向url流中寫入圖片字節(jié)流
bytesAvailable = fin.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fin.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fin.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fin.read(buffer, 0, bufferSize);
}
dos.writeBytes(lineEnd + lineEnd);
//--------------------偽造images.jpg信息結(jié)束-----------------------------------
Log.e("圖片上傳", "結(jié)束上傳");
// POST Data結(jié)束
dos.writeBytes("--" + boundary + "--");
// Server端返回的信息
Log.e("圖片上傳", "code" + connection.getResponseCode());
Log.e("圖片上傳", "message" + connection.getResponseMessage());
if (dos != null) {
dos.flush();
dos.close();
}
uploadUser("", "", "", "", "", imageUrl);
Looper.loop();
} catch (Exception e) {
e.printStackTrace();
Log.e("圖片上傳", "上傳失敗");
}
}
我們自己直接將圖片上傳到阿里的服務(wù)器固然可行晋柱,但在實(shí)際的測(cè)試當(dāng)中,容易出現(xiàn)錯(cuò)誤和失敗的情況诵叁,而這種情況可以說(shuō)是五花八門雁竞,在項(xiàng)目中定位也是比較困難的,有的時(shí)候并沒有任何報(bào)錯(cuò)但就是上傳失敗拧额,也是很無(wú)奈啊╮(╯▽╰)╭ 所以在接口能夠支持的時(shí)候碑诉,我們最好的方法是通過(guò)retrofit進(jìn)行上傳,這種方法不但只需要幾行代碼就能搞定[比較輕松]侥锦,而且就前端而言我們不需要拿到任何關(guān)于阿里服務(wù)器的實(shí)質(zhì)性內(nèi)容信息进栽,對(duì)于信息保密也有一定的好處
Retrofit是一個(gè)用于安卓和java的http框架,通常我們會(huì)使用其進(jìn)行網(wǎng)絡(luò)的連接調(diào)用恭垦,這里我們說(shuō)一下他的另一種功能----以form表單上傳圖片的方法
首先需要添加gradle的引用
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
//noinspection GradleDependency 日志的攔截器
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.9'
//noinspection GradleDependency
implementation 'com.google.code.gson:gson:2.8.5'
然后需要定義一下我們的接口請(qǐng)求方式
@Multipart//這里用Multipart,不添加的話會(huì)引起崩潰反應(yīng)
@POST("/url")//請(qǐng)求方法為POST快毛,里面為你要上傳的url
//注解用@Part,參數(shù)類型為L(zhǎng)ist<MultipartBody.Part> 方便上傳其它需要的參數(shù)或多張圖片
fun uploadPic(@Part partLis:List<MultipartBody.Part> ):
CompletableCall<UploadPicBean>
這里我用的圖片選擇器是PictureSelector番挺,關(guān)于PictureSelector網(wǎng)上有很多的介紹唠帝,這里就不多做贅述了,有興趣可以多去了解一下玄柏,還是比較好用的一個(gè)微信圖片選擇器的(?▽?)
這里看到我們所選擇的圖片襟衰,接下來(lái)就是在點(diǎn)擊已完成之后的回調(diào)進(jìn)行表單圖片上傳了
//1.創(chuàng)建MultipartBody.Builder對(duì)象
MultipartBody.Builder builder = new MultipartBody.Builder()
//表單類型
.setType(MultipartBody.FORM)
//2.獲取圖片,創(chuàng)建請(qǐng)求體
File file=new File(path);
//表單類型
RequestBody body=RequestBody.create(MediaType.parse("multipart/form-data"),file);
//3.調(diào)用MultipartBody.Builder的addFormDataPart()方法添加表單數(shù)據(jù)
/**
* ps:builder.addFormDataPart("code","123456");
* ps:builder.addFormDataPart("file",file.getName(),body);
*/
builder.addFormDataPart(key, value);//傳入服務(wù)器需要的key粪摘,和相應(yīng)value值
builder.addFormDataPart(key,file.getName(),body); //添加圖片數(shù)據(jù)瀑晒,body創(chuàng)建的請(qǐng)求體
//4.創(chuàng)建List<MultipartBody.Part> 集合,
// 調(diào)用MultipartBody.Builder的build()方法會(huì)返回一個(gè)新創(chuàng)建的MultipartBody
// 再調(diào)用MultipartBody的parts()方法返回MultipartBody.Part集合
List<MultipartBody.Part> parts=builder.build().parts();
//5.最后進(jìn)行HTTP請(qǐng)求徘意,傳入parts即可
RetrofitHelper.create(ApiService.class)
.uploadPic(parts)
.enqueue(this, new AnimCallback<UploadPicBean>(context) {
@Override
protected void onError(Call<UploadPicBean> call, HttpError error) {
Log.e("圖片上傳", error.errorMessage);
}
@Override
protected void onSuccess(Call<UploadPicBean> call, UploadPicBean response) {
Log.e("圖片上傳", response.toString());
}
});
到這里我們的圖片就上傳完畢了苔悦,最后我們打開這個(gè)圖片鏈接可以發(fā)現(xiàn)和我們一開始所選擇的圖片是一模一樣的,(▽)