자바 JSON(2) 핸들링
기본적인 JSON 구조
❗JSON의 일반적인 구조
💡 “키”: “값” 쌍으로 이루어진 객체(object)의 집합
💡 “키”는 해당하는 “값”에 매핑
💡 객체는 중괄호 {}로 둘러싸여 있음.
💡 여러 객체를 배열로 묶을 수도 있음.
기본적인 JSON 라이브러리
❗자주 사용한 라이브러리
💡 org.json 라이브러리
💡 org.json.simple 라이브러리
💡 gson 라이브러리
(케이스1). 키: 값
JSON 형태
// 기본
{
"status":200, // 이거 꺼내보자
"msg":"성공", // 이거 꺼내보자
}
핸들링 (org.json 패키지)
import org.json.JSONObject;
//import org.json.JSONArray;
String strJsonStr = "[제이슨 형태 데이터]";
// [org.json 패키지]
JSONObject jsonObject = new JSONObject(strJsonStr);
/** 일반접근 (냉무) **/
int iStatus = jsonObject.getInt("status");
String strStatus = Integer.toString(iStatus);
String strMsg = jsonObject.getString("msg");
핸들링 (org.json.simple 패키지)
import org.json.simple.parser.JSONParser;
import org.json.simple.JSONObject;
//import org.json.simple.JSONArray;
String strJsonStr = "[제이슨 형태 데이터]";
// [org.json.simple 패키지]
JSONParser parser = new JSONParser();
JSONObject jsonObject = (JSONObject) parser.parse(strJsonStr);
/** 일반접근 (냉무) **/
long lStatus = (long) jsonObject.get("status");
String strStatus = (String) jsonObject.get("status").toString();
String strMsg = (String) jsonObject.get("msg");
정리
❗설명
💡 단순한 1depth 형태이다.
💡 기본적인 사용법이다.
(케이스2). 키: [값1,값2,값3]
JSON 형태
// 키의 값이 배열[] 형태이다.
{
"status":200,
"msg":"성공",
"result": [ // 이거 꺼내보자
"data1",
"data2",
],
}
핸들링 (org.json 패키지)
import org.json.JSONObject;
import org.json.JSONArray;
String strJsonStr = "[제이슨 형태 데이터]";
// [org.json 패키지]
JSONObject jsonObject = new JSONObject(strJsonStr);
/** 일반 배열 접근 (result 객체) **/
JSONArray arrResult = jsonObject.getJSONArray("result");
// 방법1 (기본 for문)
for(int i=0; i<arrResult.length(); i++) {
String strValue = arrResult.getString(i);
}
// 방법2 (향상된 for문)
for(String value: arrResult) {
String strValue = value;
}
// 방법3 (toList로 객체를 List 으로 변경)
String[] strArr = arrResult.toList().toArray(new String[0]);
for(String value: strArr) {
String strValue = value;
}
핸들링 (org.json.simple 패키지)
import org.json.simple.parser.JSONParser;
import org.json.simple.JSONObject;
import org.json.simple.JSONArray;
String strJsonStr = "[제이슨 형태 데이터]";
// [org.json.simple 패키지]
JSONParser parser = new JSONParser();
JSONObject jsonObject = (JSONObject) parser.parse(strJsonStr);
/** 일반 배열 접근 (result 객체) **/
JSONArray arrResult = (JSONArray) jsonObject.get("result");
// 방법1 (기본 for문)
for(int i=0; i<arrResult.size(); i++) {
String strValue = (String) arrResult.get(i);
}
// 방법2 (향상된 for문))
for(Object value: arrResult) {
String strValue = (String) value;
}
// 방법3 (toList로 객체를 List 으로 변경)
// - 이 패키지는 해당 메소드 없는것으로 확인
정리
❗설명
💡 단순한 1depth 형태로 이루어진 배열이다.
💡 기본적인 사용법이다.
- 각 패키지 모두 JSONArray 객체를 활용하는것을 알 수 있다.
(케이스3). 키: [ {키:값}, {키:값} ]
JSON 형태
{
"status": 200,
"msg": "성공",
"result": [
"data1",
"data2"
],
"address": [ // 이거 꺼내보자
{
"data2": "데이터2의 값 홍길동주소",
"data1": "데이터1의 값 홍길동"
},
{
"data2": "데이터2의 값 박명수주소",
"data1": "데이터1의 값 박명수"
}
]
}
❗잠깐)
💡 address 객체가 추가되었다.
💡 키값은 배열인데, 배열 안에 또 객체가 들어있다.
💡 평소 자주 보던 구조로, 언제나 복잡해보이는 형태다.
핸들링 (org.json 패키지)
import org.json.JSONArray;
import org.json.JSONObject;
String strJsonStr = "[제이슨 형태 데이터]";
// [org.json 패키지]
JSONObject jsonData = new JSONObject(strJsonStr);
/** 객체를 가진 배열 접근 (addrss 객체) **/
//JSONArray arrAddress = (JSONArray) jsonData.get("address"); // 방법1(비직관적)
JSONArray arrAddress = (JSONArray) jsonData.getJSONArray("address"); // 방법2(직관적 방법)
// 방법1 (기본 for문)
for(int i=0; i<arrAddress.length(); i++) {
Object addrData = (Object) arrAddress.get(i);
JSONObject addr = (JSONObject) addrData; // 선택한 Array의 JSON 객체 생성
String data1 = addr.getString("data1");
String data2 = addr.getString("data2");
}
// 방법2 (향상된 for문))
for(Object addrData : arrAddress) {
JSONObject addr = (JSONObject) addrData;
String data1 = (String) addr.get("data1");
String data2 = (String) addr.get("data2");
}
// 방법3 (향상된 for문 key:set)
for(int i=0; i<arrAddress.length(); i++) {
JSONObject newjsonObject = arrAddress.getJSONObject(i);
for(String key: newjsonObject.keySet()) {
String strKey = key;
String strValue = newjsonObject.getString(key);
}
}
핸들링 (org.json.simple 패키지)
import org.json.simple.parser.JSONParser;
import org.json.simple.JSONObject;
import org.json.simple.JSONArray;
String strJsonStr = "[제이슨 형태 데이터]";
// [org.json.simple 패키지]
JSONParser parser = new JSONParser();
JSONObject jsonObject = (JSONObject) parser.parse(strJsonStr);
/** 객체를 가진 배열 접근 (addrss 객체) **/
JSONArray arrAddress = (JSONArray) jsonObject.get("address");
// 방법1 (기본 for문)
for(int i=0; i<arrAddress.size(); i++) {
JSONObject addr = (JSONObject) arrAddress.get(i); //이 패키지는 즉시 String 불가능
String data1 = (String) addr.get("data1");
String data2 = (String) addr.get("data2");
}
// 방법2 (향상된 for문))
for(Object addrData : arrAddress) {
JSONObject addr = (JSONObject) addrData;
String data1 = (String) addr.get("data1");
String data2 = (String) addr.get("data2");
}
정리
❗설명
💡 2depth 형태이다.
💡 비교적 간단한 형태이다.
💡 위 객체로 루프 돌면서 데이터 핸들링하면 끝이다.
💡 이런 간단한 데이터는 따로 VO(DTO)를 사용하지 않아도 컨버트 할 필요는 없다.
🎆 (케이스4). 키:[ {키:값}, 키:[ {키:값}, {키:값} ] ]
⭐ JSON 형태
{
"documnet": [{
"status": 200,
"msg": "성공",
"result": [
"data1",
"data2"
],
"address": [
{
"data2": "데이터2의 값 홍길동주소",
"data1": "데이터1의 값 홍길동"
},
{
"data2": "데이터2의 값 박명수주소",
"data1": "데이터1의 값 박명수"
}
],
"language": [
{
"언어": "일본어",
"언어2": "카타카나",
"언어1": "히라가나"
},
{
"언어": "중국어",
"언어2": "번체",
"언어1": "간체"
}
]
}]
}
❗설명
💡 아까전에는 배열 형태의 객체가 한개였지만.. 복잡하게 추가되었다.
💡 복잡하고 데이터 중간에 리스트이거나 , object 형 데이터가 끼어 있으면 막막하다.
⭐ 핸들링 (org.json 패키지)
import org.json.JSONArray;
import org.json.JSONObject;
String strJsonStr = "[제이슨 형태 데이터]";
// [org.json 패키지]
/** 객체를 가진 배열 접근 (document 객체) **/
JSONObject jsonData = new JSONObject(strJsonStr);
JSONArray arrDcument = jsonData.getJSONArray("documnet"); // 배열 JSON객체 GET
for (Object docData : arrDcument) {
JSONObject doc = (JSONObject) docData; // 선택한 Array의 JSON 객체 생성
/** 일반접근 (냉무) **/
String strMsg = doc.getString("msg");
int iStatus = doc.getInt("status");
/** 일반 배열 접근 (result 객체) **/
//JSONArray arrResult = (JSONArray) doc.getJSONArray("result"); // 방법1(직관적 방법)
JSONArray arrResult = (JSONArray) doc.getJSONArray("result"); // 방법2(직관적 방법)
for (int i = 0; i < arrResult.length(); i++) {
String strResult = arrResult.getString(i);
}
/** 객체를 가진 배열 접근1 (addrss 객체) **/
//JSONArray arrTemp = (JSONArray) doc.get("address"); // 방법1(비직관적)
JSONArray arrAddress = (JSONArray) doc.getJSONArray("address"); // 방법2(직관적 방법)
// 방법1 (기본 for문)
for(int i=0; i<arrAddress.length(); i++) {
Object addrData = (Object) arrAddress.get(i);
JSONObject addr = (JSONObject) addrData; // 선택한 Array의 JSON 객체 생성
String data1 = addr.getString("data1");
String data2 = addr.getString("data2");
}
// 방법2 (향상된 for문))
for(Object addrData : arrAddress) {
JSONObject addr = (JSONObject) addrData;
String data1 = (String) addr.get("data1");
String data2 = (String) addr.get("data2");
}
// 방법3 (향상된 for문 key:set)
for(int i=0; i<arrAddress.length(); i++) {
JSONObject newjsonObject = arrAddress.getJSONObject(i);
for(String key: newjsonObject.keySet()) {
String strKey = key;
String strValue = newjsonObject.getString(key);
}
}
/** 객체를 가진 배열 접근2 (language 객체) **/
//JSONArray arrTemp = (JSONArray) doc.get("language"); // 방법1(비직관적)
JSONArray arrlanguage = (JSONArray) doc.getJSONArray("language"); // 방법2(직관적 방법)
for (Object langData : arrlanguage) {
JSONObject lang = (JSONObject) langData; // 선택한 Array의 JSON 객체 생성
String lang1 = lang.getString("언어");
String lang2 = lang.getString("언어1");
String lang3 = lang.getString("언어2");
}
// 그외 방법2, 3 위와 동일
}
⭐ 핸들링 (org.json.simple 패키지)
import org.json.simple.parser.JSONParser;
import org.json.simple.JSONObject;
import org.json.simple.JSONArray;
String strJsonStr = "[제이슨 형태 데이터]";
// [org.json.simple 패키지]
/** 객체를 가진 배열 접근 (document 객체) **/
JSONParser parser = new JSONParser();
JSONObject jsonObject = (JSONObject) parser.parse(strJsonStr);
JSONArray arrDcument = (JSONArray) jsonObject.get("documnet");
for(Object docData : arrDcument) {
JSONObject doc = (JSONObject) docData; // 선택한 Array의 JSON 객체 생성
/** 일반접근 (냉무) **/
long lStatus = (long) doc.get("status");
String strStatus = (String) doc.get("status").toString();
String strMsg = (String) doc.get("msg");
/** 일반 배열 접근 (result 객체) **/
//JSONArray arrAddress = (JSONArray) doc.get("result"); // 이렇게 불가능하다.
Object objResult = doc.get("result"); //이 패키지는 object 를 즉시 array 리턴 기능이 없다. 먼저 이렇게 OBJ 로 만든다.
JSONArray arrResult = (JSONArray) objResult; // 그리고 array 로 만들 수 있다.
for(int i=0; i<arrResult.size(); i++) {
String strResult = (String) arrResult.get(i); //array를 string 으로 캐스팅
}
/** 객체를 가진 배열 접근1 (addrss 객체) **/
//JSONArray arrAddress = (JSONArray) doc.get("address"); // 이렇게 불가능하다.
Object objAddress = doc.get("address");
JSONArray arrAddress = (JSONArray) objAddress;
// (기본 for문 으로 구현!)
for(int i=0; i<arrAddress.size(); i++) {
JSONObject addr = (JSONObject) arrAddress.get(i); //이 패키지는 JSON객체형태를 즉시 String 불가능
String data1 = (String) addr.get("data1");
String data2 = (String) addr.get("data2");
}
/** 객체를 가진 배열 접근2 (language 객체) **/
//JSONArray arrLanguage = (JSONArray) doc.get("language"); // 이렇게 불가능하다.
Object objLanguage= doc.get("language");
JSONArray arrLanguage = (JSONArray) objLanguage;
// (향상된 for문 으로 구현!)
for(Object langData : arrLanguage) {
JSONObject lang = (JSONObject) langData;
String lang1 = (String) lang.get("언어").toString();
String lang2 = (String) lang.get("언어1").toString();
String lang3 = (String) lang.get("언어2").toString();
}
}
⭐ 정리
❗특정 루트를 선택해야한다.
💡 루트에 document 배열로 감싸져있으므로 접근 하려면 또 아래와 같이 객체를 선택적으로 생성하고 접근해야한다.//org.json JSONArray arrDcument = jsonData.getJSONArray("documnet"); JSONArray arrlanguage = (JSONArray) doc.getJSONArray("language"); //org.json.simple JSONArray jsonArray = new JSONArray(jsonObject.get("document").toString); JSONArray jsonArray = new JSONArray(jsonObject.get("language").toString);
❗특정
💡 선택한 JSONArray 의 데이터를 뽑기 위해서
- JSONArray ==> Object 변환
- Object ==> JSONObject 변환
- JSONObject 에서 string 값 추출한다.
❗문제점
💡 JSONObject 안에 또 객체 집합이 있으면 무한반복이다.
💡 더 복잡해지면 거의 핸들링 불가능한 수준일듯.
🎆 (최종) 데이터를 핸들링 For ‘VO(DTO) & GSON’
⭐ 강력한 라이브러리 (Jackson, Gson)
❗목표는 각 documets 반복문을 돌면서 필드아이디 별로 데이터들을 핸들링하는것이 목적이다.
💡 Jackson, Gson 등의 JSON 라이브러리를 사용하면 된다.
💡 JSON 데이터의 키와 값을 매핑하여 Map 객체로 자동 변환된다.
💡 매우 강력한 도구다.
⭐ 라이브러리 미적용 코드 (기본 사용법)
JSONObject jsonObject = new JSONObject(jsonString);
PersonDTO personDTO = new PersonDTO();
personDTO.setName(jsonObject.getString("name"));
personDTO.setAge(jsonObject.getInt("age"));
personDTO.setCity(jsonObject.getString("city"));
System.out.println("Name: " + personDTO.getName());
System.out.println("Age: " + personDTO.getAge());
System.out.println("City: " + personDTO.getCity());
❗문제점
💡 VO(DTO)를 쓰고는 있지만…. (笑)(笑)
💡 이 코드는 이전과 다를게 없다.
💡 타입 정의하고 맞춰주는 작업이 필요하다.
💡 라이브러리를 사용하면 더욱 간단하게 사용 가능하다.
JSON 형태
{
"documnet": [
{
"msg": "성공",
"result": [
"data1",
"data2"
],
"address": [
{
"data2": "데이터2의 값 홍길동주소",
"data1": "데이터1의 값 홍길동"
},
{
"data2": "데이터2의 값 박명수주소",
"data1": "데이터1의 값 박명수"
}
],
"language": [
{
"언어": "일본어",
"언어2": "카타카나",
"언어1": "히라가나"
},
{
"언어": "중국어",
"언어2": "번체",
"언어1": "간체"
}
],
"status": 200
}
],
"etc": {
"name": "기타"
}
}
⭐ 구현1) (GSON 적용)
String strJsonStr = "[제이슨 형태 데이터]";
// [Gson 활용]
Gson gson = new Gson();
/** JSON 문자열을 GSON 라이브러리로 Map<String, Object> 타입으로 변환 **/
java.lang.reflect.Type mapType = new com.google.gson.reflect.TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> mapJson = gson.fromJson(strJsonStr, mapType);
/** 배열타입인 document 를 List로 변환 **/
List<Map<String, Object>> listDocumnet = (List<Map<String, Object>>) mapJson.get("documnet");
if (listDocumnet != null && !listDocumnet.isEmpty()) {
Map<String, Object> mapDocument = listDocumnet.get(0); // document의 [0] 인덱스 선택
/** 일반접근 (냉무) **/
String msg = (String) mapDocument.get("msg");
int status = ((Double) mapDocument.get("status")).intValue(); // Double을 int로 변환
System.out.println("msg: " + msg);System.out.println("status: " + status);
/** 일반 배열 접근 (result 객체) **/
List<String> listResult = (List<String>) mapDocument.get("result"); //꺼냈는데 result의 속성 타입은 [] 배열이다.
// 배열은 이렇게 List 타입으로 캐스팅해서 핸들링하면 된다.
if (listResult != null && !listResult.isEmpty()) {
System.out.println("Result:");
for (String value : listResult) {
String strResult = value;
}
}
/** 객체를 가진 배열 접근1 (addrss 객체) **/
List<Map<String, String>> address = (List<Map<String, String>>) mapDocument.get("address");
for (Map<String, String> addr : address) {
String data1 = addr.get("data1");
String data2 = addr.get("data2");
}
/** 객체를 가진 배열 접근2 (language 객체) **/
List<Map<String, String>> language = (List<Map<String, String>>) mapDocument.get("language");
for (Map<String, String> lang : language) {
String lang1 = lang.get("언어");
String lang2 = lang.get("언어1");
String lang3 = lang.get("언어2");
System.out.println(lang1);System.out.println(lang2);System.out.println(lang3);
}
}
/** 기본 타입인 etc 를 Map 으로 변환 **/
/** etc **/
Map<String, Object> etc = (Map<String, Object>) mapJson.get("etc");
if (etc != null) {
String name = (String) etc.get("name");
System.out.println("etc name: " + name);
}
⭐ 구현2) (GSO, DTO 적용)
TestDTO.java
/* TestDto.java */
public class TestDTO {
/* 일반 JSON 형태 */
private Map<String, Object> etc; // 키:{값}
/* 배열 JSON 형태 */
private List<Map<String, Object>> documnet; // 키:[...키:{값}]
public Map<String, Object> getEtc() {
return etc;
}
public void setEtc(Map<String, Object> etc) {
this.etc = etc;
}
public List<Map<String, Object>> getDocumnet() {
return documnet;
}
public void setDocumnet(List<Map<String, Object>> documnet) {
this.documnet = documnet;
}
}
❗일반 JSON 형태
💡 키:{값} 형태이다.
💡 Map<String, Object> 타입으로 정의한다.❗배열 JSON 형태
💡 키:[…키:{값}] 형태이다.
💡 List<Map<String, Object» 타입으로 정의한다.
Gson 라이브러리는 이 형태에 꼭 맞도록 변형해줄것이다.
메인.java
String strJsonStr = "[제이슨 형태 데이터]";
// [Gson + DTO 활용]
Gson gson = new Gson();
TestDTO testDto = new TestDTO();
// 강력한 GSON 라이브러리
testDto = gson.fromJson(strJsonStr, TestDTO.class);
// 배열형태인 도큐먼트를 선택하기 위해 (리스트<맵>) 타입을 GET
List<Map<String, Object>> documnet = testDto.getDocumnet();
if (documnet != null && !documnet.isEmpty()) {
// 진짜 간단하게 가져왔다.
Map<String, Object> mapDoc = documnet.get(0);
/** 일반접근 (냉무) **/
String strMsg = (String) mapDoc.get("msg").toString();
double statusDouble = (double) mapDoc.get("status"); // gson은 double로 가져옴
int iStatus = (int) statusDouble; // Integer로 형변환
/** 일반 배열 접근 (result 객체) **/
List<String> result = (List<String>) mapDoc.get("result");
for (int i = 0; i < result.size(); i++) {
String strResult = result.get(i);
}
/** 객체를 가진 배열 접근1 (addrss 객체) **/
List<Map<String, String>> address = (List<Map<String, String>>) mapDoc.get("address");
for (Map<String, String> addr : address) {
String data1 = addr.get("data1");
String data2 = addr.get("data2");
}
/** 객체를 가진 배열 접근2 (language 객체) **/
List<Map<String, String>> language = (List<Map<String, String>>) mapDoc.get("language");
for (Map<String, String> lang : language) {
String lang1 = lang.get("언어");
String lang2 = lang.get("언어1");
String lang3 = lang.get("언어2");
}
}
// 일반형태인 ETC 를 선택하기 위해 (맵) 타입을 GET
Map<String, Object> etc = testDto.getEtc();
if (etc != null && !etc.isEmpty()) {
System.out.println(etc.get("name"));
}
❗엄청나게 간략해졌다.
💡 자동으로 key 를 매핑해서 자동으로 타입에 맞도록 넣어주고있다.
💡 직접 과정들을 구현해보니 라이브러리가 엄청난것을 느낀다..
⭐ GSON 라이브러리의 성능 정리
❗그래서 GSON 이란?
💡 Gson은 JSON 데이터의 키와 자바 객체의 필드를 자동으로 매핑한다.
💡 즉, 데이터의 타입에 따라 자동으로 적절한 타입으로 변환되어 들어간다.
💡 이를 “자동 직렬화 및 역직렬화” 라고 한다.❗예시1
💡 주어진 JSON 데이터가 “status”: 200으로 정수 형식이라면?
💡 Gson은 해당 값을 자동으로 int로 변환하여 자바 객체의 필드에 매핑.❗예시2
💡 주어진 JSON 데이터가 “msg”: “성공”으로 문자열 형식이라면?
💡 Gson은 해당 값을 문자열로 변환하여 매핑.❗명확하게 느낀 내용
💡 자동으로 데이터 타입 변환을 처리해주므로 별도의 형변환 작업을 수동으로 할 필요가 없는점이다. 아래 작업을 안해도 된다.
- 선택한 JSONArray 의 데이터를 뽑기 위해서
- JSONArray ==> Object 변환
- Object ==> JSONObject 변환
- JSONObject 에서 string 값 추출한다.
추가) JSON to Array 의 성능
❗설명
💡 이 로직은 JSON 객체의 특정 속성이 배열로 되어 있을 때 사용
💡 JSON 배열을 Java 배열로 변환하여 사용
💡 간단한 데이터는 따로 VO(DTO)를 사용하지 않아도 컨버트 할 필요는 없다.
추가) JSON to Map 성능
❗설명
💡 이 로직은 JSON 객체를 Java Map 으로 변환하는 함수를 사용
💡 더 추상화된 방법으로 JSON 데이터를 다룰 수 있어 가독성 향상
💡 JSON 데이터를 Map으로 변환하여 사용하면 다양한 속성에 쉽게 접근가능❗단점
간단하고 직관적인 방법이지만, 배열의 크기 등을 직접 다루어야 하기 때문에 조금 더 수동적인 접근이 필요.
더 복잡한 구조의 JSON 데이터를 다루거나 가독성을 높이고자 한다면 MAP 활용이 유용
(JSP 처리) EL
(JSON) JSON형태 String 조작 👎❌
/* java (백앤드) */
String strJsonStr =
"{" +
" \"documnet\": [" +
" {" +
" \"status\": 200," +
" \"msg\": \"성공\"," +
" \"result\": [" +
" \"data1\"," +
" \"data2\"" +
" ]," +
" \"address\": [" +
" {" +
" \"data2\": \"데이터2의 값 홍길동주소\"," +
" \"data1\": \"데이터1의 값 홍길동\"" +
" }," +
" {" +
" \"data2\": \"데이터2의 값 박명수주소\"," +
" \"data1\": \"데이터1의 값 박명수\"" +
" }" +
" ]," +
" \"language\": [" +
" {" +
" \"언어\": \"일본어\"," +
" \"언어2\": \"카타카나\"," +
" \"언어1\": \"히라가나\"" +
" }," +
" {" +
" \"언어\": \"중국어\"," +
" \"언어2\": \"번체\"," +
" \"언어1\": \"간체\"" +
" }" +
" ]" +
" }" +
" ]," +
" \"etc\": {" +
" \"name\": \"기타\"" +
" }" +
"}";
SONObject jsonObject = new JSONObject(strJsonStr);
SONObject etcObject = jsonObject.getJSONObject("etc");
tring etc = etcObject.getString("name");
ystem.out.println(etc);
odel.addAttribute("type0", strJsonStr);
<!-- JSP (프론트) -->
<!-- String (for Perfect ORIGNAL JSON) -->
<h3><i>완전한 json 문자열 전달</i></h3>
<ul>
<li><b>JSON String: </b> ${type0}</li>
<%-- type0 변수에 저장된 JSON 문자열을 EL을 사용하여 받아옴 --%>
<%
String strJson = (String) request.getAttribute("type0");
JSONObject jsonObject = new JSONObject(strJson);
JSONObject etcObject = jsonObject.getJSONObject("etc");
String etc = etcObject.getString("name");
System.out.println("etc: " + etc);
%>
<li><b>etc : </b> ${etc}</li>
❗JSON을 EL로 표현하는것은 사용하지말자…
💡etc 객체의 키(name)값이 출력되지 않는다..
💡내부 엔진의 문제인듯 하다. 이 방법으로 절대 시간 소비하지말자 … 꼭.. 서버에서 처리하자..❗챗GPT 답변
- JSP 문법 오류: JSP 코드 내에서 ${}로 값을 가져오는 부분에 문법적인 오류가 있는지 확인해야 합니다. <% %> 스크립트릿과 EL 표현식을 혼합해서 사용하면 문제가 발생할 수 있습니다.
- ❌ 해당되지 않는다. System.out.println(“etc: “ + etc); 출력되었기에..
- etc 변수가 null이거나 값이 없는 경우: ${etc}로 값을 출력하려면 etc 변수가 올바르게 값을 가지고 있어야 합니다. System.out.println(“etc: “ + etc);가 출력되어도, 변수 값이 null이거나 비어있다면 출력되지 않을 수 있습니다.
- ❌ 해당되지 않는다. String etc 정의가 되었으니까 출력되었겠지.
- JSP 컨테이너 설정: 일부 경우에는 JSP 컨테이너 설정이나 JSP 엔진의 동작 방식에 의해 EL 표현식이 올바르게 해석되지 않을 수 있습니다. 이 경우에는 JSP 컨테이너의 로그를 확인하거나 컨테이너 설정을 검토해야 할 수 있습니다.
- 🤔 이부분으 의심되지만 확인하기 어렵다.
(JSON) List, Map 객체 조작 👍
/* java (백앤드) */
String strJsonStr = "[제이슨 형태 데이터]";
Gson gson = new Gson();
TestDTO testDto = new TestDTO();
testDto = gson.fromJson(strJsonStr, TestDTO.class);
// document (배열)
List<Map<String, Object>> documnet = testDto.getDocumnet();
// etc (기본)
List<Map<String, Object>> type1 = testDto.getDocumnet();
Map<String, Object> type2 = testDto.getEtc();
model.addAttribute("type1", documnet);
model.addAttribute("type2", etc);
<!-- JSP (프론트) -->
<!-- List<Map<String, Object>> -->
<h3><i>document 전달</i></h3>
<c:forEach var="item" items="${type1}">
<ul>
<li><b>document 객체: </b> ${type1}</li>
<li><b>status: </b> ${item.status}</li>
<li><b>msg: </b> ${item.msg}</li>
<li><b>result: </b> ${item.result}</li>
<li><b>address: </b> ${item.address}</li>
<c:forEach var="address" items="${item.address}">
<ul>
<li><b>data1(key): </b> ${address.data1}</li>
<li><b>data2(key): </b> ${address.data1}</li>
</ul>
</c:forEach>
<li><b>language(한글EL불가):</b> ${item.language}</li>
</ul>
</c:forEach>
<hr>
<!-- Map<String, Object> -->
<h3><i>etc 전달</i></h3>
<ul>
<li><b>etc 객체: </b> ${type2}</li>
<p>name: ${type2.name}</p>
</ul>
<hr>
(JSP 처리) Script
(JSON) JSON형태 String 조작 👍
/* java (백앤드) */
String strJsonStr = "[제이슨 형태 데이터]";
model.addAttribute("type0", strJsonStr);
// jsp (프론트)
<script>
$(document).ready(function (){
// 온로드시 백앤드에서 전달받은 JSON 처리
type0 = '${type0}'; // Original JSON String
var parsedData = JSON.parse(type0);
var stastus = parsedData.documnet[0].status;
var msg = parsedData.documnet[0].msg;
var address = parsedData.documnet[0].address[0].data1;
var language = parsedData.documnet[0].language[0].언어;
});
</script>
❗설명
💡 JSON 형태가 완전하면 JSP 에서 조작이 가능하다.
💡 즉, JSON.parse(); 함수가 가능해진다.
⭐⭐⭐ (JSON) List, Map 객체 조작 핵심
❗설명
💡 JSON 형태가 완전하면 JSP 에서 조작이 가능하다.
💡 즉, JSON.parse(); 함수로 조작이 가능해진다.
💡 이, JSON.parse(); 함수를 사용해야 직관적으로 체이닝을 통해 값에 접근이 가능하므로 필수라고 생각한다..❗JSON.parse() 를 사용하기위한 조건
💡 JSON.parse()를 사용하기 위한 조건
- 키는 “” 감싸져야함.
- 값은 “” 감싸져야함.
- 즉, 완벽한 JSON 형태의 문자열을 인수로 사용해야한다.
❗문제점
💡 대부분 Java 에서 핸들링하면 무조건 키와 값의 JSON 형태가 풀리게된다.(“큰따옴표가 지워짐)
💡 값에 숫자가 들어가는 경우에도 “큰따옴표가 없으므로 에러가 발생한다.❗해결방법
💡 해결방법은 입맞대로 가공을 마치면 JS에서 인식할 수 있는 String 으로 가공해주어야 한다.
반드시 아래와 같은 형태로 서버에서 JSP 측으로 전달해야만 한다.// JSON.parse() 사용 불가능 {"clusterInfo": {"appsSubmitted": 1.0,"appsCompleted": 25000.0}} // JSON.parse() 사용 가능 {"clusterInfo": {"appsSubmitted":"1.0","appsCompleted":"25000.0"}}
(JSON) List, Map 객체 조작(1) 자바로 생성한 완벽한 JSON
/* java (백앤드) */
// org.json 패키지를 활용
// 완벽한 JSON 형태의 문자열을 만드는 함수
public static String creatJsonObj1() {
String strJsonObject = "";
JSONObject jsonObject = new JSONObject();
JSONArray resultArray = new JSONArray(); //일반 배열
JSONArray addressArray = new JSONArray(); //객체 배열
resultArray.put("data1");
resultArray.put("data2");
addressArray.put(new JSONObject() );
addressArray.put(new JSONObject() );
jsonObject.put("status", 200);
jsonObject.put("msg", "성공");
jsonObject.put("result", resultArray);
jsonObject.put("address", addressArray);
strJsonObject = (String) jsonObject.toString();
return strJsonObject;
}
// JSP (프론트로) 전달
model.addAttribute("goodJson", creatJsonObj1());
// jsp (프론트)
<script>
$(document).ready(function (){
// 완벽한 JSON 이므로 조작이 가능해진다.
var goodJson = '${goodJson}';
var perffectJson = JSON.parse(goodJson); //이게 가능해진다.
var stastus = perffectJson.status;
var msg = perffectJson.msg;
var address = perffectJson.address[0].data1;
var language = perffectJson.language[0].언어;
});
</script>
(JSON) List, Map 객체 조작(2) 자바로 생성한 완벽한 JSON
String jsonString = "{\"documnet\":[{\"msg\":\"성공\",\"result\":[\"data1\",\"data2\"],\"address\":[{\"data2\":\"데이터2의 값 홍길동주소\",\"data1\":\"데이터1의 값 홍길동\"},{\"data2\":\"데이터2의 값 박명수주소\",\"data1\":\"데이터1의 값 박명수\"}],\"language\":[{\"언어\":\"일본어\",\"언어2\":\"카타카나\",\"언어1\":\"히라가나\"},{\"언어\":\"중국어\",\"언어2\":\"번체\",\"언어1\":\"간체\"}],\"status\":200}]}";
// JSP (프론트로) 전달
model.addAttribute("goodJson2", creatJsonObj1());
// jsp (프론트)
<script>
$(document).ready(function (){
// 완벽한 JSON 이므로 조작이 가능해진다.
var goodJson2 = '${goodJson2}'; //이게 가능해진다.
var perffectJson2 = JSON.parse(goodJson2);
var stastus2 = cluMtData.documnet[0].status;
var msg2 = cluMtData.documnet[0].msg;appsSubmitted,appsSubmitted,
var address2 = cluMtData.documnet[0].address[0].data1;
var language2 = cluMtData.documnet[0].language[0].언어;
});
</script>
(JSON) List, Map 객체 조작(3) 유틸리티로 생성한 JSON (1개처리)
java.lang.reflect.Type mapType2 = new com.google.gson.TypeToken<Map<String, Object>>(){}.getType();
Gson gson2 = new Gson();
Map<String, Object> mapResult2 = new HashMap<String, Object>();
// STEP1. API 요청후 JSON 얻기
//String getYarnJson2 = BlangJsonUtil.getYarnMetrics();
String getYarnJson2 = "{\"clusterMetrics\":{\"appsSubmitted\":1,\"appsCompleted\":25000,\"appsPending\":0,\"appsRunning\":0,\"appsFailed\":1,\"appsKilled\":1,\"reservedMB\":0,\"availableMB\":17408,\"allocatedMB\":0,\"reservedVirtualCores\":0,\"availableVirtualCores\":7,\"allocatedVirtualCores\":1,\"containersAllocated\":0,\"containersReserved\":0,\"containersPending\":0,\"totalMB\":17408,\"totalVirtualCores\":8,\"totalNodes\":1,\"lostNodes\":0,\"unhealthyNodes\":0,\"decommissioningNodes\":0,\"decommissionedNodes\":0,\"rebootedNodes\":0,\"activeNodes\":1,\"shutdownNodes\":0}}";
// STEP2. 얻은 JSON 키값의 데이터타입별로 GSON 라이브러리로 Map<String, Object> 동적처리.
Map<String, Object> mapJson2 = gson2.fromJson(getYarnJson2, mapType2);
// STEP3. ROOT KEY ACCESS
Map<String, Object> accessData2 = (Map<String, Object>) mapJson2.get("clusterMetrics");
// STEP4. JS가 인식가능한 완벽한 JSON 문자열 생성
if (accessData2 != null) {
String resultData2 = BlangJsonUtil.mapToJson(accessData2); // 완벽한 JSON 만들기
mapResult2.put("clusterMetrics", resultData2); // ROOT KEY 이름으로 맵키 생성
}
// JSP (프론트로) 전달
model.addAttribute("mapResult2", mapResult2);
<script>
$(document).ready(function (){
let jsonMetrics2 = '${mapResult2.clusterMetrics}';
if (jsonMetrics2 != null) {
var clusterMetrics = JSON.parse(jsonMetrics2); //함수 성공조건: 완벽한 JSON 문자열이여야 함.
console.log(clusterMetrics.appsRunning);
}
});
</script>
❗완전한 JSON 문자열처리 유틸(mapToJson) 사용시
💡 이렇게 JS에서 사용 가능한 TO-BE 형태로 변한다.Map<String, Object> mapResult = new HashMap<String, Object>(); String resultData = BlangJsonUtil.mapToJson("[파싱한 Map객체]"); mapResult.put("clusterMetrics", resultData);
/* 출력결과 AS-IS */ {clusterMetrics={"appsSubmitted":1.0,"appsCompleted":25000.0}} /* 출력결과 TO-BE*/ {clusterInfo={"appsSubmitted":"1.0","appsCompleted":"25000.0"}}
(JSON) List, Map 객체 조작(4) 유틸리티로 생성한 JSON (n개처리)
✅ BlangJsonUtil.java
/*********************
* Cluster Resource API 요청 (분기처리)<br>
* 요청한 API 별로 <br>
* 이스케이프 처리하여 JSON 형태 데이터를 생성한다.<br>
* @return String 제이슨 형태 문자열
*********************/
public static String getYarnData(String api) {
switch (api) {
case "clusterMetrics":
return getYarnMetrics();
case "clusterInfo":
return getYarnInfo();
}
return null;
}
/*********************
* MAP객체를 JS가 인식할 수 있는 JSON 형태 문자열로 변경<br>
*
* @param mapJson - Map<String, Object> 타입
* @return String 완전한 JSON 형태의 문자열
*********************/
public static String mapToJson(Map<String, Object> mapJson) {
// JSON 문자열 구성
StringBuilder jsonStringBuilder = new StringBuilder();
jsonStringBuilder.append("{");
boolean firstEntry = true;
for (Map.Entry<String, Object> entry : mapJson.entrySet()) {
if (!firstEntry) {
jsonStringBuilder.append(",");
}
jsonStringBuilder.append("\"").append(entry.getKey()).append("\":");
Object value = entry.getValue();
if (value instanceof String) {
jsonStringBuilder.append("\"").append(value).append("\"");
} else if(value instanceof Double) {
// Gson 라이브러리의 키값이 int 형은 double 로 처리
jsonStringBuilder.append("\"").append(value).append("\"");
} else {
jsonStringBuilder.append(value);
}
firstEntry = false;
}
jsonStringBuilder.append("}");
String jsonString = jsonStringBuilder.toString();
System.out.println(jsonString);
return jsonString;
}
/*********************
* Cluster Metrics API 요청
*********************/
public static String getYarnMetrics() {
String strJsonStr = "{\"clusterMetrics\":{\"appsSubmitted\":1,\"appsCompleted\":25000,\"appsPending\":0\"appsRunning\":0,\"appsFailed\":1,\"appsKilled\":1,\"reservedMB\":0,\"availableMB\":17408\"allocatedMB\":0,\"reservedVirtualCores\":0,\"availableVirtualCores\":7,\"allocatedVirtualCores\":1\"containersAllocated\":0,\"containersReserved\":0,\"containersPending\":0,\"totalMB\":17408\"totalVirtualCores\":8,\"totalNodes\":1,\"lostNodes\":0,\"unhealthyNodes\":0,\"decommissioningNodes\":0\"decommissionedNodes\":0,\"rebootedNodes\":0,\"activeNodes\":1,\"shutdownNodes\":0}}";
return strJsonStr;
}
/*********************
* Cluster Info API 요청
*********************/
public static String getYarnInfo() {
String strJsonStr = "{\"clusterInfo\":{\"id\":1324053971963,\"startedOn\":1324053971963\"state\":\"STARTED\",\"haState\":\"ACTIVE\",\"rmStateStoreName\":\"org.apache.hadoop.yarn.serverresourcemanager.recovery.NullRMStateStore\",\"resourceManagerVersion\":\"3.0.0-SNAPSHOT\"\"resourceManagerBuildVersion\":\"3.0.0-SNAPSHOT from unknown by user1 source checksum11111111111111111111111111111111\",\"resourceManagerVersionBuiltOn\":\"2016-01-01T01:00Z\"\"hadoopVersion\":\"3.0.0-SNAPSHOT\",\"hadoopBuildVersion\":\"3.0.0-SNAPSHOT from unknown by user1 sourcechecksum 11111111111111111111111111111111\",\"hadoopVersionBuiltOn\":\"2016-01-01T01:00Z\"\"haZooKeeperConnectionState\":\"ResourceManager HA is not enabled.\"}}";
return strJsonStr;
}
✅HomeController.java
// 테스트 컨트롤러
@RequestMapping(value = "/test", method = RequestMethod.GET)
public String test(Model model) {
logger.info("HomeController test start >>");
java.lang.reflect.Type mapType = new com.google.gson.reflect.TypeToken<Map<String, Object>>(){}.getType();
Gson gson = new Gson();
Map<String, Object> mapResult = new HashMap<String, Object>();
// Yarn Resource Manager API ROOT KEY (이부분은 JSON에 맞게 하드코딩)
String yarnResource[] = {"clusterMetrics", "clusterInfo"};
// API ROOT KEY 횟수 루프
for(int i=0; i<yarnResource.length; i++) {
// STEP1. API 요청후 JSON 얻기
String getYarnJson = BlangJsonUtil.getYarnData(yarnResource[i]); // JSON 문자열
System.out.println("■ API요청으로 받은 JSON 형태의 String: "+ getYarnJson);
// STEP2. 얻은 JSON 키값의 데이터타입별로 GSON 라이브러리로 Map<String, Object> 동적처리.
Map<String, Object> mapJson = gson.fromJson(getYarnJson, mapType);
System.out.println("■ API요청으로 받은 JSON 형태의 String 데이터를 객체로 파싱: " + mapJson);
// STEP3. ROOT KEY ACCESS
Map<String, Object> accessData = (Map<String, Object>) mapJson.get(yarnResource[i]);
System.out.println("■ 파싱한 데이터에서 JSON KEY 엑세스: " + accessData);
// STEP4. JS가 인식가능한 완벽한 JSON 문자열 생성
if (accessData != null) {
String resultData = BlangJsonUtil.mapToJson(accessData); // 완벽한 JSON 만들기
mapResult.put(yarnResource[i], resultData); //API 별로 MAP생성
System.out.println("■ 엑세스한 JSON 데이터의 키,값을 완벽한 JSON 문자열로 변경 " + accessData);
}
}
// 키값은 Yarn Resource Manager REST API 문서 참고
model.addAttribute("mapResult", mapResult);
return "jsp/test/BDP002023M00";
}
<script>
$(document).ready(function (){
/* Yarn Resource Manager REST API */
let jsonMetrics = '${mapResult.clusterMetrics}';
let jsonInfo = '${mapResult.clusterInfo}';
if (jsonMetrics != null) {
clusterMetrics = JSON.parse(jsonMetrics); //함수 성공조건: 완벽한 JSON 문자열이여야 함.
console.log(clusterMetrics.appsRunning);
}
if (jsonInfo != null) {
clusterInfo = JSON.parse(jsonInfo); //함수 성공조건: 완벽한 JSON 문자열이여야 함.
console.log(clusterInfo.state);
}
});
</script>
❗완전한 JSON 문자열처리 유틸(mapToJson) 사용시
💡 이렇게 JS에서 사용 가능한 TO-BE 형태로 변한다.Map<String, Object> mapResult = new HashMap<String, Object>(); String resultData = BlangJsonUtil.mapToJson("[파싱한 Map객체]"); mapResult.put("clusterMetrics", resultData);
/* 출력결과 AS-IS */ {clusterMetrics={"appsSubmitted":1.0,"appsCompleted":25000.0}} /* 출력결과 TO-BE*/ {clusterInfo={"appsSubmitted":"1.0","appsCompleted":"25000.0"}}
Leave a comment