Android使用Retrofit進(jìn)行表單上傳圖片功能

目前的圖片上傳方式有很多種绑嘹,其中比較常見的好像都是跟阿里有關(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表單上傳圖片的方法

Retrofit官網(wǎng)

首先需要添加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());
            }
        });
請(qǐng)求成功抓包展示

到這里我們的圖片就上傳完畢了苔悦,最后我們打開這個(gè)圖片鏈接可以發(fā)現(xiàn)和我們一開始所選擇的圖片是一模一樣的,()

網(wǎng)頁(yè)打開圖片鏈接的展示
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末映砖,一起剝皮案震驚了整個(gè)濱河市间坐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌邑退,老刑警劉巖竹宋,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異地技,居然都是意外死亡蜈七,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門莫矗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)飒硅,“玉大人砂缩,你說(shuō)我怎么就攤上這事∪洌” “怎么了庵芭?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)雀监。 經(jīng)常有香客問我双吆,道長(zhǎng),這世上最難降的妖魔是什么会前? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任好乐,我火速辦了婚禮,結(jié)果婚禮上瓦宜,老公的妹妹穿的比我還像新娘蔚万。我一直安慰自己,他們只是感情好临庇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布反璃。 她就那樣靜靜地躺著,像睡著了一般苔巨。 火紅的嫁衣襯著肌膚如雪版扩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天侄泽,我揣著相機(jī)與錄音礁芦,去河邊找鬼。 笑死悼尾,一個(gè)胖子當(dāng)著我的面吹牛柿扣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闺魏,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼未状,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了析桥?” 一聲冷哼從身側(cè)響起司草,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎泡仗,沒想到半個(gè)月后埋虹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡娩怎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年搔课,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片截亦。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爬泥,死狀恐怖柬讨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情袍啡,我是刑警寧澤踩官,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站葬馋,受9級(jí)特大地震影響卖鲤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜畴嘶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望集晚。 院中可真熱鬧窗悯,春花似錦、人聲如沸偷拔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)莲绰。三九已至欺旧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蛤签,已是汗流浹背辞友。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留震肮,地道東北人称龙。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像戳晌,于是被迫代替她去往敵國(guó)和親鲫尊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容