본문 바로가기
프로그래밍/Java-자주쓰는예제

【Java-데이터 통신】Postman 처럼 HTTP 통신하기 - 3.파일 업로드(Multipart/form-data)

by 코이킹 2021. 10. 1.
반응형

1. 설명 

안녕하세요 코이킹입니다. 
이 포스트에서 다룰 예제는 HTTP 요청을 보낼 때의 콘텐츠 타입을 Multipart/form-data 방식으로 설정하여 
HTTP요청과 함께 API에 파일을 업로드하는 코드가 되겠습니다. 

 

2. 소스코드

- 메서드 

	// For Multipart File data Upload
	private PrintWriter writer;
	private String BOUNDARY = "-----";
	private String LINEFEED = "\r\n";
    
public boolean request(String protocol, String targetUrl, Map<String, String> settings, Map<String, String> params, File ...files) {
		// 파일 한개 전송시는 file, 여러개 전송시는 files로 파라미터 설정
		String fileParam = ( 2 <= files.length ) ? "files" : "file";
		BufferedReader buff = null;
		try {
			// URL에 해당하는 Connection 객체 생성
			setConnection(protocol, targetUrl);
			
			// Request 준비
			settings.put("Content-Type", "multipart/form-data;charset=utf-8;boundary=" + BOUNDARY);
			requestSetting(settings);
			
			os = this.con.getOutputStream();
			writer = new PrintWriter(new OutputStreamWriter(os, "utf-8"), true);
			
			
			for (String headerInfoKey : params.keySet()) {
				addHeaderField(headerInfoKey, settings.get(headerInfoKey));
			}
			
			for (File file : files) {
				addFilePart(fileParam, file);
			}
			
			writer.append(LINEFEED).flush();
	        writer.append("--" + BOUNDARY + "--").append(LINEFEED);
	        writer.close(); // -- 보내야할 데이터 설정완료, 요청보내기
	        
			// 응답 확인하기
			int responseCode = this.con.getResponseCode();
			
			if(responseCode == HttpURLConnection.HTTP_OK) {
				buff = new BufferedReader(
						new InputStreamReader(this.con.getInputStream(),"utf-8"));
				
				if (!responseBody.readResult(buff)) {
					throw new Exception();
				}
				
			} else {
				System.err.println("ResponseCode : " + con.getResponseCode() +", ResponseMessage" + con.getResponseMessage());
				return false;
			}
	        
			return true;
		} catch (Exception e) { 
			e.printStackTrace(); 
			return false;
			
		} finally {
			try {
				if (buff != null) {
					buff.close();
	    		    buff = null;
				}
	    		this.con.disconnect();
	    		this.con = null;
				this.os.close(); 
				this.os = null;
			} catch (IOException e) {  e.printStackTrace(); }
		}
		
	}
	
private void addHeaderField(String name, String value) {
        writer.append(name + ": " + value).append(LINEFEED);
        writer.flush();
    }
    
private void addFilePart(String fieldName, File uploadFile)
            throws IOException {
        String fileName = uploadFile.getName();
        writer.append("--" + BOUNDARY).append(LINEFEED);
        writer.append("Content-Disposition:form-data;name=\""+ fieldName +"\";filename=\"" + fileName + "\"").append(LINEFEED);
        writer.append(LINEFEED);
        writer.flush();

        FileInputStream inputStream = new FileInputStream(uploadFile);
        byte[] buffer = new byte[(int)uploadFile.length()];
        int bytesRead = -1;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.flush();
        inputStream.close();

        writer.append(LINEFEED);
        writer.flush();
    }

※ boundary는 파라미터와 파일 데이터가 어디서부터 어디까지인지를 알려주는 값으로 임의 값을 설정하면 됩니다. 

※ Linefeed는 고정값으로 "\r\n"을 설정해 주어야 합니다. 

 

 

- 메인

public class Net_03_HttpRequestMultipartForm {

	static HttpUtil hu = HttpUtil.getInstance();

	public static void main(String[] args) {
		
		try {

			uploadOneFile(new File(args[0]));
			Thread.sleep(1000); // Stream이 완전 종료되기까지 대기
			
			File [] files = new File[args.length];
			for (int i=0; i<args.length; i++) {
				files[i] = new File(args[i]);
			}
			
			uploadManyFile(files);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	public static void uploadOneFile(File file) throws Exception {
		System.out.println("POST Request Body file = "+file.getName());	
		String protocol = "http";
		String targetUrl = "http://localhost:8080/api/items/127/upload-file";
		System.out.println("URL : "+targetUrl);
		Map<String, String> settings = new HashMap<String, String>();
		
		settings.put("Method", "POST");
		settings.put("HOST", "localhost:8080");
		settings.put("User-Agent", "Java-Client");
		settings.put("Connection", "Keep-Alive");
		settings.put("Cache-Control", "no-cache");
		
		hu.setResponseBody(new ResponseBodyString());
		hu.request(protocol, targetUrl, settings, new HashMap(), file);
		
		System.out.println("Post Request - Response Result ");
		System.out.println(hu.getResponseBody().getResult());
		
	}
	
	
	public static void uploadManyFile(File [] files) throws Exception {
		System.out.println("POST Request Body files = "+files[0].getName());
		
		String protocol = "http";
		String targetUrl = "http://localhost:8080/api/items/127/upload-files";
		System.out.println("URL : "+targetUrl);
		Map<String, String> settings = new HashMap<String, String>();
		
		settings.put("Method", "POST");
		settings.put("HOST", "localhost:8080");
		settings.put("User-Agent", "Java-Client");
		settings.put("Connection", "Keep-Alive");
		settings.put("Cache-Control", "no-cache");
		
		hu.setResponseBody(new ResponseBodyString());
		hu.request(protocol, targetUrl, settings, new HashMap(), files);
		
		System.out.println("Post Request - Response Result ");
		System.out.println(hu.getResponseBody().getResult());
		
	}
	
}

uploadOneFile메서드는 한개의 파일을 API에 업로드하는 코드입니다. 

uploadManyFile메서드는 동시에 여러 개의 파일을 API에 업로드하는 코드입니다.

 

테스트에 사용한 API는 Spring boot로 구현했습니다. 아래 URL의 포스트를 참고하셔서 파일 업로드와 다운로드가 가능한 API를 준비해야 위의 코드를 실행하여 제대로 된 결과 값을 얻을 수 있습니다. 

 

※ 이전 포스트 URL

https://koiking.tistory.com/46

 

※ API 코드 

https://github.com/leeyoungseung/item-admin

3. 실행결과【Windows(이클립스) / Linux】

아래의 화면에 보이는 사진 파일 3개를 업로드 해보겠습니다. 

좌측이 API의 로그, 우측이 이 포스트의 예제코드 결과 로그
업로드 결과

4. 전체코드

https://github.com/leeyoungseung/template-java

반응형

댓글