[java] httpurlconnection multipart / form-data를 사용하여 배열 목록 업로드

Arraylist라이브러리를 사용하지 않고 이미지를 서버 에 업로드해야합니다 . 내가 사용하고 Asynctask하나의 이미지를 업로드 할 수 있으며, HttpURLConnection의 다중 / 폼 데이터의 도움으로 완벽하게 작동합니다. 이제 코드를 변경하여 모든 유형의 여러 파일을 사용하여 업로드해야 Arraylist<String>하지만 문제는 기존 코드가 FileinputStreamarraylist를 지원하지 않으며 Fileinputstreamarraylist를 서버에 업로드 하는 대신 무엇을 사용 해야할지 모르겠습니다. 이 라이브러리를 사용하고 싶습니다.

public class multipart_test extends AsyncTask<Void,Void,String> {
    Context context;
    String Images;
    public static final String TAG = "###Image Uploading###";


    public multipart_test(Context context,String Upload_Images) {
        this.context = context;
        this.Images = Upload_Images;

    }

    @Override
    protected String doInBackground(Void... params) {
        BufferedReader reader;
        String WebPath = null;
        try {
            String lineEnd = "\r\n";
            String twoHyphens = "--";
            String boundary = "*****";
            int bytesRead, bytesAvailable, bufferSize;
            byte[] buffer;
            int maxBufferSize = 1024 * 1024;
            //todo change URL as per client ( MOST IMPORTANT )
            URL url = new URL("10.0.0.1/uploadMultipart.php");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            // Allow Inputs &amp; Outputs.
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setUseCaches(false);

            // Set HTTP method to POST.
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
            FileInputStream fileInputStream;
            DataOutputStream outputStream;
            outputStream = new DataOutputStream(connection.getOutputStream());
            outputStream.writeBytes(twoHyphens + boundary + lineEnd);

            outputStream.writeBytes("Content-Disposition: form-data; name=\"reference\""+ lineEnd);
            outputStream.writeBytes(lineEnd);
            //outputStream.writeBytes("my_refrence_text");
            outputStream.writeBytes(lineEnd);
            outputStream.writeBytes(twoHyphens + boundary + lineEnd);

            outputStream.writeBytes("Content-Disposition: form-data; name=\"uploadFile\";filename=\"" + "profileImage" +"\"" + lineEnd);
            outputStream.writeBytes(lineEnd);

            //Dummy ArrayList for upload
            ArrayList<String> uploadFiles = new ArrayList<>();
            uploadFiles.add(Images);
            uploadFiles.add(Images);
            uploadFiles.add(Images);
            uploadFiles.add(Images);


            fileInputStream = new FileInputStream(uploadFiles); // NOT SUPPORTING ARRAYLIST HERE
            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            buffer = new byte[bufferSize];

            // Read file
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);

            while (bytesRead > 0) {
                outputStream.write(buffer, 0, bufferSize);
                bytesAvailable = fileInputStream.available();
                bufferSize = Math.min(bytesAvailable, maxBufferSize);
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);

            outputStream.writeBytes(lineEnd);
            outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
                fileInputStream.close();
            }
            // Responses from the server (code and message)
            int serverResponseCode = connection.getResponseCode();
            String result = null;
            if (serverResponseCode == 200) {
                StringBuilder s_buffer = new StringBuilder();
                InputStream is = new BufferedInputStream(connection.getInputStream());
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                String inputLine;
                while ((inputLine = br.readLine()) != null) {
                    s_buffer.append(inputLine);
                }
                result = s_buffer.toString();
            }
            connection.getInputStream().close();
            outputStream.flush();
            outputStream.close();
            if (result != null) {
                Log.d("result_for upload", result);
            }
            return WebPath;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


}

또한 FileInputStream루프 에 넣으려고했지만 여러 요청에 이미지를 업로드하는 것은 내가 원하는 것이 아닙니다. 내 서버는 n 개의 이미지를 단일 요청하도록 앱이 필요합니다. 라이브러리를 사용하지 않아도 도움이 될 것입니다.



답변

이 코드가 HttpURLConnection과 정확하게 작동한다면 시도하지 않았지만 참고해야합니다.

인터넷에서 읽은 내용에서 언급 한 루프를 여전히 사용할 수 있지만 몇 가지 수정 사항이 있습니다.

