관련주소 : http://javacan.tistory.com/60 를 보고 따라한 관련주소 : http://hyunisjolly.blogspot.kr/2012/04/http-client.html 를 따라함.

회사에서 사용한다고 해서 만들었는데, 안쓰게 되서 우선 블로그에 킵해둡니다. 서버에서 받아서 다른 서버로 파일을 보내는, 서버to서버 파일 전송 Class 입니다. 기존 소스에서 MultipartFile 을 받아서 처리할 수 있도록 작업하였습니다.

/**
 *
 * HTTP 요청을 전송한 후, 응답을 받아오는 유틸리티 클래스
 *
 * GET 방식과 POST 방식으로 데이터를 전송해주며
 * POST 방식의 경우 multipart/form-date 인코딩 방식도 지원해준다.
 * </pre>
 * @history :
 * ------------------------------------------------------------------
 * 변경일  작성자   변경내용
 * ------------------------------------------------------------------
 * 2013. 11. 25. 젊은광대 최초작성
 *
 * ------------------------------------------------------------------
 */

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.BufferedReader;

import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
//import java.net.URLConnection;
import java.net.URLEncoder;

import java.util.ArrayList;

import org.springframework.web.multipart.MultipartFile;


public class HttpRequest {

    public static final String CRLF = "\r\n";

    protected URL targetURL; // 연결할 URL
    protected String encoding = "UTF-8";   // String encoding

    /** HTTP HEADER **/
    private ArrayList<Object> requestHeader;
//    private ArrayList<Object> responseHeader;

    /**
     * 파라미터 목록을 저장하고 있다.
     * 파라미터 이름과 값이 차례대로 저장된다.
     */
    private ArrayList<Object> params;    
    private int responseCode;  // 응답코드
    private String responseMessage; // 응답메시지


    public HttpRequest(){
     reset();
    }

    /**
     * CONSTRUCTOR
     */
    public HttpRequest(URL target){
     reset();
     this.targetURL  = target;
    }

    public void setTargetUrl(String targetURL) {
     try {
   this.targetURL = new URL(targetURL);
  } catch (MalformedURLException e) {
   e.printStackTrace();
  }
    }

    /**
     * CONSTRUCTOR
     *
     * @param target HTTP 메시지를 전송할 대상 URL
     */
    public HttpRequest(URL target, String encoding) {
     reset();
     this.targetURL  = target;
     if ( encoding != null && encoding.equals("") == false ) { this.encoding  = encoding; }

    }

    /**
     * CONSTRUCTOR
     *
     * @param target HTTP 메시지를 전송할 대상 URL
     */
    public HttpRequest(URL target, String encoding, int initialCapicity) {
     reset();
     this.targetURL  = target;
     if ( encoding != null && encoding.equals("") == false ) { this.encoding  = encoding; }
    }

    public void reset()
    {
     this.targetURL    = null;
     this.requestHeader   = new ArrayList<Object>();
     // this.responseHeader  = new ArrayList<Object>();
     this.params    = new ArrayList<Object>();
     this.responseCode  = -1;
     this.responseMessage = "";
    }

    /**
     * INITIALIZE
     * @param target
     */
    public void init(URL target) {
     reset();
     this.targetURL  = target;
    }

    /**
     * INITIALIZE
     * @param target
     * @param encoding
     */
    public void init(URL target, String encoding) {
     reset();
     this.targetURL  = target;
     if ( encoding != null && encoding.equals("") == false ) { this.encoding  = encoding; }
    }

    /*****************************************************/

    public void addHeader(String parameterName, String parameterValue)
    {
        if (parameterValue == null)
            throw new IllegalArgumentException("Parameter Value can't be null(parameterName:"+parameterName+")!");

        requestHeader.add(parameterName);
        requestHeader.add(parameterValue);     
    }

    /**
     * 파라미터를 추가한다.
     * @param parameterName 파라미터 이름
     * @param parameterValue 파라미터 값
     * @exception IllegalArgumentException parameterValue가 null일 경우
     */
    public void addParameter(String parameterName, Object parameterValue) {
        if (parameterValue == null)
        throw new IllegalArgumentException("Parameter Value can't be null(parameterName:"+parameterName+")!");

        params.add(parameterName);
        params.add(parameterValue);
    }

