Feb 5, 2014 - HTTP Client (서버 to 서버)

관련주소 : 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;
 }

Oct 22, 2013 - php 서버를 윈도우 서버에서 테스트하기

요즘 그누보드로 가볍게 서버를 하나 만들어서 가지고 놀고 있는데, 집에서 로컬서버 뛰우기 위한 php 서버를 인터넷을 검색해보면 [apmsetup] 이라는 프로그램만 검색이 된다.

예전부터 사용하던 서버가 XAMPP 인데 정말 검색이 안된다. “php 서버” 로 검색하면 검색이 안된다.

XAMPP 주소 : http://www.apachefriends.org/en/xampp.html

XAMPP 의 장점은 설치할때, Apache, MySQL, FileZilla FTP Server, Mercury Mail Server, Tomcat 이 한번에 깔린다. 난 php 개발자가 아니므로, 추가적으로 설정없이 또한 PHP 와 동시에 Perl 이 깔리며, phpMyAdmin 까지 저절로 깔리기 때문에 따로 쿼리를 날리기 위해 TOAD 같은 쿼리툴 프로그램을 깔필요가 없어 편하게 사용하고 있다.

다만 32bit 용밖에 없고, 영문이라는 것만 빼면 정말 좋은 프로그램이다.

XAMPP 다운로드 주소 : http://sourceforge.net/projects/xampp/files/XAMPP%20Windows/1.8.2/xampp-win32-1.8.2-2-VC9-installer.exe/download?use_mirror=jaist&download=

여담으로 별도의 재미를 위해 이미 asp 로 80port 를 사용하고 있었기 때문에 81port 로 바꿔서 쓰고 싶었는데 이런 부분에서 사용하기가 편한 인터페이스라 XAMPP 를 잘쓰고 있다.

Oct 22, 2013 - 이클립스 Code Template 관련

Window > Preferences > Java > Code Style > Code Template 에서 원하는 주소 타입을 정의한 후 우측 하단의 Apply 을 클릭합니다.

원하시는 주석을 달 위치(클래스명, 메소드명)에 마우스를 클릭하신후 단축키 alt+shift+J(알트+쉬프트+제이)를 누르시면 주석이 생성됩니다.

클래스에 넣을 주석 형식을 Types 에 간단하게 정의해서 넣어주시면됩니다.

/**
 * <pre>
 * File : ${file_name}
 * </pre>
 * @history : 
 * ------------------------------------------------------------------
 * 변경일  작성자   변경내용
 * ------------------------------------------------------------------
 * ${date} ${user}  최초작성
 * 
 * ------------------------------------------------------------------
 */ 

또한 임의로 정의된 변수명을 원하는 변수명으로 넣을 경우에는 eclipse.ini 파일을 수정하시면됩니다.

예를 들어 ${user}의 값을 변경하고 싶을 경우 eclipse.ini 파일에 -Duser.name=(원하는계정명) 을 입력하시면 됩니다.