8 minute read

JSON 핸들링

JSON 형태 예제1 (document)

{
    "documnet": [
        {
            "msg": "성공",
            "result": [
                "data1",
                "data2"
            ],
            "address": [
                {
                    "data2": "데이터2의 값 홍길동주소",
                    "data1": "데이터1의 값 홍길동"
                },
                {
                    "data2": "데이터2의 값 박명수주소",
                    "data1": "데이터1의 값 박명수"
                }
            ],
            "language": [
                {
                    "언어": "일본어",
                    "언어2": "카타카나",
                    "언어1": "히라가나"
                },
                {
                    "언어": "중국어",
                    "언어2": "번체",
                    "언어1": "간체"
                }
            ],
            "status": 200
        }
    ],
    "etc": {
        "name": "기타"
    }
}

JSON 형태 예제2 (clusterMetrics)

{
    "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
    }
}

(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"}}
 

Leave a comment