본문 바로가기
공부/Trouble Shooting

Open API로 받아온 정보 JSON 파싱

by son_i 2023. 9. 4.
728x90

JSON 라이브러리를 추가하려고 프로젝트 우클릭 Configure - Convert To Maven Project 해서 pom.xml파일 생성

역시 한 번에 되면 재미없지 오류 발생

<build> 안에 넣어주란다. -> 넣어져있음

<plugin>으로 안 감싸져있어서 감싸줬더니 오류 또 발생

 

그래도 안 됐는데 <dependencies>안에 넣어주면 된다 !

코드는 여기서 가져왔다

https://mvnrepository.com/artifact/org.json/json/20230618

 

으잉.. 아니네 위에 오류가 있어서 안 떴나봐.. 안 된다

아니 <build> 안에 넣어주는게 아닌데 ???

 

pom.xml 파일 구조 참조한 블로그

https://velog.io/@coreminw/spring-Maven%EA%B3%BC-pom.xml

 

spring - Maven과 pom.xml

Maven과 pom.xml 정리

velog.io

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>Mission01-web</groupId>
  <artifactId>Mission01-web</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
    <dependencies>
      <!-- https://mvnrepository.com/artifact/org.json/json -->
		<dependency>
    			<groupId>org.json</groupId>
    			<artifactId>json</artifactId>
    			<version>20230618</version>
		</dependency>
   	</dependencies>	
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <release>17</release>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.3</version>
      </plugin>
    </plugins>
  </build>
</project>

됐다.

 

잘 생겼다. 생각해보니 SQLite도 dependency 추가해줘야겠다.

<dependencies>
      <!-- https://mvnrepository.com/artifact/org.json/json -->
		<dependency>
    			<groupId>org.json</groupId>
    			<artifactId>json</artifactId>
    			<version>20230618</version>
		</dependency>
		<dependency>
			<groupId>org.xerial</groupId>
			<artifactId>sqlite-jdbc</artifactId>
			<version>3.36.0.3</version>
		</dependency>
   	</dependencies>

 

JSONParser 쓰려고 라이브러리 또 추가

<!-- https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple -->
		<dependency>
    			<groupId>com.googlecode.json-simple</groupId>
    			<artifactId>json-simple</artifactId>
    			<version>1.1.1</version>
		</dependency>

<Open API에서 데이터 가져오기>

https://fbtmdwhd33.tistory.com/264

 

[Java] 공공데이터 포털 오픈 API 사용 방법.

✏️개요 오랜만에 작성하는 이번 글의 주제는 공공데이터 포털의 오픈 API 사용방법이다. 공공데이터 포털은 정부에서 운영하는 오픈 API 서비스로 정부의 공공기관들이 운영되는 과정에서 수

fbtmdwhd33.tistory.com

여기 참고했다. 

 

 

<JSON 파싱>

일단 API에서 받아온 결과코드를 보면

{"TbPublicWifiInfo":{"list_total_count":23343,"RESULT":{"CODE":"INFO-000","MESSAGE":"정상 처리되었습니다"},"row":[{"X_SWIFI_MGR_NO":"---EP000001","X_SWIFI_WRDOFC":"은평구","X_SWIFI_MAIN_NM":"갈현1동주민센터","X_SWIFI_ADRES1":"갈현동 갈현로 301","X_SWIFI_ADRES2":"갈현1동 1층","X_SWIFI_INSTL_FLOOR":"","X_SWIFI_INSTL_TY":"7-1. 공공 - 행정","X_SWIFI_INSTL_MBY":"의견(자치)","X_SWIFI_SVC_SE":"공공WiFi","X_SWIFI_CMCWR":"자가망_U무선망","X_SWIFI_CNSTC_YEAR":"2011","X_SWIFI_INOUT_DOOR":"실내","X_SWIFI_REMARS3":"","LAT":"126.9167","LNT":"37.62364","WORK_DTTM":"2023-09-02 10:58:34.0"},
{ ....}, {....} 이런식으로 코드의 연속이고 ]}}

내가 필요한 정보들은 "row" : [ ... , ...] 이렇게 row 키 값에 value가 배열형태로 존재.

 

그러면 나는 제일 큰 중괄호를 object 파싱을 해야하고 그 안에 중괄호 안에 list_total_cout, Result, row 객체들이 있으니까 object 파싱을 한 번 더 해야한다.


