[Java] 공공 데이터를 활용한 날씨 프로그램 만들기 3 - Java를 활용해 DB 조회하기

류재성's avatar
Jun 10, 2024
[Java] 공공 데이터를 활용한 날씨 프로그램 만들기 3 - Java를 활용해 DB 조회하기
 

1. Scanner 로 값 입력받기

💡
날씨 조회 프로그램 로직 1. 조회를 원하는 구를 입력한다. 2. 입력한 구 데이터로 DB에서 조회해 동 리스트를 출력한다. 3. 출력된 동 리스트 중 하나의 동을 입력한다. 4. 입력받은 구와 동 데이터로 DB에서 위도 경도를 구한다. 5. 위도 경도를 공공데이터 API에 포함시켜 날씨 데이터를 받는다. 6. 입력 받은 JSON 데이터를 자바 오브젝트(DTO) 로 받는다. 7. DTO 에서 날씨데이터를 꺼내 출력한다.
 
package org.example; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("원하는 구를 입력하세요"); System.out.println("ex) [종로구, 강남구,광악구]"); String gu = sc.nextLine(); System.out.println("원하는 동을 입력하세요"); } }
 
notion image
 
스캐너로 값을 받게 되었다. 이제 입력받은 값을 DB에서 조회해서 출력해보자.
 

2. 동 데이터 DB 조회

 

2.1 의존성 추가

 
build.gradle
notion image
implementation group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.13' implementation 'mysql:mysql-connector-java:8.0.33' implementation group: 'com.google.code.gson', name: 'gson', version: '2.7'
 
build.gradle 에 라이브러리를 추가한다.
 
💡
httpclient : HTTP 요청을 보내고 응답을 수신하기 위한 라이브러리 mysql-connector-java : MySQL 데이터베이스에 연결하고 SQL 쿼리를 수행하기 위한 라이브러리 gson : Java 객체와 JSON 간의 변환을 도와주는 라이브러리
 

