19 minute read

기본적인 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 의 데이터를 뽑기 위해서

    1. JSONArray ==> Object 변환
    1. Object ==> JSONObject 변환
    1. 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은 해당 값을 문자열로 변환하여 매핑.

명확하게 느낀 내용
💡 자동으로 데이터 타입 변환을 처리해주므로 별도의 형변환 작업을 수동으로 할 필요가 없는점이다. 아래 작업을 안해도 된다.

  1. 선택한 JSONArray 의 데이터를 뽑기 위해서
  2. JSONArray ==> Object 변환
  3. Object ==> JSONObject 변환
  4. 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 답변

  1. JSP 문법 오류: JSP 코드 내에서 ${}로 값을 가져오는 부분에 문법적인 오류가 있는지 확인해야 합니다. <% %> 스크립트릿과 EL 표현식을 혼합해서 사용하면 문제가 발생할 수 있습니다.
    • ❌ 해당되지 않는다. System.out.println(“etc: “ + etc); 출력되었기에..
  2. etc 변수가 null이거나 값이 없는 경우: ${etc}로 값을 출력하려면 etc 변수가 올바르게 값을 가지고 있어야 합니다. System.out.println(“etc: “ + etc);가 출력되어도, 변수 값이 null이거나 비어있다면 출력되지 않을 수 있습니다.
    • ❌ 해당되지 않는다. String etc 정의가 되었으니까 출력되었겠지.
  3. 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"}}
 

Tags:

Categories:

Updated:

Leave a comment