json 파싱한 데이터를 WifiList DTO 객체에 저장할 필요성을 느꼈다.

<WifiList.java>

테이블의 객체 다 만들어주고 getter/setter 추가

이때 작업일시 type Date로 해주고 import java.util.Date;

 

이제 1. DB드라이버로드 2. connection 객체 생성 3. prepared 객체 생성 4. 쿼리 실행  5. 객체 닫기

과정을 통해서 openAPI로 불러온 정보들을 DB에 저장한다.

다 작성은 했는데 이런 오류 발생

pom.xml에 dependency추가해줬고 여기에 sqlite 라이브러리 있고 음.. url이 맞는진 모르겠지만

이렇게 연결도 해줬음.

 

위 코드로 db파일 생성까지 해줘서 빈 .db 파일이 (처음이자 마지막으로) 생성.

음 그러면 이게 내가 datagrip에서 미리 쿼리문으로 만들어놓은 테이블이 있는 db가 아닌가보다 ?

그럼 DataGrip에서 만든 db파일은 어디있을까나

찾았다 

나같은 경우는 sqlite 설치파일 zip 을 dev_web폴더에 저장해놓았고

그 안에 있음.

이파일위치를 이클립스에서 연결해줘야 할 것 같다.

url을 이렇게 수정해줬더니 오류문구가 바뀌었다 !

manageno를 pk로 not null 옵션을 줬는데 없다는 오류

근데 manageno는 없을 수가 없는데 뭘까 파싱이 잘못 되었나 ?

 

이렇게 파싱해서 화면에 뽑아봤을 땐 잘 나왔음.. 음..

음... 근데 wifiList.getManageNo()를 출력했을 때는 null이 나온다 .값이 member객체에 세팅이 안 된다는 건데

알고보니 저기에 키 값하고 공백이 있어서 발생하는 거였음 !

공백 없애주고 실행시키니까 

데이터 저장 ~~ 근데 왜 하나 밖에 안 됐지 ? 맨 마지막 데이터만 들어갔음 지금.

아 하나 wifiList에 세팅 되면 곧바로 db에 저장저장저장 계속 해줘야함 반복문 안에서

 

그러면 코드를 좀 정리를 해서 반복되는 드라이버 연결 같은 부분은 밖으로 빼주고 sql쿼리 실행하는 부분만 메소드로 만들어서 계속 호출할 수 있게 해줘야겠다.

해줬고

 

이제 해야할 일 

: 모든 와이파이 데이터 저장먼저

총 데이터를 했더니만 이렇게 오류가 난다. API는 한 번에 최대 1000건만 가능하대

근데 이거를 야매로 그냥 숫자 바꿔서 해줘도 되겠지만

openAPI 와이파이 정보 가져오기 버튼을 눌렀을 때마다 ? API데이터가 싸악 저장이 되어야하는 거 같으니까

코드로 만들어보자. 근데 총 데이터 갯수를 어떻게 알지 ? 아 json 파싱한 거에 나와있따.

실시간 저장이 아니라고 한다. 그럼 누를 때마다 API데이터를 db에 저장하는 것이 아닌 이미 저장해 놓고 불러오는 방식을 의미하는 것 같다 !

 

아무튼 그래서 1000건씩 계속 데이터 시작행, 마지막 행 숫자 바꿔가면서 하고 있는데 저장은 재빨리 되는데 이클립스에서 렉이 너무 많이 걸린다. 1000번을 계속 드라이버 연결하고 해제해주고 하는 작업 때문인 듯.. . 코드 수정을 좀 다시 해야겠다.

 

 


날아가서 다시 ..

