天天看點

Android 上傳圖檔到伺服器(多檔案上傳)

Android用戶端的UI與《Android 上傳圖檔到伺服器(單檔案上傳)》唯一差別增加了多檔案上傳的功能。

1.Android用戶端多檔案上傳核心代碼:

* 多檔案上傳
     * @param view
     */
    public void multiUpload(View view){

        List<File> fileList = new ArrayList<>();
        for (ItemBean itemBean : list) {
            if (itemBean.isButton()) continue;
            fileList.add(itemBean.getImageFileBean().getFile());
            itemBean.getImageFileBean().setStartUpload(true);
            adapter.notifyDataSetChanged();
        }
        // 用上傳的檔案生成RequestBody
        if(fileList == null || fileList.size() == 0)return;

        //建立MultipartBody.Builder,用于添加請求的資料
        MultipartBody.Builder builder = new MultipartBody.Builder();
        for (int i = 0; i < fileList.size(); i++) { //對檔案進行周遊
            //根據檔案的字尾名,獲得檔案類型
            builder.setType(MultipartBody.FORM)
                    .addFormDataPart("name",fileList.get(i).getName())// 其他資訊
                    .addFormDataPart("id","12,13,14")// 其他資訊
                    .addFormDataPart("type","2"+i)// 其他信
                    .addFormDataPart( //給Builder添加上傳的檔案
                            "images",  //請求的名字
                            fileList.get(i).getName(), //檔案的文字,伺服器端用來解析的
                            RequestBody.Companion.create(fileList.get(i),MediaType.parse("multipart/form-data"))//建立RequestBody,把上傳的檔案放入
                    );
        }
        RequestBody requestBody = builder.build();//根據Builder建立請求
        Request request = new Request.Builder()
                .url(Global.MULTI_FILE_UPLOAD_URL)
                .post(requestBody)
                .addHeader("user-agent", "PDA")
                .addHeader("x-userid", "752332")// 添加x-userid請求頭
                .addHeader("x-sessionkey", "kjhsfjkaskfashfuiwf")// 添加x-sessionkey請求頭
                .addHeader("x-tonce", Long.valueOf(System.currentTimeMillis()).toString())// 添加x-tonce請求頭
                .addHeader("x-timestamp", Long.valueOf(System.currentTimeMillis()).toString())// 添加x-timestamp請求頭
                .build();

        final Message msg = myHandler.obtainMessage();
        OkHttpClient okHttpClient = new OkHttpClient();
        okHttpClient.newCall(request)
                .enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                msg.obj = list;
                msg.what =0;
                myHandler.sendMessage(msg);
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                String result = response.body().string();
                Log.i("上傳圖檔結果:", result);
                msg.obj = list;
                if (!response.isSuccessful()) {
                    Log.i("響應失敗:", response.code() + "");
                    msg.what =1;
                    return;
                }
                msg.what = 3;
                myHandler.sendMessage(msg);

            }
        });
    }      

2.伺服器端接收多檔案核心代碼:

