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("원하는 동을 입력하세요");
}
}

스캐너로 값을 받게 되었다. 이제 입력받은 값을 DB에서 조회해서 출력해보자.
2. 동 데이터 DB 조회
2.1 의존성 추가
build.gradle

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() 가 커서를 하나씩 내리는 코드이다.

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);
}
}

테스트 코드 실행 시 정상적으로 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"));
}
}

테스트가 정상적으로 완료되었다.
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;
}
}

마이페이지 - 데이터 활용 - 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());
}
}
}

구 와 동을 입력하면 온도를 얻을 수 있다.
Share article