1. jdbc 드라이버 연결 & API 정보 가져오는 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class APITest {
	static {
		// 1. 드라이버 연결
				//2. connection 객체 생성
				//3. statement 객체 생성
				//4. 쿼리 실행
				//5. 결과 수행(insert경우)
				//6. 객체 연결 해제
		try {
			Class.forName("org.sqlite.JDBC");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		
		String url_value = "jdbc:sqlite:C:\\dev_web\\sqlite-tools-win32-x86-3430000wifi.db";
		
		try {
			connection = DriverManager.getConnection(url_value);
			
			
		} catch (SQLException e){
			e.printStackTrace();
		}
	}
	public static void main(String args[]) throws IOException {
		//1. url 만들기 위한 StringBuilder
		StringBuilder urlBuilder = new StringBuilder("http://openapi.seoul.go.kr:8088");
		
		//2. 오픈 API의 요청 규격에 맞는 파라미터 생성, 발급받은 인증키
		urlBuilder.append("/" + URLEncoder.encode("4b78435972736f6534356e73497157","UTF-8"));
		urlBuilder.append("/" + URLEncoder.encode("json","UTF-8"));
		urlBuilder.append("/" + URLEncoder.encode("TbPublicWifiInfo", "UTF-8"));
		urlBuilder.append("/" + URLEncoder.encode("1","UTF-8"));
		urlBuilder.append("/" + URLEncoder.encode("3","UTF-8"));

			//3. URL 객체 생성
			URL url = new URL(urlBuilder.toString()); 
			
			//4. 요청하고자 하는 url과 통신하기 위한 Connection 객체 생성
			HttpURLConnection conn = (HttpURLConnection)url.openConnection();
			
			//5. 통신을 위한 메소드 set
			conn.setRequestMethod("GET");
			//6. 통신을 위한 content-type set
			conn.setRequestProperty("Content-type", "application/json");
			//7. 통신 응답코드 확인
			System.out.println("Response Code : " + conn.getResponseCode());
			//8. 전달받은 데이터를 BufferedReader 객체로 저장.
			BufferedReader rd;
			if(conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
				rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			} else {
				rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
			}
			
			//9. 저장된 데이터 라인별로 읽어 StringBuilder 객체로 저장
			StringBuilder sb = new StringBuilder();
			String line;
			while((line = rd.readLine()) != null) {
				sb.append(line);
			}
			
			//10. 객체 해제
			rd.close();
			conn.disconnect();
			
			//11. 전달받은 데이터 확인
			System.out.println(sb.toString());
	}
}

1. 문자열 형태로 날아오는 결과 json을 파싱하기 위한 JSONParser 객체 생성

import org.json.simple.parser.JSONParser;
//json-simple 라이브러리 pom.xml에 dependency 해줘야 함.

JSONParser parser = new JSONParser();

 

2. 문자열을 JSON 형태로 JSONObject 객체에 저장.

import org.json.JSONObject;
import org.json.simple.parser.ParseException;

//2. 문자열을 JSON 형태로 JSONObject 객체에 저장.
			JSONObject obj = null;
			try {
				obj = (JSONObject)parser.parse(sb.toString());
				
			} catch (ParseException e) {
				e.printStackTrace();
			}

이렇게 하면 key : value 형태가 obj에 저장.

내가 필요한 정보는 

더보기

{"TbPublicWifiInfo":{"list_total_count":23343,"RESULT":{"CODE":"INFO-000","MESSAGE":"정상 처리되었습니다"},"row":[{"X_SWIFI_MGR_NO":"---EP000001","X_SWIFI_WRDOFC":"은평구","X_SWIFI_MAIN_NM":"갈현1동주민센터","X_SWIFI_ADRES1":"갈현동 갈현로 301","X_SWIFI_ADRES2":"갈현1동 1층","X_SWIFI_INSTL_FLOOR":"","X_SWIFI_INSTL_TY":"7-1. 공공 - 행정","X_SWIFI_INSTL_MBY":"의견(자치)","X_SWIFI_SVC_SE":"공공WiFi","X_SWIFI_CMCWR":"자가망_U무선망","X_SWIFI_CNSTC_YEAR":"2011","X_SWIFI_INOUT_DOOR":"실내","X_SWIFI_REMARS3":"","LAT":"126.9167","LNT":"37.62364","WORK_DTTM":"2023-09-02 10:58:34.0"} ] } }

이렇게 하나의 obj 안에 key가 TbPublicWifiInfo이고 그 안에 value 중에서도 또 키와 값으로 이루어진 row 값이 필요함.

row는 jsonArray 형태로 구성돼있음.

 

결론은 나는 object 파싱을 2번 해준다음 row키 값으로 jsonArray파싱을 해줘야 원하는 값들을 얻을 수 있다.

- jsonArray 사용 참고

https://codechacha.com/ko/java-parse-json/#object

 

Java - JSON을 파싱하는 가장 쉬운 방법

org.json 라이브러리를 사용하여 JSON을 파싱하는 방법을 소개합니다. JSON은 Object, Array, Key-Value 타입으로 이루어져 있으며 Value는 String, Int, Long, Boolean 등의 타입을 지원합니다.

codechacha.com

https://studyingazae.tistory.com/196

 

[JAVA] 다양한 형태의 JSON 파일 파싱하기 JSONParser, JSONObject, JSONArray (json.simple, GSON)

JSON 파일을 땡겨왔는데 이를 저장하기 위해선 JSON 데이터를 사용하기 위해 JSONObject와 JSONArray를 쓸 수 있습니다. json-simple을 통해 json 객체를 다루는 법을 알아보겠습니다. 본 글에는 없지만 jackson

studyingazae.tistory.com

 

APITest 풀코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

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 {
	public static void main(String args[]) throws IOException {

		// 1. 드라이버 연결
		// 2. connection 객체 생성
		// 3. statement 객체 생성
		// 4. 쿼리 실행
		// 5. 결과 수행(insert경우)
		// 6. 객체 연결 해제
		try {
			Class.forName("org.sqlite.JDBC");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		Connection connection = null;
		PreparedStatement preparedStatement = null;

		String url_value = "jdbc:sqlite:C:\\dev_web\\sqlite-tools-win32-x86-3430000\\wifi.db";

		try {
			connection = DriverManager.getConnection(url_value);

		} catch (SQLException e) {
			e.printStackTrace();
		}
		// 1. url 만들기 위한 StringBuilder
		StringBuilder urlBuilder = new StringBuilder("http://openapi.seoul.go.kr:8088");

		// 2. 오픈 API의 요청 규격에 맞는 파라미터 생성, 발급받은 인증키
		urlBuilder.append("/" + URLEncoder.encode("4b78435972736f6534356e73497157", "UTF-8"));
		urlBuilder.append("/" + URLEncoder.encode("json", "UTF-8"));
		urlBuilder.append("/" + URLEncoder.encode("TbPublicWifiInfo", "UTF-8"));
		urlBuilder.append("/" + URLEncoder.encode("1", "UTF-8"));
		urlBuilder.append("/" + URLEncoder.encode("3", "UTF-8"));

		// 3. URL 객체 생성
		URL url = new URL(urlBuilder.toString());

		// 4. 요청하고자 하는 url과 통신하기 위한 Connection 객체 생성
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();

		// 5. 통신을 위한 메소드 set
		conn.setRequestMethod("GET");
		// 6. 통신을 위한 content-type set
		conn.setRequestProperty("Content-type", "application/json");
		// 7. 통신 응답코드 확인
		System.out.println("Response Code : " + conn.getResponseCode());
		// 8. 전달받은 데이터를 BufferedReader 객체로 저장.
		BufferedReader rd;
		if (conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
			rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		} else {
			rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
		}

		// 9. 저장된 데이터 라인별로 읽어 StringBuilder 객체로 저장
		StringBuilder sb = new StringBuilder();
		String line;
		while ((line = rd.readLine()) != null) {
			sb.append(line);
		}

		// 10. 객체 해제
		rd.close();
		conn.disconnect();

		// 11. 전달받은 데이터 확인
		System.out.println(sb.toString());

		// JSON 파싱
		// 1. 문자열 형태의 JSOn 파싱하기 위한 JSONParser 객체 생성.
		JSONParser parser = new JSONParser();
		// 2. 문자열을 JSON 형태로 JSONObject 객체에 저장.
		JSONObject obj = null;
		try {
			obj = (JSONObject) parser.parse(sb.toString());

		} catch (ParseException e) {
			e.printStackTrace();
		}
		// 3. 한 번 더 Parsing
		JSONObject second = (JSONObject) obj.get("TbPublicWifiInfo");

		// 4. row 키 값으로 배열을 JSONArray에 가져옴
		JSONArray jArray =  (JSONArray)second.get("row");
		int affected = 0;
		for (int i = 0; i < jArray.size(); i++) {
			WifiList wifiList = new WifiList();

			JSONObject o = (JSONObject)jArray.get(i);
			wifiList.setManageNo((String) o.get("X_SWIFI_MGR_NO"));
			// wifiList.setDist((String)o.get(거리));
			wifiList.setGugun((String) o.get("X_SWIFI_WRDOFC"));
			wifiList.setWifiName((String) o.get("X_SWIFI_MAIN_NM"));
			wifiList.setAddress((String) o.get("X_SWIFI_ADRES1"));
			wifiList.setDetailAddress((String) o.get("X_SWIFI_ADRES2"));
			wifiList.setSetFloor((String) o.get("X_SWIFI_INSTL_FLOOR"));
			wifiList.setSetType((String) o.get("X_SWIFI_INSTL_TY"));
			wifiList.setSetOrgan((String) o.get("X_SWIFI_INSTL_MBY"));
			wifiList.setServiceDivision((String) o.get("X_SWIFI_SVC_SE"));
			wifiList.setNetworkKind((String) o.get("X_SWIFI_CMCWR"));
			wifiList.setSetYear(Integer.parseInt((String)o.get("X_SWIFI_CNSTC_YEAR")));
			wifiList.setInOutdoor((String) o.get("X_SWIFI_INOUT_DOOR"));
			wifiList.setWificonnectEnvirionment((String) o.get("X_SWIFI_REMARS3"));
			wifiList.setX(Double.parseDouble((String)o.get("LAT")));
			wifiList.setY(Double.parseDouble((String)o.get("LNT")));
//			wifiList.setWorkDate((java.sql.Date)o.getDate("WORK_DTTM"));
			
			String sql = "insert into wifi_list (manage_no, dist, gugun, wifi_name, address, detail_address, set_floor, set_type, set_organ, service_division, network_kind, "
					+ "set_year, in_outdoor, wificonnect_environment, x, y, work_date)"
					+ " values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

			try {
				preparedStatement = connection.prepareStatement(sql);
				preparedStatement.setString(1, wifiList.getManageNo());
				preparedStatement.setDouble(2, wifiList.getDist());
				preparedStatement.setString(3, wifiList.getGugun());
				preparedStatement.setString(4, wifiList.getWifiName());
				preparedStatement.setString(5, wifiList.getAddress());
				preparedStatement.setString(6, wifiList.getDetailAddress());
				preparedStatement.setString(7, wifiList.getSetFloor());
				preparedStatement.setString(8, wifiList.getSetType());
				preparedStatement.setString(9, wifiList.getSetOrgan());
				preparedStatement.setString(10, wifiList.getServiceDivision());
				preparedStatement.setString(11, wifiList.getNetworkKind());
				preparedStatement.setInt(12, wifiList.getSetYear());
				preparedStatement.setString(13, wifiList.getInOutdoor());
				preparedStatement.setString(14, wifiList.getWificonnectEnvirionment());
				preparedStatement.setDouble(15, wifiList.getX());
				preparedStatement.setDouble(16, wifiList.getY());
				preparedStatement.setDate(17, (Date) wifiList.getWorkDate());

				affected += preparedStatement.executeUpdate();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println(affected+"개 저장 완료");
		 try {
             if(preparedStatement != null && !preparedStatement.isClosed()) {
                 preparedStatement.close();
             }
         } catch (SQLException e) {
             e.printStackTrace();
         }
         try {
             if(connection != null && !connection.isClosed()) {
                 connection.close();
             }
         } catch (SQLException e) {
             e.printStackTrace();
         }
	}
}

여기서 Date 저장을 아직 못 하고 있다.

 

그냥 String으로 받음 !

 

한 번에 API 요청 1000건 밖에 안 돼서 나눠서 저장을 했다.

여기서 중요한 건 manageNo를 PK처리 해줘야 데이터 중복 저장이 안 됨 !

 

혹시나 나중에 json 다른 형태로 받고 싶을 때 참조

https://jhyonhyon.tistory.com/11

 

[Java] JSON 파싱하기 (jackson/gson/json-simple)

JSON 파싱시 자주 쓰이는 라이브러리 3개로 JSON을 파싱하는 예제를 소개합니다. 라이브러리 Gson (https://mvnrepository.com/artifact/com.google.code.gson/gson) Jackson (https://mvnrepository.com/artifact/com.fasterxml.jackson.co

jhyonhyon.tistory.com

 

728x90