    /**
     * 파일 파라미터를 추가한다.
     * 만약 parameterValue가 null이면(즉, 전송할 파일을 지정하지 않는다면
     * 서버에 전송되는 filename 은 "" 이 된다.
     *
     * @param parameterName 파라미터 이름
     * @param parameterValue 전송할 파일
     * @exception IllegalArgumentException parameterValue가 null일 경우
     */
    public void addFile(String parameterName, File parameterValue) {
        // paramterValue가 null일 경우 NullFile을 삽입한다.
        if (parameterValue == null) {
         params.add(parameterName);
         params.add(new NullFile());
        } else {
         params.add(parameterName);
         params.add(parameterValue);
        }
    }

    /**
     * 파일 파라미터를 추가한다.
     * 만약 parameterValue가 null이면(즉, 전송할 파일을 지정하지 않는다면
     * 서버에 전송되는 filename 은 "" 이 된다.
     *
     * @param parameterName 파라미터 이름
     * @param parameterValue 전송할 파일
     * @exception IllegalArgumentException parameterValue가 null일 경우
     */
    public void addMultiFile(String parameterName, MultipartFile parameterValue) {
        // paramterValue가 null일 경우 NullFile을 삽입한다.
        if (parameterValue == null) {
         params.add(parameterName);
         params.add(new NullFile());
        } else {
         params.add(parameterName);
         params.add(parameterValue);
        }
    }

    /**
     * 지금까지 지정한 파라미터를 모두 삭제한다.
     */
    public void clearParameters() {
     params.clear();
    }

    /*****************************************************/

    /**
     * GET 방식으로 대상 URL에 파라미터를 전송한 후
     * 응답을 InputStream으로 리턴한다.
     * @return InputStream
     */
    public InputStream sendGet() throws Exception {

        String paramString = null;
        if (params.size() > 0)
            paramString = "?" + encodeString(params);
        else
            paramString = "";

        URL url = new URL(targetURL.toExternalForm() + paramString);

        HttpURLConnection conn = (HttpURLConnection)url.openConnection();     
        conn.setRequestMethod("GET");

        // conn.setDoInput(true);
        conn.setDoOutput(true);
        // conn.setUseCaches(true);

        if (requestHeader != null && requestHeader.size() > 0) {
         for(int i=0, j=requestHeader.size(); i<j; i++) {
          String name = (String)requestHeader.get(i);
          i++;
          String value = (String)requestHeader.get(i);
          conn.setRequestProperty(name, value);
         }
        }
        conn.connect();

        this.responseCode   = conn.getResponseCode();
        this.responseMessage  = conn.getResponseMessage();

        for (int i=0; ; i++) {
            String headerName  = conn.getHeaderFieldKey(i);
            String headerValue  = conn.getHeaderField(i);

            if (headerName == null && headerValue == null) {
                // No more headers
                break;
            }
            if (headerName == null) {
                // The header value contains the server's HTTP version
             break;
            }
        }

        return conn.getInputStream();
    }

    /**
     * POST 방식으로 대상 URL에 파라미터를 전송한 후
     * 응답을 InputStream으로 리턴한다.
     * @return InputStream
     */
    public InputStream sendPost() throws Exception {
        String paramString = null;
        if (params.size() > 0)
            paramString = encodeString(params);
        else
            paramString = "";

        HttpURLConnection conn = (HttpURLConnection)targetURL.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

        if (requestHeader != null && requestHeader.size() > 0) {
         for(int i=0, j=requestHeader.size(); i<j; i++) {
          String name = (String)requestHeader.get(i);
          i++;
          String value = (String)requestHeader.get(i);
          conn.setRequestProperty(name, value);
         }
        }

        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);

        DataOutputStream out = null;

        try {
            out = new DataOutputStream(conn.getOutputStream());
            out.writeBytes(paramString);
            out.flush();
        } finally {
            if (out != null) out.close();
        }


        this.responseCode   = conn.getResponseCode();
        this.responseMessage  = conn.getResponseMessage();

        for (int i=0; ; i++) {
            String headerName  = conn.getHeaderFieldKey(i);
            String headerValue  = conn.getHeaderField(i);

            if (headerName == null && headerValue == null) {
                // No more headers
                break;
            }
            if (headerName == null) {
                // The header value contains the server's HTTP version
             break;
            }
        }

        //conn.getResponseCode();
        //conn.getResponseMessage();
        //conn.getErrorStream();