/**
     * 多檔案上傳
     *
     * @param files
     * @param model
     * @param request
     * @return
     */
    @PostMapping("/api/multi_upload")
    public String multiFileUpload(@RequestParam(value = "images") MultipartFile[] files, Model model, HttpServletRequest request, @RequestParam(value = "type") int[] type, @RequestHeader(value = "user-agent") String userAgent) {
        if (files != null && files.length > 0) {
            System.out.println("檔案為空空");
        }

        for (int i : type) {
            logger.info("獲得的其他參數type=" + i);
        }

        logger.info("獲得的Header user-agent=" + userAgent);


        // 如果參數比較少可以直接在方法上使用注解@RequestParam來映射到不同的名稱上獲得,當然如果不用此注解,也可以定義一個與傳過來的參數名一樣的形參來獲得
        // 蒜從用戶端傳過來的其他參數
        Enumeration names = request.getParameterNames();
        while (names.hasMoreElements()) {
            String key = names.nextElement().toString();
            String[] values = request.getParameterValues(key);
            for(String str: values){
                String info = "用戶端傳過來的參數:key=" + key + ",value=" + str;
                logger.info(info);
            }

        }

        Enumeration headers = request.getHeaderNames();
        while (headers.hasMoreElements()) {
            String key = headers.nextElement().toString();
            String info = "用戶端傳過來的Header參數:key=" + key + ",value=" + request.getHeader(key);
            logger.info(info);
        }


        for (MultipartFile file : files) {
            saveFile(file);
        }
        return "上傳成功";
    }

    private String saveFile(MultipartFile file) {
        // BMP、JPG、JPEG、PNG、GIF
        String fileName = file.getOriginalFilename();  // 檔案名
        logger.info("上傳檔案名:" + fileName);
        String suffixName = fileName.substring(fileName.lastIndexOf("."));  // 字尾名
        // 驗證上傳的檔案是否圖檔
        if (!".bmp".equalsIgnoreCase(suffixName) && !".jpg".equalsIgnoreCase(suffixName)
                && !".jpeg".equalsIgnoreCase(suffixName)
                && !".png".equalsIgnoreCase(suffixName)
                && !".gif".equalsIgnoreCase(suffixName)) {
            return "上傳失敗,請選擇BMP、JPG、JPEG、PNG、GIF檔案!";
        }

        fileName = UUID.randomUUID() + suffixName; // 新檔案名
        File dest = new File(fileName);
        // 如果檔案的父路徑不存在,則建立
        if (fileName.startsWith("/") && !dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        // 開始存放檔案到指定目錄去
        try {
            file.transferTo(dest);
            return "上傳成功";
        } catch (IOException e) {
            e.printStackTrace();
            return "上傳失敗";

        }
    }      

Demo如下:

Hypertext Transfer Protocol
    POST /api/multi_upload HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): POST /api/multi_upload HTTP/1.1\r\n]
            [POST /api/multi_upload HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: POST
        Request URI: /api/multi_upload
        Request Version: HTTP/1.1
    user-agent: PDA\r\n
    x-userid: 752332\r\n
    x-sessionkey: kjhsfjkaskfashfuiwf\r\n
    x-tonce: 1592183885988\r\n
    x-timestamp: 1592183885988\r\n
    Content-Type: multipart/form-data; boundary=0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Content-Length: 59249\r\n
        [Content length: 59249]
    Host: 192.168.43.120:8080\r\n
    Connection: Keep-Alive\r\n
    Accept-Encoding: gzip\r\n
    \r\n
    [Full request URI: http://192.168.43.120:8080/api/multi_upload]
    [HTTP request 1/1]
    [Response in frame: 270]
    File Data: 59249 bytes
MIME Multipart Media Encapsulation, Type: multipart/form-data, Boundary: "0d03917a-192a-4b48-91b3-cae54dcbd929"
    [Type: multipart/form-data]
    First boundary: --0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part: 
        Content-Disposition: form-data; name="name"\r\n
        Content-Length: 36\r\n\r\n
        Data (36 bytes)
            Data: 313330633133303932316632343839663930663261656436…
            [Length: 36]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part: 
        Content-Disposition: form-data; name="id"\r\n
        Content-Length: 8\r\n\r\n
        Data (8 bytes)
            Data: 31322c31332c3134
            [Length: 8]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part: 
        Content-Disposition: form-data; name="type"\r\n
        Content-Length: 2\r\n\r\n
        Data (2 bytes)
            Data: 3230
            [Length: 2]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part:  (multipart/form-data)
        Content-Disposition: form-data; name="images"; filename="130c130921f2489f90f2aed6551f2c5f.jpg"\r\n
        Content-Type: multipart/form-data\r\n
        Content-Length: 47952\r\n\r\n
        The multipart dissector could not find a required parameter.
            [Expert Info (Error/Protocol): The multipart dissector could not find a required parameter.]
                [The multipart dissector could not find a required parameter.]
                [Severity level: Error]
                [Group: Protocol]
        Data (47952 bytes)
            Data: ffd8ffe12ee245786966000049492a00080000000b001001…
            [Length: 47952]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part: 
        Content-Disposition: form-data; name="name"\r\n
        Content-Length: 36\r\n\r\n
        Data (36 bytes)
            Data: 306432643236353564363332346234656238626235333763…
            [Length: 36]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part: 
        Content-Disposition: form-data; name="id"\r\n
        Content-Length: 8\r\n\r\n
        Data (8 bytes)
            Data: 31322c31332c3134
            [Length: 8]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part: 
        Content-Disposition: form-data; name="type"\r\n
        Content-Length: 2\r\n\r\n
        Data (2 bytes)
            Data: 3231
            [Length: 2]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part:  (multipart/form-data)
        Content-Disposition: form-data; name="images"; filename="0d2d2655d6324b4eb8bb537cac083cd0.jpg"\r\n
        Content-Type: multipart/form-data\r\n
        Content-Length: 6149\r\n\r\n
        The multipart dissector could not find a required parameter.
            [Expert Info (Error/Protocol): The multipart dissector could not find a required parameter.]
                [The multipart dissector could not find a required parameter.]
                [Severity level: Error]
                [Group: Protocol]
        Data (6149 bytes)
            Data: ffd8ffe10ad745786966000049492a00080000000b001001…
            [Length: 6149]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part: 
        Content-Disposition: form-data; name="name"\r\n
        Content-Length: 36\r\n\r\n
        Data (36 bytes)
            Data: 316431313536643461386238343033343839393963366464…
            [Length: 36]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part: 
        Content-Disposition: form-data; name="id"\r\n
        Content-Length: 8\r\n\r\n
        Data (8 bytes)
            Data: 31322c31332c3134
            [Length: 8]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part: 
        Content-Disposition: form-data; name="type"\r\n
        Content-Length: 2\r\n\r\n
        Data (2 bytes)
            Data: 3232
            [Length: 2]
    Boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929\r\n
    Encapsulated multipart part:  (multipart/form-data)
        Content-Disposition: form-data; name="images"; filename="1d1156d4a8b840348999c6ddd050df76.jpg"\r\n
        Content-Type: multipart/form-data\r\n
        Content-Length: 3407\r\n\r\n
        The multipart dissector could not find a required parameter.
            [Expert Info (Error/Protocol): The multipart dissector could not find a required parameter.]
                [The multipart dissector could not find a required parameter.]
                [Severity level: Error]
                [Group: Protocol]
        Data (3407 bytes)
            Data: ffd8ffe000104a46494600010100000100010000ffdb0043…
            [Length: 3407]
    Last boundary: \r\n--0d03917a-192a-4b48-91b3-cae54dcbd929--\r\n      

繼續閱讀