[Spring] HashMap json mapping
2024. 10. 10. 01:41ㆍSpring
공공데이터 포털에 가면 오픈 되어 있는 여러가지 공공데이터들이 있다.
오늘은 그 오픈 json데이터를 HashMap으로 mapping 해볼 것이다.
home.jsp
<%@ 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
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;
}
}
위 코드에서 어려웠던 부분
처음에는 DTO로 처리하려고 했으나, 필드명이 너무 복잡해서 mapping이 잘 되지 않았다.
그래서 mapping을 HashMap으로 구현하였다.
FestivalDTO
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의 호출을 받고,
요청된 내용을 처리한 후
결과값을 호출한 장소로 반환한다.
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;
}
}
여기서 주의할 점
공공데이터 포털 사이트에서 url과 serviceKey 오타를 항상 조심해야 함.
DTO로 매핑을 계속 시도 했는데 잘 되지도 않고, 비효율적인 것 같아서 Chat gpt의 도움을 조금 받았다.
그래서 HashMap을 사용하게 되었고, 훨씬 효율적인 로직이 완성되었다.
언제나 간결성, 가독성 그리고 효율성이 좋은 코드를 작성하도록 노력이 필요하다.
'Spring' 카테고리의 다른 글
[Spring] WebSocket - 실시간 채팅 (0) | 2024.10.10 |
---|---|
[Spring] WebSocket을 활용한 메모장 만들기 (2) | 2024.10.10 |
[Spring] 매장 포스기 시스템 (1) | 2024.10.09 |
[Spring] RestController (1) | 2024.10.09 |
[Spring] 설문 투표 및 결과 보기 (1) | 2024.10.09 |