본문 바로가기

Dot Programming/Java

[Java] API 호출 및 JSON Parsing 하기 (JSONObject, JSONArray, JSONParser)

    자바에서 API 호출하기

    1. URL 생성자로 URL 객채 만들기

    java.net.URL은 자바에서 url을 다루는 클래스이다.

     

    URL 클래스의 주요 생성자는 다음과 같다.

    • URL(String spec) : 문자열 spec이 지정하는 자원에 대한 URL 객체 생성
    • URL(String protocol, String host, int port, String file) : 프로토콜 식별자 protocol, 호스트 주소 host, 포트 번호 port, 파일 이름 file이 지정하는 자원에 대한 URL 객체 생성
    URL url = new URL("https://yts.mx/api/v2/list_movies.json");

     

    2. HTTP Connection 구하기  - URLConnection openConnection()

    java.net.HttpURLConnection은 URLConnection을 구현한 추상 클래스이다. URLConnection은 웹을 통해 데이터를 주고 받는데 사용된다.

     

    openConnection() 메서드는 URL을 참조하는 객체를 URLConnection 객체로 반환한다.

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

     

    3. Request 방식 설정하기 -  void setRequestMethod(String method)

    기본 설정은 GET 요청이다. GET/ POST/ HEAD/ OPTIONS/ PUT/ DELETE/ TRACE 중 한 개를 골라서 요청이 가능하다.

     conn.setRequestMethod("GET");

     

    4. Request 속성 값 설정하기 - void setRequestProperty(String key, String value)

    JSON형식의 데이터를 받으려면 Content-type의 값을 "application/json"으로 설정해야 한다. 또한 X-Auth-Token이나 Authorization값 설정이 필요하다면 해당 메서드를 사용하여 값을 설정해주면 된다.

    con.setRequestProperty("X-Auth-Token", AUTH_TOKEN);
    con.setRequestProperty("Content-type", "application/json");

     

    5. 출력 가능 상태로 설정하기 - void setDoOutput(boolean dooutput)

    받아온 Json 데이터를 출력 가능한 상태(True)로 변경해줘야 한다. 기본값은 false이다.

    con.setDoOutput(true);

     

    6. 입력 스트림으로 데이터 읽기 

    인코딩방식은 InputStreamReader 생성자 두번째 인자값(charsetName)에 "UTF-8"로 설정해주면 된다.

    try{
    	StringBuffer sb = new StringBuffer();
    	BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
    	while(br.ready()) {
    		sb.append(br.readLine());
    	}
    }catch(Exception e) {
    	e.printStackTrace();
    }

     

    이대로 값을 출력하면 다음과 같이 출력된다. 이렇게 하면 데이터를 구분하기도 어렵고 어떻게 뽑아써야할지도 복잡하다. 그래서 이 데이터를 Java에서는 JSON 파싱하는 org.json이나 Gson 라이브러리를 사용하여 데이터를 가독성이 좋게 가공하여 사용해야 한다.

     

    입력 스트림으로 읽은 JSON 데이터 출력

     

    POST 요청 Parameter 전송하기

    // JSON 데이터 
    JSONObject jsonData = new JSONObject();
    jsonData.put("problem", problem);
    
    // 파라미터 데이터 출력 스트림에 입력
    OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream(), "UTF-8");
    osw.write(parameters.toString());	
    osw.flush();
    osw.close();

     

    자바에서 JSON Parsing하기

    1. JSON 라이브러리 설치하기

    [Eclipse/ IntelliJ] Java 프로젝트에 JSON 러이브러리(org.json) 설치하기

    → Java에서 JSON Parsing을 하기 위해서느 외부 라이브러리를 등록해줘야 한다.

     

    2. Object 데이터가 있는 JSON 파싱하기

    Object 데이터는 "{", "}"(curly brace)로 감싸져 있는 데이터를 나타낸다. 

    import org.json.simple.JSONObject;
    import org.json.simple.parser.JSONParser;
    import org.json.simple.parser.ParseException;
    
    public class ApiTest2 {
    	public static void main(String[] args) throws ParseException {
    		// JSONParser로 JSONObject 객체
    		JSONObject objData = (JSONObject)new JSONParser().parse(jsonData);
    
    		// 첫 번째 JSONObject
    		JSONObject movieData1 = (JSONObject)objData.get("movie1");
    		// 두 번째 JSONObject
    		JSONObject movieData2 = (JSONObject)objData.get("movie2");
    
    		// 데이터 출력하기
    		StringBuilder sb = new StringBuilder();
    		sb.append("movie1----\n");
    		sb.append("title: " + movieData1.get("title")+"\n");
    		sb.append("url: " + movieData1.get("url")+"\n");
    		sb.append("movie2----\n");
    		sb.append("title: " + movieData2.get("title")+"\n");
    		sb.append("url: " + movieData2.get("url")+"\n");
    
    		System.out.println(sb.toString());
    	}
        
    	// jsonData
    	static String jsonData=
                "{"
                    +       "\"movie1\": {"
                    +           "\"title\": \"Blame\","
                    +           "\"url\": \"https://yts.mx/movies/blame-2021\","
                    +       "},"
                    +       "\"movie2\": {"
                    +           "\"title\": \"Tethered\","
                    +           "\"url\": \"https://yts.mx/movies/tethered-2021\","
                    +       "},"
                    + "}";
    }

    출력 결과

    데이터 출력 결과

     

     

    3. Array 데이터가 있는 JSON 파싱하기

    JSON 데이터안에 있는 "[", "]"로 감싸진 배열 데이터를 파싱하기 위해서는 JSONArray가 추가적으로 필요하다.

    import org.json.simple.JSONArray;
    import org.json.simple.JSONObject;
    import org.json.simple.parser.JSONParser;
    import org.json.simple.parser.ParseException;
    
    public class ApiTest2 {
    	public static void main(String[] args) throws ParseException {
    		// JSONParser에 JSON데이터를 넣어 파싱한 다음 JSONObject로 반환한다.
    		JSONObject objData = (JSONObject)new JSONParser().parse(jsonData);
    		// JSONObject에서 Array데이터를 get하여 JSONArray에 저장한다.
    		JSONArray arrData = (JSONArray)objData.get("movies");
    
    		// 배열 데이터 출력하기
    		JSONObject tmp;
    		JSONArray tmpArr;
    		StringBuilder sb= new StringBuilder();
    		for(int i=0; i<arrData.size(); i++){
    			tmp = (JSONObject)arrData.get(i);
    
    			sb.append("title("+i+"): " + tmp.get("title")+"\n");
    			sb.append("url("+i+"): " + tmp.get("url")+"\n");
    
    			// Array데이터 안에 Array 데이터 꺼내기 
    			tmpArr = (JSONArray)tmp.get("genres");
    			sb.append("genres("+i+"): ");
    			for(int j=0; j<tmpArr.size(); j++){
    				sb.append(j+"." + tmpArr.get(j));
    				if(j!=tmpArr.size()-1) sb.append(", ");
    			}
    			sb.append("\n");
    		}
    		System.out.println(sb.toString());
    
    	}
        
    	// jsonData
    	static String jsonData=
                   "{"
                           +   "\"movies\": ["
                           +       "{"
                           +           "\"title\": \"Blame\","
                           +           "\"url\": \"https://yts.mx/movies/blame-2021\","
                           +           "\"genres\": ["
                           +                        "\"Crime\",\"Thriller\""
                           +            "]"
                           +       "},"
                           +       "{"
                           +           "\"title\": \"Tethered\","
                           +           "\"url\": \"https://yts.mx/movies/tethered-2021\","
                           +           "\"genres\": ["
                           +                        "\"Drama\",\"Mystery\",\"Sci-Fi\""
                           +            "]"
                           +       "},"
                           +       "{"
                           +           "\"title\": \"The Resonator: Miskatonic U\","
                           +           "\"url\": \"https://yts.mx/movies/the-resonator-miskatonic-u-2021\","
                           +           "\"genres\": ["
                           +                        "\"Fantasy\""
                           +            "]"
                           +       "}"
                           +   "]"
                           +"}";
    }

    출력 결과

    데이터 출력 결과

     

    자바에서 API 호출하여 JSON 데이터 파싱하기

    위에서 다룬 URL, URLConnection, HttpURLConnection 클래스들의 메서드와 JSON 파싱 예제를 활용하여 REST API로 받아오는 JSON 데이터를 파싱할 수 있다.

     

    OPEN API에서 제공하는 JSON 데이터 URL 예시

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    import org.json.simple.JSONArray;
    import org.json.simple.JSONObject;
    import org.json.simple.parser.JSONParser;
    import org.json.simple.parser.ParseException;
    
    public class ApiTest {
    	static final String BASE_URL = "https://yts.mx/api/v2/list_movies.json";
    	static final String AUTH_TOKEN = "AUTH_TOKEN 값";
    	static String AUTH_KEY = "Bearer " + "AUTH_KEY 값";
    	public static void main(String[] args) throws ParseException {
    
    		/**
    		 *  REST API 호출하기
    		 */
    		URL url = null;
    		HttpURLConnection con= null;
    		JSONObject result = null;
    		StringBuilder sb = new StringBuilder();
    		try {
    			// URL 객채 생성 (BASE_URL)
    			url = new URL(BASE_URL);
    			// URL을 참조하는 객체를 URLConnection 객체로 변환
    			con = (HttpURLConnection) url.openConnection();
    
    			// 커넥션 request 방식 "GET"으로 설정
    			con.setRequestMethod("GET");
    
    			// 커넥션 request 값 설정(key,value) 
    			con.setRequestProperty("Content-type", "application/json");
    			// void setRequestProperty (key,value) 다른 예시
    			// con.setRequestProperty("Authorization", AUTH_KEY);
    			// con.setRequestProperty("X-Auth-Token", AUTH_TOKEN);
    
    			// 받아온 JSON 데이터 출력 가능 상태로 변경 (default : false)
    			con.setDoOutput(true);
    
    			// 데이터 입력 스트림에 담기
    			BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
    			while(br.ready()) {
    				sb.append(br.readLine());
    			}
    			con.disconnect();
    		}catch(Exception e) {
    			e.printStackTrace();
    		}
    
    		/**
    		 *  JSON 데이터 파싱하기
    		 */
    		// JSONParser에 입력 스트림에 담은 JSON데이터(sb.toString())를 넣어 파싱한 다음 JSONObject로 반환한다.
    		result = (JSONObject) new JSONParser().parse(sb.toString());
    
    		// REST API 호출 상태 출력하기
    		StringBuilder out = new StringBuilder();
    		out.append(result.get("status") +" : " + result.get("status_message") +"\n");
    
    		// JSON데이터에서 "data"라는 JSONObject를 가져온다.
    		JSONObject data = (JSONObject) result.get("data");
    		// JSONObject에서 Array데이터를 get하여 JSONArray에 저장한다.
    		JSONArray array = (JSONArray) data.get("movies");
    
    		// 데이터 출력하기 (뮤비 제목, 장르)
    		JSONObject tmp;
    		out.append("데이터 출력하기 \n");
    		for(int i=0; i<array.size(); i++) {
    			tmp = (JSONObject) array.get(i);
    			out.append("title("+i+") :"+ tmp.get("title") +"\n");
    
    			// movies[] 배열 안에 있는 genres[] 데이터 꺼내기
    			JSONArray array2 = (JSONArray) tmp.get("genres");
    			out.append("genres("+i+"): ");
    			for(int j=0; j<array2.size(); j++) {
    				out.append(array2.get(j));
    				if(j!=array2.size()-1) {
    					out.append(",");
    				}
    			}
    			out.append("\n");
    			out.append("\n");
    		}
    		System.out.println(out.toString());
    	}
    }

     

    출력 결과

    ok : Query was successful
    데이터 출력하기 
    title(0) :Blame
    genres(0): Crime,Thriller
    
    title(1) :Tethered
    genres(1): Drama,Mystery,Sci-Fi
    
    title(2) :The Resonator: Miskatonic U
    genres(2): Fantasy
    
    title(3) :Verbindung
    genres(3): Drama
    
    title(4) :Bloodbath at the House of Death
    genres(4): Comedy,Horror
    
    title(5) :The Alpines
    genres(5): Mystery,Thriller
    
    title(6) :This Is the Night
    genres(6): Drama
    
    title(7) :Shock Troops
    genres(7): Action,Drama,History
    
    title(8) :Moments Without Proper Names
    genres(8): Action
    
    title(9) :Potato Salad
    genres(9): Comedy,Horror
    
    title(10) :The Big Steal
    genres(10): Comedy
    
    title(11) :The Division
    genres(11): Action,Crime,Thriller
    
    title(12) :Second Origin
    genres(12): Adventure,Horror,Sci-Fi
    
    title(13) :Elisa's Day
    genres(13): Crime,Drama
    
    title(14) :15 Years and One Day
    genres(14): Drama
    
    title(15) :Most Dangerous Game
    genres(15): Action,Thriller
    
    title(16) :Night of the Animated Dead
    genres(16): Animation,Horror
    
    title(17) :Devil's Five
    genres(17): Horror
    
    title(18) :The Secret Lives of Dorks
    genres(18): Comedy
    
    title(19) :When I Get Home, My Wife Always Pretends to Be Dead.
    genres(19): Comedy,Drama