        return conn.getInputStream();
    }

    /**
     * multipart/form-data 인코딩을 사용하여
     * 대상 URL에 데이터를 전송한 후에
     * 응답을 InputStream으로 리턴한다.
     * @return InputStream
     */
    public InputStream sendMultipartPost() throws IOException {

        HttpURLConnection conn = (HttpURLConnection)targetURL.openConnection();

        // Delimeter 생성
        String delimeter = makeDelimeter();

        byte[] newLineBytes = CRLF.getBytes();
        byte[] delimeterBytes = delimeter.getBytes();
        byte[] dispositionBytes = "Content-Disposition: form-data; name=".getBytes();
        byte[] quotationBytes = "\"".getBytes();
        byte[] contentTypeBytes = "Content-Type: application/octet-stream".getBytes();
        byte[] fileNameBytes = "; filename=".getBytes();
        byte[] twoDashBytes = "--".getBytes();

        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "multipart/form-data; boundary="+delimeter);

        if (requestHeader != null && requestHeader.size() > 0) {
         for(int i=0, j=requestHeader.size(); i<j; i++) {
          String name = (String)requestHeader.get(i);
          i++;
          String value = (String)requestHeader.get(i);
          conn.setRequestProperty(name, value);
         }
        }

        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);

        BufferedOutputStream out = null;
        try {
            out = new BufferedOutputStream(conn.getOutputStream());

            Object[] obj = new Object[params.size()];
            params.toArray(obj);

            for (int i = 0 ; i < obj.length ; i += 2) {
                // Delimeter 전송
                out.write(twoDashBytes);
                out.write(delimeterBytes);
                out.write(newLineBytes);
                // 파라미터 이름 출력
                out.write(dispositionBytes);
                out.write(quotationBytes);
                out.write( ((String)obj[i]).getBytes() );
                out.write(quotationBytes);
                if ( obj[i+1] instanceof String) {
                    // String 이라면
                    out.write(newLineBytes);
                    out.write(newLineBytes);
                    // 값 출력
                    out.write( ((String)obj[i+1]).getBytes() );
                    out.write(newLineBytes);
                } else {
                    // 파라미터의 값이 File 이나 NullFile인 경우
                    if ( obj[i+1] instanceof File) {
                        File file = (File)obj[i+1];
                        // File이 존재하는 지 검사한다.
                        out.write(fileNameBytes);
                        out.write(quotationBytes);
                        out.write(file.getAbsolutePath().getBytes() );
                        out.write(quotationBytes);
                    } else if ( obj[i+1] instanceof MultipartFile) {
                     MultipartFile file = (MultipartFile)obj[i+1];
                        // File이 존재하는 지 검사한다.
                        out.write(fileNameBytes);
                        out.write(quotationBytes);
                        out.write(file.getOriginalFilename().getBytes() );
                        out.write(quotationBytes);
                    } else {
                        // NullFile 인 경우
                        out.write(fileNameBytes);
                        out.write(quotationBytes);
                        out.write(quotationBytes);
                    }
                    out.write(newLineBytes);
                    out.write(contentTypeBytes);
                    out.write(newLineBytes);
                    out.write(newLineBytes);
                    // File 데이터를 전송한다.
                    if (obj[i+1] instanceof File) {
                        File file = (File)obj[i+1];
                        // file에 있는 내용을 전송한다.
                        BufferedInputStream is = null;
                        try {
                            is = new BufferedInputStream(new FileInputStream(file));
                            byte[] fileBuffer = new byte[1024 * 8]; // 8k
                            int len = -1;
                            while ( (len = is.read(fileBuffer)) != -1) {
                                out.write(fileBuffer, 0, len);
                            }
                        } finally {
                            if (is != null) try { is.close(); } catch(IOException ex) {}
                        }
                    } else if ( obj[i+1] instanceof MultipartFile) {
                     MultipartFile file = (MultipartFile)obj[i+1];
                        // MultipartFile 있는 내용을 전송한다.
                        BufferedInputStream is = null;
                        try {
                            is = new BufferedInputStream(file.getInputStream());
                            byte[] fileBuffer = new byte[1024 * 8]; // 8k
                            int len = -1;
                            while ( (len = is.read(fileBuffer)) != -1) {
                                out.write(fileBuffer, 0, len);
                            }
                        } finally {
                            if (is != null) try { is.close(); } catch(IOException ex) {}
                        }
                    }
                    out.write(newLineBytes);
                } // 파일 데이터의 전송 블럭 끝
                if ( i + 2 == obj.length ) {
                    // 마지막 Delimeter 전송
                    out.write(twoDashBytes);
                    out.write(delimeterBytes);
                    out.write(twoDashBytes);
                    out.write(newLineBytes);
                }
            } // for 루프의 끝

            out.flush();
        } finally {
            if (out != null) out.close();
        }

        this.responseCode   = conn.getResponseCode();
        this.responseMessage  = conn.getResponseMessage();

        for (int i=0; ; i++) {
            String headerName  = conn.getHeaderFieldKey(i);
            String headerValue  = conn.getHeaderField(i);

            if (headerName == null && headerValue == null) {
                // No more headers
                break;
            }
            if (headerName == null) {
                // The header value contains the server's HTTP version
             break;
            }
        }

        return conn.getInputStream();
    }

    /**
     * 응답 코드를 얻는다.
     * @return
     */
    public int getResponseCode()
    {
     return this.responseCode;
    }
    /**
     * 응답 메시지를 얻는다.
     * @return
     */
    public String getResponseMessage()
    {
     return this.responseMessage;
    }


    /**
     * Response Stream을 읽어 String으로 리턴한다.
     * @param is
     * @return
     */
    public static String readResponseToString(InputStream is, String encoding)
    {  
     if ( encoding == null || encoding.equals("") ) {
      encoding = "UTF-8";
     }

     StringWriter  out  = null;
  BufferedReader  br   = null;
  String response = "";
  try {  

   br = new BufferedReader(new InputStreamReader(is, encoding));
   out = new StringWriter();

   String temp;
   while ((temp = br.readLine()) != null) {
    out.write(temp+CRLF);
   }
   br.close();
   response = out.toString().trim();
   out.close();
   is.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
     finally {
   try{
    if (out != null ) { out.close(); }
    if (br != null ) { br.close(); }
    if (is != null ) { is.close(); }
   } catch (Exception e){}
     }

  return response;
    }

    /**
     * 지정한 ArrayList에 저장되어 있는 파라미터&값 목록을
     * application/x-www-form-urlencoded MIME에 맞춰서 인코딩한다.
     * 파라미터의 값의 타입이 File일 경우에는 그 파라미터를 무시하고
     * 다음 파라미터를 처리한다.
     *
     * @param parameters 파라미터 이름과 파라미터 값을 저장하고 있는 객체
     * @return 인코딩된 String
     */
    protected static String encodeString(ArrayList<Object> parameters) throws Exception {
        StringBuffer sb = new StringBuffer(256);

        Object[] obj = new Object[parameters.size()];
        parameters.toArray(obj);

        for (int i = 0 ; i < obj.length ; i += 2) {
            if ( obj[i+1] instanceof File || obj[i+1] instanceof NullFile ) continue;

            sb.append(URLEncoder.encode(((String)obj[i]), "UTF-8"));
            sb.append('=');
            sb.append(URLEncoder.encode(((String)obj[i+1]), "UTF-8"));

            if (i + 2 < obj.length) sb.append('&');
        }

        return sb.toString();
    }

    /**
     * multipart/form-data 로 데이터를 전송할 때 사용되는
     * 딜리미터를 생성한다.
     * <p>
     * 임의로 생성하지 않고 매번 같은 딜리미터를 생성한다.
     */
    protected static String makeDelimeter()
    {
        return "---------------------------7d115d2a20060c";
    }

    /**
     * 전송할 파일을 지정하지 않은 경우에 사용되는 클래스
     */
    protected class NullFile {
        NullFile() {
        }
        public String toString() {
            return "";
        }
    }

}