나는 multipart / form-data here dev.to 튜토리얼을 따라이 글을 더 많이 배우기 위해이 방법이 어떻게 진행되는지 알려 드리겠습니다.

다중 / 폼 데이터가 같이 전송된다

--boundary
Content-Disposition: form-data; name="something1"

data1
--boundary
Content-Disposition: form-data; name="something2"

data2
--boundary--

내가 할 일은 새로운 방법을 만드는 것이지만 기존 방법으로 코드를 작성할 수 있습니다.

public byte[] get_multipart_data(List<String> files, String boundary)

당신 은 처분 다음에 데이터가 따르는 경계 입니다. 모든 파일에 대해 그런 다음 닫는 경계 를 보냅니다 . 이것은 당신이 원하는 multipart / form-data 구조를 생성 할 것 입니다.

의사 코드에서 이것은

loop for all files
    write "--boundary"
    write "Content-Disposition: ...."
    write image_data
end
write "--boundary--"

코드는 다음과 같이 작성할 수 있습니다. 먼저 변수를 정의하십시오.

ByteArrayOutputStream message = null;
DataOutputStream stream = null;

FileInputStream fileInputStream;

int maxBufferSize = 1024 * 1024;
byte[] buffer = new byte[maxBufferSize];
byte[] sendData = new byte[0];

데이터가 생성되는 위치는 다음과 같습니다. 경계 를 연결 한 다음 데이터를 읽는 것으로 시작합니다. 해당 데이터는 스트림에 기록되며 모든 파일 / 이미지에 대한 루프를 계속합니다.

try {
    message = new ByteArrayOutputStream();
    stream = new DataOutputStream(message);

    // Loop though all file names
    for(String fileName : files) {
        stream.writeBytes("--" + boundary + "\r\n"); // Start boundary
        stream.writeBytes("Content-Disposition: form-data; name=\"" + fileName + "\"\r\n\r\n");

        // Read the image data
        fileInputStream = new FileInputStream(fileName);
        int readBytes = 0;
        while((readBytes = fileInputStream.read(buffer)) != -1) {
            // Write file data to output
            stream.write(buffer, 0, readBytes);
        }
        fileInputStream.close();

        stream.writeBytes("\r\n");
    }
    stream.writeBytes("--" + boundary + "--\r\n"); // Closing boundary

    sendData = message.toByteArray();
} catch(IOException e) {
    e.printStackTrace();
}

이제 바이트 배열 sendData에는 HttpURLConnection과 함께 보내야 하는 multipart / form-data 가 포함됩니다 .

나는 오랫동안 여기에서 활동적이지 않았습니다. 더 많은 사양이 필요하거나 내 텍스트를 분명히 밝히면 알려주십시오.


답변

FileinputStream 은 ArrayList를 지원하지 않습니다. 그러나 ObjectOutputStream 을 사용하는 방법이 있습니다 . 또한 ArrayList를 직렬화합니다. 코드 변경 사항을 확인하십시오.

       //Changes required in your code
        ArrayList<String> uploadFiles = new ArrayList<>();
        uploadFiles.add(Images);
        uploadFiles.add(Images);
        uploadFiles.add(Images);
        uploadFiles.add(Images);

        fileInputStream = new FileInputStream("listImages");
        java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fileInputStream);
        oos.writeObject(uploadFiles);

        bytesAvailable = fileInputStream.available();
        bufferSize = Math.min(bytesAvailable, maxBufferSize);
        buffer = new byte[bufferSize];
        ...
        ...
        ...
        oos.close();

행복한 코딩 🙂


답변

단일 비동기 작업을 사용해야하는지 확실하지 않습니다.

말했듯이 코드는 단일 이미지에 완벽하게 작동합니다. 따라서 arraylist에서 여러 파일을 업로드하려면 AsyncTask를 약간 수정하면됩니다. 한 파일을 다른 파일 로 업로드하기 만해도 수정을 많이하고 싶지 않다면 업로드중인 항목의 인덱스를 보유하는 전역 변수를 선언하고 OnPostExecute에서 비동기 작업의 새 인스턴스를 만들고 arraylist의 다음 항목을 전달하십시오. 이것이 분명하기를 바랍니다.


답변