사용자가 공공데이터를 원하는 데이터만 제어하기 위해서는 어떤 지역을 날짜에 맞춰 선택하는 조회 관련 내용들이 필요합니다.
저는 Toast UI에서 제공하는 데이트 피커를 사용하였습니다.
https://ui.toast.com/tui-date-picker
이곳에서 cdn을 확인할 수 있습니다.
https://nhn.github.io/tui.date-picker/latest/tutorial-example08-daterangepicker
위 링크는 제가 사용한 범위를 선택하는 데이트피커입니다.
예제의 코드들을 통해 어떤 구성이 있는지 확인 가능합니다.
var today = new Date();
var yesterDay = new Date(today.setDate(today.getDate() - 1));
var picker = tui.DatePicker.createRangePicker({
startpicker: {
date: today,
input: '#startpicker-input',
container: '#startpicker-container'
},
endpicker: {
date: today,
input: '#endpicker-input',
container: '#endpicker-container'
},
selectableRanges: [
[new Date('2020-05-01'), yesterDay]
]
});
우선 컨트롤러에서는 어제의 날짜 하나의 데이터를 출력하기 때문에 데이트 피커도 동일하게 어제 날짜를 범위로 지정시켰습니다.
또한 코로나의 공공데이터가 1997년의 데이터는 없기 때문에 적당한 날짜의 범위를 제한하였습니다.
var startDate = document.getElementById('startpicker-input').value;
var endDate = document.getElementById('endpicker-input').value;
var dateArray = getDateRangeData(startDate, endDate);
조회 버튼을 누를 경우 데이트 피커의 시작, 끝 날짜를 받고 getDateRangeData라는 함수에 정의한 파라미터에 담깁니다.
getDateRangeData 이 함수는 범위를 배열로 담아주는 함수입니다.
그냥 범위에 맞는 데이터를 한 번에 받아서 처리하면 안 되나?라는 생각이 들 수도 있어 부가적인 설명을 드리자면..
공공데이터를 제어하기 위한 메서드는 url을 넣어 데이터를 받아오는 방식인데
2022-08-21,2022-08-22,2022-08-23을 한 번에 파라미터에 넣어 공공데이터를 가져올 수 없고
하나씩 넣어야 하기 때문에 배열로 ["2022-08-21", "2022-08-22", "2022-08-23" ] 받은 이후 반복하여 받아온 내용에 대해 데이터를 가공해야 합니다.
(분명 더 좋은 방법이 있을 거라고 생각하고 최대한 찾아봤지만 저의 최선이었습니다)
function getDateRangeData(param1, param2){ //param1은 시작일, param2는 종료일이다.
var res_day = [];
var ss_day = new Date(param1);
var ee_day = new Date(param2);
while(ss_day.getTime() <= ee_day.getTime()){
var _mon_ = (ss_day.getMonth()+1);
_mon_ = _mon_ < 10 ? '0'+_mon_ : _mon_;
var _day_ = ss_day.getDate();
_day_ = _day_ < 10 ? '0'+_day_ : _day_;
res_day.push(ss_day.getFullYear() + '-' + _mon_ + '-' + _day_);
ss_day.setDate(ss_day.getDate() + 1);
}
return res_day;
}
getDateRangeData 함수 코드는 다음과 같습니다.
8월 말에서 9월 초가 선택되면 어떻게 하지..라는 고민이 있었는데 다행히 구글링이 저를 살렸습니다.
그럼 이제 지역을 선택하는 파라미터가 남았습니다.
const query = 'input[name="gubun"]:checked'; //gubun name을 가진 input값의 checked값들만 가져온다
const selectedEls = document.querySelectorAll(query);
let result = '';
selectedEls.forEach((el) => {
result += el.value + ' '; //스페이스바를 줌으로서 기준점을 주는데
});
trimResult = result.trim();
resultArray = trimResult.split(' '); //스페이스바를 기준으로 배열이 생성되면서 마지막 result값에 스페이스바도 나뉘어짐
결과적으로 필요한 파라미터들이 모두 준비되었습니다.
이 데이터를 ajax를 통해 넘겨주고 컨트롤러에서 값을 담아 데이터를 받아 성공 시 그리드에 뿌려주면 되겠죠?
$.ajax({
url : "/togongda/searchCovidList",
method : "POST",
dataType : "JSON",
data : JSON.stringify({
"resultArray" : JSON.stringify(resultArray),
"dateArray" : JSON.stringify(dateArray)
}),
contentType : "application/json; charset=UTF-8",
success : function(result) {
grid1.resetData(result);
}// suc
,error:function(){
console.log('error');
}
}); //ajax
방금까지 만든 두 개의 배열을 data에 담으려니 평소에 하나씩 담아본 적은 있어도
두개의 배열을 어떤 식으로 넘겨야 할지 정말 고민이었습니다. (수많은 구글링이 저를 감쌈)
아래의 링크는 넘기려는 중 알게 된 내용 정리입니다.
https://yuni-spring.tistory.com/25
key값과 value값으로 이루어진 Map을 @RequestBody를 통해 넘기는 방향으로 잡았습니다.
@PostMapping(value = "/searchCovidList")
public List<Map<String, Object>> searchCovidList(@RequestBody Map<String, Object> params) throws IOException {
String resultStr = (String) params.get("resultArray");
String resultStr1 =resultStr.substring(0, resultStr.length()-1);
String resultStr2 = resultStr1.substring(1);
String[] resultArray = null;
resultArray = resultStr2.split(",");
String date = (String) params.get("dateArray");
String date1 =date.substring(0, date.length()-1);
String date2 = date1.substring(1);
String[] dateArray = null;
dateArray = date2.split(",");
List<Map<String, Object>> result = null; //마지막에 return할 List 선언
result = new ArrayList<>(); //list 초기화
for(int i=0; i<dateArray.length;i++) {
for(int j=0; j<resultArray.length;j++) {
String xml = getCovidData((dateArray[i].substring(0, dateArray[i].length()-1)).substring(1),(resultArray[j].substring(0, resultArray[j].length()-1)).substring(1));
Object json = XML.toJSONObject(xml); //xml -> json
String jsonStr = json.toString(); // json -> string
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject)jsonParser.parse(jsonStr);
JsonObject covidInfoResponse = (JsonObject)jsonObject.get("response");
JsonObject covidInfoBody = (JsonObject)covidInfoResponse.get("body"); // pageNo, totalCount
JsonObject covidInfoItems = (JsonObject)covidInfoBody.get("items");
JsonArray covidInfoItem = (JsonArray)covidInfoItems.get("item"); //item은 배열 형태 이기 때문에 JsonArray 형태로 변환
int len = covidInfoItem.size(); //JsonArray의 개수를 len에 대입
for (int k=0;k<len/2;k++){ //배열 크기만큼 반복
JsonObject jso = (JsonObject) covidInfoItem.get(k); //JsonArray안에 있는 값들의 순서대로 JsonObject로 변환
Map<String, Object> map = getMapFromJsonObject(jso); //변환한 JsonObject는 JSONObject를 Map<String, String> 형식으로 변환처리
result.add(map); //변환한 jso가 담긴 map이 list에 순서대로 담음
}
}
}
return result;
}
파라미터에서 가져온 resultArray와 dateArray (각 지역명, 날짜 범위) 값들을 좀 지저분하지만
컨트롤러에서 사용할 수 있도록 손봤습니다.
중요한 부분은 for문의 시작부터입니다.
총 출력되어야 하는 데이터를 생각해보면 날짜의 개수 x 선택한 지역의 개수입니다.
그렇기 때문에 날짜의 개수와 선택한 지역의 개수를 곱한 만큼 반복시켰습니다.
그 이후 xml 코드를 얻기 위해 getCovidData 메서드를 순서에 맞게 실행시켜야 하는데 큰따옴표가 붙는 관계로 잘라주고 파라미터에 넣어줍니다
getMapFromJsonObject 메서드에 대해 설명을 전에 했어야 했는데 말 그대로 JsonObject를 Map으로 변환해주는 메서드입니다.
public static Map<String, Object> getMapFromJsonObject(JsonObject covidInfoItem){
Map<String, Object> map = null;
try {
map = new ObjectMapper().readValue(covidInfoItem.toString(), Map.class);
} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}
covidInfoItem을 변환시켜주는 아주 중요한 메서드입니다.
이렇게 파라미터 값에 맞는 데이터를 List에 담았으니 ajax로 돌아가서 grid에 resetData 메서드를 통해 그리드에 값을 넣어주면 결과 화면은 아래와 같습니다.
아름답네요
선택한 파라미터를 통해 그리드에 값이 변경되는 것까지 확인했으니
다음 글부터는 Toast UI의 차트를 만드는 내용에 대해 다뤄보겠습니다.
'토공데' 카테고리의 다른 글
토스트 그리드를 통한 공공데이터 제어 프로젝트[5] - 파라미터에 의한 차트 (0) | 2022.08.23 |
---|---|
토스트 그리드를 통한 공공데이터 제어 프로젝트[4] - 차트 (0) | 2022.08.23 |
토스트 그리드를 통한 공공데이터 제어 프로젝트[2] - Toast Grid (0) | 2022.08.23 |
토스트 그리드를 통한 공공데이터 제어 프로젝트[1] - 공공데이터 (0) | 2022.08.23 |