사용방법은 다음과 같습니다.


 public static Map postForFile(String url, Map param, File file) {
  HttpRequest httpRequest = new HttpRequest();
  Iterator iterator = param.entrySet().iterator();
  while (iterator.hasNext()) {
   Entry entry = (Entry) iterator.next();
   httpRequest.addParameter((String)entry.getKey(), entry.getValue());
  }
  httpRequest.addFile(FILE_ID, file);

  InputStream is = null;
  BufferedReader br = null;
  Map<String, Object> result = new HashMap<String, Object>();
  StringBuffer json = new StringBuffer();

  try {
   is = httpRequest.sendMultipartPost();
   br = new BufferedReader(new InputStreamReader(is));
      String jsonString = "";

      while ((jsonString = br.readLine()) != null) {
       json.append(jsonString);
   }
  } catch (IOException e) {
   e.printStackTrace();
  }
//     JSONObject paramJson = (JSONObject) JSONSerializer.toJSON( json.toString() );
     JSONObject paramJson = (JSONObject) JSONObject.fromObject( json.toString() );

     String errorMessage = (String) paramJson.get(ERROR_MESSAGE);
     String errorCode = (String) paramJson.get(ERROR_CODE);


     if (!SUCCESS_CODE.equals(errorCode)) {
      logger.debug("ErrorCode :::::: " + errorCode);
      logger.debug("ErrorMessage :::::: " + errorMessage);

      result.put("errorMessage", errorMessage);
      result.put("errorCode", errorCode);
     }

  return result;
 }