2.2 DB와 연결 코드

 
_core/db/DBConnection
package org.example.weather._core.db; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBConnection { public static Connection getInstance() { String username = "root"; String password = "1234"; String url = "jdbc:mysql://localhost:3306/weatherdb"; // database의 이름을 넣는다. try { Connection connection = DriverManager.getConnection(url, url, password); return connection; } catch (SQLException e) { throw new RuntimeException(e.getMessage()); } } }
 
DB와 연결하기 위한 클래스를 만든다.
 

2.3 Http 요청 코드 만들기

 
_core/util/MyHttp
package org.example.weather._core.util; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class MyHttp { private static HttpClient httpClient = HttpClient.newHttpClient(); public static String get(String uri, String serviceKey, String baseDate, String baseTime, String nx, String ny) throws IOException, InterruptedException { String uriAndParams = "$uri?serviceKey=$serviceKey&base_date=$baseDate&base_time=$baseTime&nx=$nx&ny=$ny&dataType=json&pageNo=1&numOfRows=1000" .replace("$uri", uri) .replace("$serviceKey", serviceKey) .replace("$baseDate", baseDate) .replace("$baseTime", baseTime) .replace("$nx", nx) .replace("$ny", ny); System.out.println(uriAndParams); HttpRequest request = HttpRequest.newBuilder() .GET() .uri(URI.create(uriAndParams)) .build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); return response.body(); } }
 
공공 데이터 API 에 GET 요청을 위한 클래스를 만든다.
💡
문서에 위도 경도는 String 타입으로 표기 되어있기 때문에 String 타입으로 받아준다.

2.4 쿼리 코드 만들기

 
_core/dao/WeatherDAO
package org.example.weather._core.data; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; public class WeatherDAO { private final Connection connection; public WeatherDAO(Connection connection) { this.connection = connection; } public List<String> findDong(String gu) { List<String> dongList = new ArrayList<String>(); try { PreparedStatement pstmt = connection.prepareStatement("select dong from opendata_weather_tb where gu =?"); pstmt.setString(1, gu); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { dongList.add(rs.getString("dong")); } return dongList; } catch (Exception e) { throw new RuntimeException(e); } } }
 
DB에 접근해 데이터를 조회하는 클래스를 만든다.
 
💡
아래 사진의 화살표를 커서라고 한다. 커서가 테이블의 Row 를 하나씩 내려가면서 데이터를 조회하는데 데이터의 끝을 알 수 없기 때문에 while 문을 통해 반복한다. rs.next() 가 커서를 하나씩 내리는 코드이다.
notion image
 

2.5 테스트 코드 만들기

 
test/org/example/weahter/data/WeatherDAOTest
package org.example.weather._core.dao; import org.example.weather._core.db.DBConnection; import org.junit.jupiter.api.Test; import java.util.List; public class WeatherDAOTest { @Test public void findDong_test(){ //given String gu = "부산진구"; //when WeatherDAO dao = new WeatherDAO(DBConnection.getInstance()); List<String> dongList = dao.findDong(gu); dongList.forEach(System.out::println); } }
 
notion image
 
테스트 코드 실행 시 정상적으로 DB 조회가 되었다.
 

3. 위도 경도 조회하기

 

3.1 위도 경도 조회 쿼리 만들기

_core/dao/WeatherDAO
package org.example.weather.data; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class WeatherDAO { private final Connection connection; public WeatherDAO(Connection connection) { this.connection = connection; } public List<String> findDong(String gu) { List<String> dongList = new ArrayList<String>(); try { PreparedStatement pstmt = connection.prepareStatement("select dong from opendata_weather_tb where gu =?"); pstmt.setString(1, gu); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { dongList.add(rs.getString("dong")); } return dongList; } catch (Exception e) { throw new RuntimeException(e); } } public Map<String, String> findNxNy(String gu, String dong) { Map<String, String> los = new HashMap<>(); try { PreparedStatement pstmt = connection.prepareStatement("select nx,ny from opendata_weather_tb where gu= ? and dong =?"); pstmt.setString(1, gu); pstmt.setString(2, dong); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { los.put("nx", rs.getString("nx")); los.put("ny", rs.getString("ny")); } return los; } catch (Exception e) { throw new RuntimeException(e.getMessage()); } } }
 

3.2 테스트 코드 만들기

 
test/org/example/weahter/dao/WeatherDAOTest
package org.example.weather._core.dao; import org.example.weather._core.db.DBConnection; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.List; import java.util.Map; public class WeatherDAOTest { @Test public void findDong_test() { //given String gu = "부산진구"; //when WeatherDAO dao = new WeatherDAO(DBConnection.getInstance()); List<String> dongList = dao.findDong(gu); dongList.forEach(System.out::println); } @Test public void findNyNy_test() { //given String gu = "종로구"; String dong = "사직동"; //when WeatherDAO dao = new WeatherDAO(DBConnection.getInstance()); Map<String, String> los = dao.findNxNy(gu, dong); System.out.println(los.get("nx")); System.out.println(los.get("ny")); Assertions.assertEquals("60", los.get("nx")); Assertions.assertEquals("127", los.get("ny")); } }
 
notion image
 
테스트가 정상적으로 완료되었다.
 

4. 공공데이터 API 요청하기

 

4.1 공공 API 요청 클래스 만들기

 
_core/data/WeatherVO
package org.example.weather._core.data; public class WeatherVO { public String uri = "https://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst"; public String serviceKey = "GwP4SAIbheNGehkwEohRbKiZarjkYCbbT0%2FKzCWnPd7XL0vo97Tvx8b1Q4wwORGuGx47qa34CKrCDe4AL4vCrw%3D%3D"; public String baseDate; public String baseTime; public String nx; public String ny; public WeatherVO(String baseData, String baseTime, String nx, String ny) { this.baseDate = baseData; this.baseTime = baseTime; this.nx = nx; this.ny = ny; } }
 
notion image
 
마이페이지 - 데이터 활용 - Open API - 활용신청 현황에서 엔드포인트와 인코딩 인증키를 넣는다.
 

4.2 DTO 만들기

 
_core/data/WeatherDTO
package org.example.weather._core.data; import java.util.List; public class WeatherDTO { public ResponseDTO response; public static class ResponseDTO { public Body body; public static class Body { public String dataType; public Items items; public int pageNo; public int numOfRows; public int totalCount; public static class Items { public List<Item> item; public static class Item { public String baseDate; public String baseTime; public String category; public int nx; public int ny; public String obsrValue; } } } } }
 
API 요청을 통해 받을 JSON 데이터를 받을 DTO를 만든다.
 

4.3 메인 페이지 마무리

 
main
package org.example.weather; import com.google.gson.Gson; import org.example.weather._core.dao.WeatherDAO; import org.example.weather._core.data.WeatherDTO; import org.example.weather._core.data.WeatherVO; import org.example.weather._core.db.DBConnection; import org.example.weather._core.util.MyHttp; import java.util.List; import java.util.Map; import java.util.Scanner; public class Main { public static void main(String[] args) { // 객체 초기화 Scanner sc = new Scanner(System.in); WeatherDAO dao = new WeatherDAO(DBConnection.getInstance()); System.out.println("원하는 구를 입력하세요"); System.out.println("ex) [종로구, 수영구, 부산진구]"); // 구 데이터 입력받기 String gu = sc.nextLine(); // 입력받은 정보로 DB 연결 List<String> dongList = dao.findDong(gu); System.out.println("원하는 동을 입력하세요"); // 입력받기 전 DB로 조회된 동 리스트를 출력 dongList.forEach(s -> System.out.print(s + " ")); System.out.println(); // 한칸 띄우기 용 // 동 데이터 입력받기 String dong = sc.nextLine(); // 입력받은 데이터로 DB 연결 Map<String, String> los = dao.findNxNy(gu, dong); // 공공데이터 API 요청 WeatherVO vo = new WeatherVO("20240607", "1600", los.get("nx"), los.get("ny")); try { String responseBody = MyHttp.get( vo.uri, vo.serviceKey, vo.baseDate, vo.baseTime, vo.nx, vo.ny ); //GSON 라이브러리를 사용해 JSON 데이터 담기 Gson gson = new Gson(); WeatherDTO dto = gson.fromJson(responseBody, WeatherDTO.class); System.out.println("현재 온도 : " + dto.response.body.items.item.get(3).obsrValue); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } } }
notion image
 
구 와 동을 입력하면 온도를 얻을 수 있다.
Share article
RSSPowered by inblog