オープンAPI気象局は短期予報クエリーサービス/パケットを使用する(2)
1.getWeather()関数の作成
前回の記事では、DBはエリア情報を照会し、ダイナミックにエリアを変更しました.
これで、領域+日付+時間値を使用して実行すると、実際にAPI要求を実行するgetWeather()関数が作成されます.
function getWeather() {
var nullCheck = true;
$('.emptyCheck').each(function (){
if ('' == $(this).val()){
alert($(this).attr('title') + "을(를) 확인바람");
nullCheck = false;
return false; // 빈 값에서 멈춤
}
});
if (nullCheck) {
var time = $('#time').val()+'00';
if ($('#time').val() < 10){
time = "0" + time;
}
var areacode = "";
var cityCode = $('#step1 option:selected').val();
var countyCode = $('#step2 option:selected').val();
var townCode = $('#step3 option:selected').val();
if (townCode == '' && countyCode == '') {
areacode = cityCode;
}
else if(townCode == '' && countyCode != '') {
areacode = countyCode;
}
else if(townCode != '') {
areacode = townCode;
}
var date = $('#datepicker').val();
var data = {"areacode" : areacode, "baseDate" : date, "baseTime" : time};
$.ajax({
url: "/board/getWeather.do",
data: data,
dataType: "JSON",
method : "POST",
success : function(res){
console.log(res);
if (res[0].resultCode != null) {
alert(res[0].resultMsg);
}
else {
var html = "";
html += "<tbody><tr><th>nx=" + res[0].nx + "</th><th>ny=" + res[0].ny + "</th></tr>";
$("#resultWeather").empty();
$.each(res, function(index, item){
html += "<tr><td>" + item.category + "</td><td>" + item.obsrValue + "</td></tr>";
});
html += "</tbody>";
$("#resultWeather").append(html);
}
},
error : function(xhr){
alert(xhr.responseText);
}
});
}
}
Javascriptに擬似関数を追加します.htmlタグに
class=emptyCheck
の要素を設定します.eachを使用してすべての巡回操作を行う場合、入力されていない値がある場合、alertウィンドウを使用してAPI要求は実行されず、要素が空であることが表示されます.2.コントローラの変更
@Controller
public class WeatherController
{
@Autowired
private WeatherService weatherService;
@GetMapping(value = "/board/weather.do")
public String openWeatherPage()
{
return "/weather/weather";
}
@PostMapping(value = "/board/getWeather.do")
@ResponseBody
public List<WeatherDTO> getWeatherInfo(@ModelAttribute AreaRequestDTO areaRequestDTO) throws JsonMappingException, JsonProcessingException, UnsupportedEncodingException, URISyntaxException
{
AreaRequestDTO coordinate = this.weatherService.getCoordinate(areaRequestDTO.getAreacode());
areaRequestDTO.setNx(coordinate.getNx());
areaRequestDTO.setNy(coordinate.getNy());
List<WeatherDTO> weatherList = this.weatherService.getWeather(areaRequestDTO);
return weatherList;
}
@PostMapping(value = "/board/weatherStep.do")
@ResponseBody
public List<AreaRequestDTO> getAreaStep(@RequestParam Map<String, String> params)
{
return this.weatherService.getArea(params);
}
}
パラメータのAreaRequestDTOは、上のgetWeather()関数のdata(JSON形式)に設定されたareacode、baseDate、baseTime値のDTOです.getCoordinate()メソッドを受信値の領域コード(行政領域コード)を使用して実行すると、その領域コードに一致するny、nyの値が座標変数に格納されます.
nx、ny値を保存してgetWeather()メソッドを実行すると、AreaRequestDTOの変数を使用してAPI要求が実行されます.
最終的に、WeatherListには、API結果値情報を含むWeatherDTO値が含まれる.
3.サービスの変更
既存のサービスのgetArea()メソッドを保持し、次のコードを追加します.
Service
public interface WeatherService
{
List<WeatherDTO> getWeather(AreaRequestDTO areaRequestDTO) throws UnsupportedEncodingException, URISyntaxException, JsonMappingException, JsonProcessingException;
List<AreaRequestDTO> getArea(Map<String, String> params);
AreaRequestDTO getCoordinate(String areacode);
ResponseEntity<WeatherApiResponseDTO> requestWeatherApi(AreaRequestDTO areaRequestDTO) throws UnsupportedEncodingException, URISyntaxException;
}
ServiceImpl@Service
@Slf4j
public class WeatherServiceImpl implements WeatherService
{
@Autowired
private WeatherMapper weatherMapper;
@Override
public List<WeatherDTO> getWeather(AreaRequestDTO areaRequestDTO) throws UnsupportedEncodingException, URISyntaxException, JsonMappingException, JsonProcessingException
{
List<WeatherDTO> weatherList = this.weatherMapper.selectSameCoordinateWeatherList(areaRequestDTO); // 날짜, 시간, nx, ny가 requestDTO의 값과 일치하는 데이터가 있는지 검색
if ( weatherList.isEmpty() )
{
ResponseEntity<WeatherApiResponseDTO> response = requestWeatherApi(areaRequestDTO); // 데이터가 하나도 없는 경우 새로 생성
ObjectMapper objectMapper = new ObjectMapper();
List<WeatherItemDTO> weatherItemList = response.getBody()
.getResponse()
.getBody()
.getItems()
.getItem();
for ( WeatherItemDTO item : weatherItemList )
{
weatherList.add(objectMapper.readValue(objectMapper.writeValueAsString(item), WeatherDTO.class));
}
this.weatherMapper.insertWeatherList(weatherList); // API요청 후 결과값을 DB에 저장
return weatherList; // 로그를 찍지 않으려면 삭제해도 OK
}
return weatherList; // DB에 기존 저장되어있는 값에서 가져온 List
}
@Override
public List<AreaRequestDTO> getArea(Map<String, String> params)
{
return this.weatherMapper.selectArea(params);
}
@Override
public AreaRequestDTO getCoordinate(String areacode)
{
return this.weatherMapper.selectCoordinate(areacode);
}
@Override
public ResponseEntity<WeatherApiResponseDTO> requestWeatherApi(AreaRequestDTO areaRequestDTO) throws UnsupportedEncodingException, URISyntaxException
{
String url = "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtNcst";
String serviceKey = "여기에 Decoding Service Key를 입력";
String encodedServiceKey = URLEncoder.encode(serviceKey, "UTF-8");
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application", "JSON", Charset.forName("UTF-8")));
StringBuilder builder = new StringBuilder(url);
builder.append("?" + URLEncoder.encode("serviceKey", "UTF-8") + "=" + encodedServiceKey);
builder.append("&" + URLEncoder.encode("pageNo", "UTF-8") + "=" + URLEncoder.encode("1", "UTF-8"));
builder.append("&" + URLEncoder.encode("numOfRows", "UTF-8") + "=" + URLEncoder.encode("1000", "UTF-8"));
builder.append("&" + URLEncoder.encode("dataType", "UTF-8") + "=" + URLEncoder.encode("JSON", "UTF-8"));
builder.append("&" + URLEncoder.encode("base_date", "UTF-8") + "=" + URLEncoder.encode(areaRequestDTO.getBaseDate(), "UTF-8"));
builder.append("&" + URLEncoder.encode("base_time", "UTF-8") + "=" + URLEncoder.encode(areaRequestDTO.getBaseTime(), "UTF-8"));
builder.append("&" + URLEncoder.encode("nx", "UTF-8") + "=" + URLEncoder.encode(areaRequestDTO.getNx(), "UTF-8"));
builder.append("&" + URLEncoder.encode("ny", "UTF-8") + "=" + URLEncoder.encode(areaRequestDTO.getNy(), "UTF-8"));
URI uri = new URI(builder.toString());
ResponseEntity<WeatherApiResponseDTO> response = restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<String>(headers), WeatherApiResponseDTO.class);
return response;
}
}
4.Mapperの修正
@Mapper
public interface WeatherMapper
{
List<AreaRequestDTO> selectArea(Map<String, String> params);
AreaRequestDTO selectCoordinate(String areacode);
List<WeatherDTO> selectSameCoordinateWeatherList(AreaRequestDTO areaRequestDTO);
void insertWeatherList(List<WeatherDTO> weatherList);
}
mybatis<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.my.board.mapper.WeatherMapper">
<select id="selectArea" resultType="AreaRequestDTO" parameterType="Map">
<choose>
<when test="type == 'city'">
SELECT
areacode, step1
FROM
tb_weather_area
WHERE
step2 = "" AND step3 = ""
ORDER BY
step1
</when>
<when test="type == 'county'">
SELECT
areacode, step2
FROM
tb_weather_area
WHERE
step1 = #{keyword} AND step3 = "" AND step2 != ""
ORDER BY
step2
</when>
<when test="type == 'town'">
SELECT
areacode, step3
FROM
tb_weather_area
WHERE
step2 = #{keyword} AND step3 != ""
ORDER BY
step3
</when>
</choose>
</select>
<select id="selectCoordinate" parameterType="String" resultType="AreaRequestDTO">
SELECT
gridX as nx, gridY as ny
FROM
tb_weather_area
WHERE
areacode = #{areacode}
</select>
<select id="selectSameCoordinateWeatherList" parameterType="AreaRequestDTO" resultType="WeatherDTO">
SELECT DISTINCT
baseDate, baseTime, category, nx, ny, obsrValue
FROM
tw_weather_response
WHERE
baseDate = #{baseDate} AND
baseTime = #{baseTime} AND
nx = #{nx} AND
ny = #{ny}
</select>
<insert id="insertWeatherList" parameterType="WeatherDTO">
INSERT INTO tw_weather_response(
baseDate
,baseTime
,category
,nx
,ny
,obsrValue
)
VALUES
<foreach collection="list" item="item" open="(" separator="),(" close=")">
#{item.baseDate}
,#{item.baseTime}
,#{item.category}
,#{item.nx}
,#{item.ny}
,#{item.obsrValue}
</foreach>
</insert>
</mapper>
5.データベース表の作成
dbmsは、API応答値を格納するテーブルを生成する.
CREATE TABLE `tw_weather_response` (
`baseDate` VARCHAR(50) NOT NULL COMMENT '발표일자' COLLATE 'utf8_general_ci',
`baseTime` VARCHAR(50) NOT NULL COMMENT '발표시각' COLLATE 'utf8_general_ci',
`category` VARCHAR(50) NOT NULL COMMENT '자료구분코드' COLLATE 'utf8_general_ci',
`nx` VARCHAR(50) NOT NULL COMMENT '예보지점X좌표' COLLATE 'utf8_general_ci',
`ny` VARCHAR(50) NOT NULL COMMENT '예보지점Y좌표' COLLATE 'utf8_general_ci',
`obsrValue` VARCHAR(50) NOT NULL COMMENT '실황 값' COLLATE 'utf8_general_ci'
)
COMMENT='날씨 API 호출 응답값 저장'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
完了すると、次のようなテーブル構成が作成されます.APIリクエスト後、これらの値はすべて上のテーブルに格納されます.
6.DTOの作成
WeatherApiResponseDTO-APIリクエストを受信した後のレスポンス値オブジェクトのために作成されたDTOは、変数名レスポンスが実際のAPIリクエストの結果と一致する必要があります.
<200,WeatherApiResponseDTO(response=WeatherResponseDTO(header=WeatherHeaderDTO(resultCode=00, resultMsg=NORMAL_SERVICE), body=WeatherBodyDTO(dataType=JSON, items=WeatherItemsDTO(item=[WeatherItemDTO(baseDate=20220124, baseTime=1700, category=PTY, nx=60, ny=120, obsrValue=0.0), WeatherItemDTO(baseDate=20220124, baseTime=1700, category=REH, nx=60, ny=120, obsrValue=43.0), WeatherItemDTO(baseDate=20220124, baseTime=1700, category=RN1, nx=60, ny=120, obsrValue=0.0), WeatherItemDTO(baseDate=20220124, baseTime=1700, category=T1H, nx=60, ny=120, obsrValue=7.6), WeatherItemDTO(baseDate=20220124, baseTime=1700, category=UUU, nx=60, ny=120, obsrValue=-3.3), WeatherItemDTO(baseDate=20220124, baseTime=1700, category=VEC, nx=60, ny=120, obsrValue=100.0), WeatherItemDTO(baseDate=20220124, baseTime=1700, category=VVV, nx=60, ny=120, obsrValue=0.6), WeatherItemDTO(baseDate=20220124, baseTime=1700, category=WSD, nx=60, ny=120, obsrValue=3.5)], numOfRows=0, pageNo=0, totalCount=0)))),[Content-Language:"ko-KR", Set-Cookie:"JSESSIONID=7DMnHdbsSR49wbVAb64iZwZ1kX4vt7RlwRIHymwNqlZqpr9zpkaA2wfDEREDYPr5.amV1c19kb21haW4vbmV3c2t5Mw==; Path=/1360000/VilageFcstInfoService_2.0; HttpOnly; Domain=apis.data.go.kr", Content-Type:"application/json;charset=UTF-8", Content-Length:"909", Date:"Mon, 24 Jan 2022 08:30:25 GMT", Server:"NIA API Server"]>
実際のAPI要求後に受信した応答値の形式は、上記の形式である.
import lombok.Data;
@Data
public class WeatherApiResponseDTO
{
private WeatherResponseDTO response;
}
WeatherResponseDTO-タイトルと本文を応答オブジェクトから分離するために、上のWeatherApiResponseDTOで作成されたDTOimport lombok.Data;
@Data
public class WeatherResponseDTO
{
private WeatherHeaderDTO header;
private WeatherBodyDTO body;
}
WeatherHeaderDTO:DTOのタイトルに対応するDTOimport lombok.Data;
@Data
public class WeatherHeaderDTO
{
private String resultCode;
private String resultMsg;
}
WeatherBodyDTO-上の応答DTOにおいてbodyに適合するDTOimport lombok.Data;
@Data
public class WeatherBodyDTO
{
private String dataType;
private WeatherItemsDTO items;
}
WeatherItemsDTO-BodyDTOからアイテムコンテンツをインポートするDTOimport java.util.List;
import lombok.Data;
@Data
public class WeatherItemsDTO
{
private List<WeatherItemDTO> item;
private int numOfRows;
private int pageNo;
private int totalCount;
}
WeatherItemDTO:各実際の応答値をItems DTOから取得するためのDTOimport lombok.Data;
@Data
public class WeatherItemDTO
{
private String baseDate;
private String baseTime;
private String category;
private String nx;
private String ny;
private Double obsrValue;
}
WeatherDTO:View側に送信されるDTO@Data
public class WeatherDTO
{
// 발표 일자
private String baseDate;
// 발표 시각
private String baseTime;
// 자료구분코드
private String category;
// 예보지점 X좌표
private String nx;
// 예보지점 Y좌표
private String ny;
// 실황 값
private Double obsrValue;
}
これまでに8つのDTOが作成されています.上のWeatherApiResponseDTOからPTYクラスの応答値を知りたいなら
ResponseEntity<WeatherApiResponseDTO> response = restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<String>(headers), WeatherApiResponseDTO.class);
System.out.println(response.getBody().getResponse().getBody().getItems().getItem().get(0).getCategory());
同様に値を取得できます.書き終わったら、ページの実行ボタンをクリックすると、パケットされhtmlに送信されます.
また、定期的なAPI要求のスケジューリング機能とデータベース収集の平均値を表示するページを作成します.
Reference
この問題について(オープンAPI気象局は短期予報クエリーサービス/パケットを使用する(2)), 我々は、より多くの情報をここで見つけました https://velog.io/@with667800/오픈-API-기상청-단기예보2テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol