today_is
[ json ] HashMap 을 이용한 json 데이터 mapping 본문
오늘의 목표
공공데이터 포털에 있는 json 데이터를 HashMap 으로 mapping 해서 출력해보자
프로젝트 구조

home.jsp
: 시작 페이지, a 태그를 이용하여 페이지 이동
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>day09</h1>
<hr>
<h3>JSON : JavaScript Object Notation</h3>
<h3>자바스크립트에서 객체를 표현하는데 사용하는 문법</h3>
<ul>
<li><a href="ex01">ex01 - 부산 축제 정보 서비스 연습</a></li>
<li><a href="ex02">ex02 - 부산 축제 정보 서비스 (AJAX)</a></li>
</ul>
</body>
</html>
ex01.jsp
: json 파일을 자바 객체로 변환하여 출력하기
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="cpath" value="${pageContext.request.contextPath }" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ex01.jsp</title>
<style>
#root {
width: 900px;
margin: 20px auto;
}
.item {
width: 800px;
margin: 10px auto;
border: 1px solid grey;
padding: 10px;
}
</style>
</head>
<body>
<h1>ex01 - JSON을 자바 객체로 변환하여 출력하기</h1>
<hr>
<p>
<a href="${cpath }/ex01/js"><button>JS로 처리하기</button></a>
</p>
<div id="root">
<c:forEach var="dto" items="${list }">
<div class="item">
<div><h3>${dto.UC_SEQ }. ${dto.TITLE } (${dto.GUGUN_NM })</h3></div>
<div>${dto.HOMEPAGE_URL }</div>
<div><img src="${dto.MAIN_IMG_NORMAL }" height="300"></div>
<div>
<details>
<summary>상세보기</summary>
<span>${dto.ITEMCNTNTS }</span>
</details>
</div>
</div>
</c:forEach>
</div>
</body>
</html>
해당 API 의 내용을 알아야함.
필드명이 일치해야 불러올 수 있기 때문
ex01- js.jsp
: json 파일을 자바 스크립트로 변환하여 출력하기
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ex01-js</title>
<style>
#root {
width: 900px;
margin: 20px auto;
}
.item {
width: 800px;
margin: 10px auto;
border: 1px solid grey;
padding: 10px;
}
</style>
</head>
<body>
<h1>ex01 - JSON을 자바스크립트로 처리하여 출력하기</h1>
<hr>
<div id="root"></div>
<script>
const jsonObject = ${json}
// console.log(jsonObject.getFestivalKr.item)
const arr = jsonObject.getFestivalKr.item
const root = document.getElementById('root')
root.innerHTML = ''
for(let i = 0; i < arr.length; i++) {
let tag = ''
tag += '<div class="item">'
tag += ' <div><h3>' + arr[i].UC_SEQ + '. ' + arr[i].TITLE + '(' + arr[i].GUGUN_NM + ')</h3></div>'
tag += ' <div>' + arr[i].HOMEPAGE_URL + '</div>'
tag += ' <div><img src="' + arr[i].MAIN_IMG_NORMAL + '" height="300"></div>'
tag += ' <div>'
tag += ' <details>'
tag += ' <summary>상세보기</summary>'
tag += ' <span>' + arr[i].ITEMCNTNTS + '</span>'
tag += ' </details>'
tag += ' </div>'
tag += '</div>'
root.innerHTML += tag
}
</script>
</body>
</html>
Ex01Controller
package com.itbank.controller;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.itbank.service.Ex01Service;
@Controller
public class Ex01Controller {
@Autowired private Ex01Service service;
private ObjectMapper objectMapper = new ObjectMapper();
@GetMapping("/ex01/js")
public ModelAndView ex01Js() throws MalformedURLException, IOException {
ModelAndView mav = ex01();
mav.setViewName("ex01-js");
return mav;
}
@GetMapping("/ex01")
public ModelAndView ex01() throws MalformedURLException, IOException {
ModelAndView mav = new ModelAndView();
String json = service.getFestivalJson(); // JSON 데이터는 문자열이다
mav.addObject("json", json);
System.out.println(json);
// JSON 형식의 문자열을 자바 객체로 변환하기 위한 코드
JsonNode node = objectMapper.readTree(json);
JsonNode item = node.get("getFestivalKr").get("item");
System.out.println("item : " + item.toPrettyString());
// DTO로 맵핑하기 (필드이름이 복잡하여 제대로 맵핑되지 않았다)
// List<FestivalDTO> list = Arrays.asList(
// objectMapper.readValue(item.toPrettyString(), FestivalDTO[].class)
// );
// System.out.println(list.get(0).getMAIN_TITLE());
// HashMap으로 맵핑하기
@SuppressWarnings("unchecked")
List<HashMap<String, Object>> list = Arrays.asList(
objectMapper.readValue(item.toPrettyString(), HashMap[].class)
);
System.out.println(list.get(0).get("MAIN_TITLE"));
mav.addObject("list", list);
return mav;
}
}
Ex01Controller 내용 중 어려웠던 부분
처음에는 DTO 로 처리하려고 했으나, 필드명이 복잡했기 때문에 mapping 이 잘 되지 않았음
수정사안 ) mapping 을 HashMap 으로 구현
(+) FestivalDTO
package com.itbank.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
// JSON데이터에서 DTO에 명시되지 않은 속성(알수없는 속성)은 무시하겠다
@JsonIgnoreProperties(ignoreUnknown = true)
// JSON의 속성이름을 자바 네이밍 컨벤션(camelCase)으로 변환하는 과정이 맞아야 한다
public class FestivalDTO {
@JsonProperty("UC_SEQ") private int UC_SEQ;
@JsonProperty("MAIN_TITLE") private String MAIN_TITLE;
@JsonProperty("GUGUN_NM") private String GUGUN_NM;
@JsonProperty("HOMEPAGE_URL") private String HOMEPAGE_URL;
@JsonProperty("MAIN_IMG_NORMAL") private String MAIN_IMG_NORMAL;
@JsonProperty("ITEMCNTNTS") private String ITEMCNTNTS;
public int getUC_SEQ() {
return UC_SEQ;
}
public void setUC_SEQ(int uC_SEQ) {
UC_SEQ = uC_SEQ;
}
public String getMAIN_TITLE() {
return MAIN_TITLE;
}
public void setMAIN_TITLE(String mAIN_TITLE) {
MAIN_TITLE = mAIN_TITLE;
}
public String getGUGUN_NM() {
return GUGUN_NM;
}
public void setGUGUN_NM(String gUGUN_NM) {
GUGUN_NM = gUGUN_NM;
}
public String getHOMEPAGE_URL() {
return HOMEPAGE_URL;
}
public void setHOMEPAGE_URL(String hOMEPAGE_URL) {
HOMEPAGE_URL = hOMEPAGE_URL;
}
public String getMAIN_IMG_NORMAL() {
return MAIN_IMG_NORMAL;
}
public void setMAIN_IMG_NORMAL(String mAIN_IMG_NORMAL) {
MAIN_IMG_NORMAL = mAIN_IMG_NORMAL;
}
public String getITEMCNTNTS() {
return ITEMCNTNTS;
}
public void setITEMCNTNTS(String iTEMCNTNTS) {
ITEMCNTNTS = iTEMCNTNTS;
}
}
Ex01Service
: Ex01Controller의 호출을 받고
요청된 내용을 처리한 후
결과값을 호출한 장소로 반환한다
package com.itbank.service;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Scanner;
import org.springframework.stereotype.Service;
@Service
public class Ex01Service {
// 공공데이터포털, 부산 축제 정보
private final String serviceKey = "K7G5hCA%2FRqnmALDK%2F7POZXDGSgTgQFRIcOqpF8HUf9rqLn17QSaJ4Q0Ox732h%2BF%2FgxuyB3bXrdEWApNVwrOtWA%3D%3D";
public String getFestivalJson() throws MalformedURLException, IOException {
// 1) 요청 주소 및 파라미터 준비
String url = "https://apis.data.go.kr/6260000/FestivalService/getFestivalKr";
HashMap<String, String> param = new HashMap<>();
param.put("pageNo", "1");
param.put("numOfRows", "10");
param.put("resultType", "json");
param.put("serviceKey", serviceKey);
url += "?";
for(String key : param.keySet()) {
url += key + "=" + param.get(key) + "&";
}
// 2) 요청을 전송하여 응답을 받아서 저장
Scanner sc = null;
String response = "";
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
if(conn.getResponseCode() == 200) { // 200 = 정상
sc = new Scanner(conn.getInputStream());
while(sc.hasNextLine()) {
response += sc.nextLine();
}
sc.close();
conn.disconnect();
}
return response;
}
}
Ex01Service 주의할 점
공공데이터포털 사이트에서 url 과 serviceKey 오타를 조심하자.
Study_review
처음에는 DTO로 매핑하려고 계속 코드를 수정했으나, 비효율적인 코드가 되었다.
이를 해결하고자 챗지피티에게 물어보았고, HashMap을 이용하게 되었다.
DTO를 이용해도 충분히 답을 얻을 수 있었겠지만, 일일이 코드를 수정해야 하는 상황이라
현재의 로직으로 바꾼 것이 신의 한 수였던 것 같다.
나의 원칙 = 비효율적인 방식은 선택하지말자.
'spring' 카테고리의 다른 글
[ websocket ] 메모장 (0) | 2024.03.03 |
---|---|
[ spring ] 다른 ip와 DB 내용 공유하기 (0) | 2024.03.03 |
[ Exception ] 예외처리, 예외전가 (0) | 2024.01.30 |
[ spring ] 간단한 POS 구현 (0) | 2024.01.19 |
[ spring ] RestController (0) | 2024.01.16 |