class ClassName {
    private int a;    
// 클래스 초기화 블록
    static {
        a = 10;
    }
     // 인스턴스 초기화 블록
    {
        a = 10;
     }

}

* 장점
1. 맴버변수 초기화는 보통 생성자에서 하므로 생성자 오버로딩하여 사용하는 경우 생성자마다 초기화 코드가 들어가야한다.
    static block으로 묶어주는 경우 컴파일 시점에 한번 초기화되어 중복코드를 방지할 수 있다.

2. 하나의 클래스로 여러개의 인스턴스가 동시에 실행되는 경우 유용하다.
    공통적으로 사용하는 변수를 static영역에 넣으므로 1회만 초기화되어도 여러 인스턴스에서 사용이 가능하다.
    
공통적으로 사용하는 변수의 초기화는 static { } 으로 묶어주는 것이 좋다.

'JAVA' 카테고리의 다른 글

HttpURLConnection으로 POST / GET 연습  (0) 2022.10.11
JAVA / JSON 연습  (0) 2022.09.18
AES 암호화 & BASE64 인코딩  (0) 2022.09.04
BufferedInputStream  (0) 2022.08.28
BigDecimal  (0) 2022.08.28

https://webhook.site/

 

Webhook.site - Test, process and transform emails and HTTP requests

This URL received over {{ appConfig.MaxRequests }} requests and can't accept more webhooks. New requests sent to this URL will return HTTP status code 410 Gone or 429 Too Many Requests and won't be logged. Also note that it is against our terms of service

webhook.site

조만간 정리

'JAVA' 카테고리의 다른 글

Static { } (Static 블록화)  (0) 2022.11.03
JAVA / JSON 연습  (0) 2022.09.18
AES 암호화 & BASE64 인코딩  (0) 2022.09.04
BufferedInputStream  (0) 2022.08.28
BigDecimal  (0) 2022.08.28

지금까지 회사다니며 매일 화면만 만지작 거렸는데

드디어 타 회사와 연계할 API를 만들일이 생기게 되었다.

지난번 API 개발에서 사용할 AES/BASE64 에 대해서는 정리하였는데 

JSON에 대해서는 정리하지 않아 이번 기회에 정리한다.

 

 

1. JAVE에서 JSON 사용하기.

먼저 JAVA에서 JSON을 사용하려면 JSON관련 jar를 추가해야한다. 

아래의 링크에서 jar를 다운받자. 

※ json_simple-1.0.x 을 사용하면 ParseException 이 없는 것 같다. 왠만하면 1.1.x 이상 버전을 사용하자.

https://code.google.com/archive/p/json-simple/downloads

 

Google Code Archive - Long-term storage for Google Code Project Hosting.

 

code.google.com

다운로드 후 Build Path를 지정해주자.

잘 적용이 되었다면 아래의 클래스들을 사용할 수 있다.

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

 

2. JSON 데이터 만들기

먼저 JSON을 만드는 연습부터 해보자.

만들고자 하는 데이터는 다음과 같다.

"rec_data" : {
	  "store_no" : "12345"
	, "store_nm" : "카페알리"
	, "search_dt" : "20220917"
	, "tran_cnt" : "4"
	, "tran_data" : 
	[
		{ 
		    "tran_dt" : "20220917"
		  , "tran_tm" : "135959"
		  , "tr_div" : "0"
		  , "tr_amt" : 3500
		  , "cust_nm" : "홍길동"
		}, 
		{ 
		    "tran_dt" : "20220917"
		  , "tran_tm" : "140101"
		  , "tr_div" : "0"
		  , "tr_amt" : 13500
		  , "cust_nm" : "고길동"
		}, 
		{ 
		    "tran_dt" : "20220917"
		  , "tran_tm" : "153131"
		  , "tr_div" : "0"
		  , "tr_amt" : 23500
		  , "cust_nm" : "김길동"
		}, 
		{ 
		    "tran_dt" : "20220917"
		  , "tran_tm" : "163123"
		  , "tr_div" : "0"
		  , "tr_amt" : 53500
		  , "cust_nm" : "오길동"
		}, 
	]
}

간단히 보면 { "data":"data" ... "array" : [ { ... }, { ... }, { ... }, { ... } ] } 형태이다.

 

JSON 데이터를 만들때는 최하위 -> 최상위 순서로 만든다.

즉, 예시의 데이터를 만드는 순서는 다음과 같다.

  • 가장 안쪽의 { ... } Object 생성
  • { ... } Object를  "tran_data" Array에 넣는다.
  • 최상위의 "rec_data" Object 에 들어가는 "data" : "data" 를 넣는다.
  • "rec_data"에 "tran_data" Array 를 넣는다.
package com.stream.study;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

public class JsonMakeData {
	
	public JSONObject MakeJsonData() {
		
		// 최하위의 데이터를 생성한다.
		JSONObject jsonData1 = new JSONObject();
		JSONObject jsonData2 = new JSONObject();
		JSONObject jsonData3 = new JSONObject();
		JSONObject jsonData4 = new JSONObject();

		jsonData1.put("tran_dt", "20220917");
		jsonData1.put("tran_tm", "135959");
		jsonData1.put("tr_div", "0");
		jsonData1.put("tr_amt", 3500);
		jsonData1.put("cust_nm", "홍길동");
		
		jsonData2.put("tran_dt", "20220917");
		jsonData2.put("tran_tm", "140101");
		jsonData2.put("tr_div", "0");
		jsonData2.put("tr_amt", 13500);
		jsonData2.put("cust_nm", "고길동");
		
		jsonData3.put("tran_dt", "20220917");
		jsonData3.put("tran_tm", "153131");
		jsonData3.put("tr_div", "0");
		jsonData3.put("tr_amt", 23500);
		jsonData3.put("cust_nm", "김길동");
		
		jsonData4.put("tran_dt", "20220917");
		jsonData4.put("tran_tm", "162322");
		jsonData4.put("tr_div", "0");
		jsonData4.put("tr_amt", 53500);
		jsonData4.put("cust_nm", "박길동");
		
		// 최하위 데이터 출력
		System.out.println("jsonData1 :: " + jsonData1.toString());
		System.out.println("jsonData2 :: " + jsonData2.toString());
		System.out.println("jsonData3 :: " + jsonData3.toString());
		System.out.println("jsonData4 :: " + jsonData4.toString());


		// 최하위 데이터를 배열로 묶음
		JSONArray tran_data = new JSONArray();
		
		tran_data.add(jsonData1);
		tran_data.add(jsonData2);
		tran_data.add(jsonData3);
		tran_data.add(jsonData4);
		
		// 배열 출력
		System.out.println("tran_data :: " + tran_data.toString());
		
		// 최상위의 객체 생성 후 데이터 입력
		JSONObject rec_data = new JSONObject();
		
		rec_data.put("store_no", "12345");
		rec_data.put("store_nm", "카페알리");
		rec_data.put("search_dt", "20220917");
		rec_data.put("tran_cnt", String.valueOf(tran_data.size()));
		
		// 최상위 객체에 배열을 넣음
		rec_data.put("tran_data", tran_data);
	
		// 최종 확인
		System.out.println("rec_data :: " + rec_data.toString());
		
		return rec_data;
	}
}

/* 실행결과
jsonData1 :: {"tran_dt":"20220917","cust_nm":"홍길동","tr_amt":3500,"tr_div":"0","tran_tm":"135959"}
jsonData2 :: {"tran_dt":"20220917","cust_nm":"고길동","tr_amt":13500,"tr_div":"0","tran_tm":"140101"}
jsonData3 :: {"tran_dt":"20220917","cust_nm":"김길동","tr_amt":23500,"tr_div":"0","tran_tm":"153131"}
jsonData4 :: {"tran_dt":"20220917","cust_nm":"박길동","tr_amt":53500,"tr_div":"0","tran_tm":"162322"}
tran_data :: [{"tran_dt":"20220917","cust_nm":"홍길동","tr_amt":3500,"tr_div":"0","tran_tm":"135959"},{"tran_dt":"20220917","cust_nm":"고길동","tr_amt":13500,"tr_div":"0","tran_tm":"140101"},{"tran_dt":"20220917","cust_nm":"김길동","tr_amt":23500,"tr_div":"0","tran_tm":"153131"},{"tran_dt":"20220917","cust_nm":"박길동","tr_amt":53500,"tr_div":"0","tran_tm":"162322"}]
rec_data :: {"store_nm":"카페알리","store_no":"12345","search_dt":"20220917","tran_cnt":"4","tran_data":[{"tran_dt":"20220917","cust_nm":"홍길동","tr_amt":3500,"tr_div":"0","tran_tm":"135959"},{"tran_dt":"20220917","cust_nm":"고길동","tr_amt":13500,"tr_div":"0","tran_tm":"140101"},{"tran_dt":"20220917","cust_nm":"김길동","tr_amt":23500,"tr_div":"0","tran_tm":"153131"},{"tran_dt":"20220917","cust_nm":"박길동","tr_amt":53500,"tr_div":"0","tran_tm":"162322"}]}
{"store_nm":"카페알리","store_no":"12345","search_dt":"20220917","tran_cnt":"4","tran_data":[{"tran_dt":"20220917","cust_nm":"홍길동","tr_amt":3500,"tr_div":"0","tran_tm":"135959"},{"tran_dt":"20220917","cust_nm":"고길동","tr_amt":13500,"tr_div":"0","tran_tm":"140101"},{"tran_dt":"20220917","cust_nm":"김길동","tr_amt":23500,"tr_div":"0","tran_tm":"153131"},{"tran_dt":"20220917","cust_nm":"박길동","tr_amt":53500,"tr_div":"0","tran_tm":"162322"}]}
*/

 

3. JSON 데이터 읽기

이번엔 생성한 데이터에 접근해서 읽어보자

이번엔 JSON데이터 생성과 반대로 최상위 -> 최하위로 접근한다.

package com.stream.study;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

public class JsonParsingData {


	// 생성한 JSON 데이터를 매개변수로 받는다.
	public void JsonDataParser_JSON(JSONObject jsonOrgData) {
		
	    System.out.println("======== PARSE JSON START ========");

        JSONObject jsonObject = jsonOrgData;
        
        // 받아 온 데이터 확인
        System.out.println("jsonObject :: " + jsonObject.toString());

        // 배열에 접근하기 위해 데이터를 JSONArray로 변환
        JSONArray tran_data = (JSONArray) jsonObject.get("tran_data");
        
        // 배열 확인
        System.out.println("tran_data :: " + tran_data.toString());

        // 배열을 순차적으로 탐색
        for(int i = 0; i < tran_data.size(); i++) {
        	
        	// 배열의 INDEX 별로 JsonObject 로 변환
        	JSONObject tran_data_arr = (JSONObject) tran_data.get(i);
        	
        	// JsonObject의 각 데이터를 파싱
        	String 	tran_dt 	= (String) 	tran_data_arr.get("tran_dt");
        	String 	tran_tm 	= (String) 	tran_data_arr.get("tran_tm");
        	String 	tr_div 		= (String) 	tran_data_arr.get("tr_div");
        	int 	tr_amt 		= (Integer) tran_data_arr.get("tr_amt");
        	String 	cust_nm 	= (String) 	tran_data_arr.get("cust_nm");
        	
        	// 데이터 출력
        	System.out.println("====== tran_data[" + i + "] ======");
        	System.out.println("tran_dt :: " + tran_dt);
        	System.out.println("tran_tm :: " + tran_tm);
        	System.out.println("tr_div 	:: " + tr_div);
        	System.out.println("tr_amt 	:: " + tr_amt);
        	System.out.println("cust_nm :: " + cust_nm);
        	
        	
        	System.out.println("======== PARSE JSON END ========");

    }
  }
}
    
/* 실행결과
======== PARSE JSON START ========
jsonObject :: {"store_nm":"카페알리","store_no":"12345","search_dt":"20220917","tran_cnt":"4","tran_data":[{"tran_dt":"20220917","cust_nm":"홍길동","tr_amt":3500,"tr_div":"0","tran_tm":"135959"},{"tran_dt":"20220917","cust_nm":"고길동","tr_amt":13500,"tr_div":"0","tran_tm":"140101"},{"tran_dt":"20220917","cust_nm":"김길동","tr_amt":23500,"tr_div":"0","tran_tm":"153131"},{"tran_dt":"20220917","cust_nm":"박길동","tr_amt":53500,"tr_div":"0","tran_tm":"162322"}]}
tran_data :: [{"tran_dt":"20220917","cust_nm":"홍길동","tr_amt":3500,"tr_div":"0","tran_tm":"135959"},{"tran_dt":"20220917","cust_nm":"고길동","tr_amt":13500,"tr_div":"0","tran_tm":"140101"},{"tran_dt":"20220917","cust_nm":"김길동","tr_amt":23500,"tr_div":"0","tran_tm":"153131"},{"tran_dt":"20220917","cust_nm":"박길동","tr_amt":53500,"tr_div":"0","tran_tm":"162322"}]
====== tran_data[0] ======
tran_dt :: 20220917
tran_tm :: 135959
tr_div 	:: 0
tr_amt 	:: 3500
cust_nm :: 홍길동
======== PARSE JSON END ========
====== tran_data[1] ======
tran_dt :: 20220917
tran_tm :: 140101
tr_div 	:: 0
tr_amt 	:: 13500
cust_nm :: 고길동
======== PARSE JSON END ========
====== tran_data[2] ======
tran_dt :: 20220917
tran_tm :: 153131
tr_div 	:: 0
tr_amt 	:: 23500
cust_nm :: 김길동
======== PARSE JSON END ========
*/

 

4. JSON 데이터를 문자열로 받은 후 파싱

생성된 데이터를 프로젝트 내부적으로 처리하는 것이 아니라면  JSON형태 그대로 주고 받는 경우는 없을 것이다.

대부분이 JSON데이터를 단순히 문자열 형태로 줄테니 문자열을 JSON으로 변환하여 사용하는 연습도 해보자.

package com.stream.study;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

public class JsonParsingData {


	// 생성한 JSON 데이터를 매개변수로 받는다.
	public void JsonDataParser_JSON(JSONObject jsonOrgData) {
		
		System.out.println("======== PARSE JSON START ========");

        JSONObject jsonObject = jsonOrgData;
        
        // 받아 온 데이터 확인
        System.out.println("jsonObject :: " + jsonObject.toString());

        // 배열에 접근하기 위해 데이터를 JSONArray로 변환
        JSONArray tran_data = (JSONArray) jsonObject.get("tran_data");
        
        // 배열 확인
        System.out.println("tran_data :: " + tran_data.toString());

        // 배열을 순차적으로 탐색
        for(int i = 0; i < tran_data.size(); i++) {
        	
        	// 배열의 INDEX 별로 JsonObject 로 변환
        	JSONObject tran_data_arr = (JSONObject) tran_data.get(i);
        	
        	// JsonObject의 각 데이터를 파싱
        	String 	tran_dt 	= (String) 	tran_data_arr.get("tran_dt");
        	String 	tran_tm 	= (String) 	tran_data_arr.get("tran_tm");
        	String 	tr_div 		= (String) 	tran_data_arr.get("tr_div");
        	int 	tr_amt 		= (Integer) tran_data_arr.get("tr_amt");
        	String 	cust_nm 	= (String) 	tran_data_arr.get("cust_nm");
        	
        	// 데이터 출력
        	System.out.println("====== tran_data[" + i + "] ======");
        	System.out.println("tran_dt :: " + tran_dt);
        	System.out.println("tran_tm :: " + tran_tm);
        	System.out.println("tr_div 	:: " + tr_div);
        	System.out.println("tr_amt 	:: " + tr_amt);
        	System.out.println("cust_nm :: " + cust_nm);
        	
        	
        	System.out.println("======== PARSE JSON END ========");

        }
	}
	
	// JSON 데이터 문자열을 매개변수로 받는다
	public void JsonDataParser_String(String jsonOrgData_String) {

		System.out.println("======== PARSE STRING START ========");
		
		// String 출력
		System.out.println(jsonOrgData_String);
		
		// 문자열 -> JSONObject로 변환하기 위해 JSONParser를 생성
		JSONParser jsonParser = new JSONParser();
		
		// Parse를 하면 try-catch 감싸주어야 함.
		try {
			
			// parse()의 반환형이 Object 이므로 JSONObject형으로 변환
			JSONObject rec_data = (JSONObject) jsonParser.parse(jsonOrgData_String);
			
			// rec_data의 배열에 접근하기 위해 tran_data를 JSONArray로 변환
			JSONArray tran_data = (JSONArray) rec_data.get("tran_data");
	        
	        System.out.println("tran_data :: " + tran_data.toString());

	        for(int i = 0; i < tran_data.size(); i++) {
	        	//System.out.println("tran_data[" + i + "] :: " + tran_data.get(i).toString());
	        	
	        	JSONObject tran_data_arr = (JSONObject) tran_data.get(i);
	        	
	        	String 	tran_dt 	= (String) 	tran_data_arr.get("tran_dt");
	        	String 	tran_tm 	= (String) 	tran_data_arr.get("tran_tm");
	        	String 	tr_div	 	= (String) 	tran_data_arr.get("tr_div");
	        	
	        	// JSON에서 숫자의 기본 타입은 Long으로 지정되므로 Integer를 쓰면 에러
	        	Long 	tr_amt 		= (Long)	tran_data_arr.get("tr_amt");
	        	String 	cust_nm 	= (String) 	tran_data_arr.get("cust_nm");
	        	
	        	System.out.println("====== tran_data[" + i + "] ======");
	        	System.out.println("tran_dt :: " + tran_dt);
	        	System.out.println("tran_tm :: " + tran_tm);
	        	System.out.println("tr_div 	:: " + tr_div);
	        	System.out.println("tr_amt 	:: " + tr_amt);
	        	System.out.println("cust_nm :: " + cust_nm);

	        }
			
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		System.out.println("======== PARSE STRING END ========");
		
	}
}

/* 실행결과
======== PARSE STRING START ========
{"store_nm":"카페알리","store_no":"12345","search_dt":"20220917","tran_cnt":"4","tran_data":[{"tran_dt":"20220917","cust_nm":"홍길동","tr_amt":3500,"tr_div":"0","tran_tm":"135959"},{"tran_dt":"20220917","cust_nm":"고길동","tr_amt":13500,"tr_div":"0","tran_tm":"140101"},{"tran_dt":"20220917","cust_nm":"김길동","tr_amt":23500,"tr_div":"0","tran_tm":"153131"},{"tran_dt":"20220917","cust_nm":"박길동","tr_amt":53500,"tr_div":"0","tran_tm":"162322"}]}
tran_data :: [{"tran_dt":"20220917","cust_nm":"홍길동","tr_amt":3500,"tr_div":"0","tran_tm":"135959"},{"tran_dt":"20220917","cust_nm":"고길동","tr_amt":13500,"tr_div":"0","tran_tm":"140101"},{"tran_dt":"20220917","cust_nm":"김길동","tr_amt":23500,"tr_div":"0","tran_tm":"153131"},{"tran_dt":"20220917","cust_nm":"박길동","tr_amt":53500,"tr_div":"0","tran_tm":"162322"}]
====== tran_data[0] ======
tran_dt :: 20220917
tran_tm :: 135959
tr_div 	:: 0
tr_amt 	:: 3500
cust_nm :: 홍길동
====== tran_data[1] ======
tran_dt :: 20220917
tran_tm :: 140101
tr_div 	:: 0
tr_amt 	:: 13500
cust_nm :: 고길동
====== tran_data[2] ======
tran_dt :: 20220917
tran_tm :: 153131
tr_div 	:: 0
tr_amt 	:: 23500
cust_nm :: 김길동
====== tran_data[3] ======
tran_dt :: 20220917
tran_tm :: 162322
tr_div 	:: 0
tr_amt 	:: 53500
cust_nm :: 박길동
======== PARSE STRING END ========
*/

 

※ 위의 코드를 실행하기 위한 main() 

package com.stream.study;
import org.json.simple.JSONObject;
	
public class JsonParsingTest {
	
	public static void main(String[] args) {
		
		JsonMakeData 	jsonMakeData 	= new JsonMakeData();
		JsonParsingData jsonParsingData = new JsonParsingData();
		
		
		JSONObject jsonData = new JSONObject();
		
		jsonData = jsonMakeData.MakeJsonData();
		
		System.out.println(jsonData.toString());
		
		jsonParsingData.JsonDataParser_JSON(jsonData);
		jsonParsingData.JsonDataParser_String(jsonData.toString());
		
	}
}

'JAVA' 카테고리의 다른 글

Static { } (Static 블록화)  (0) 2022.11.03
HttpURLConnection으로 POST / GET 연습  (0) 2022.10.11
AES 암호화 & BASE64 인코딩  (0) 2022.09.04
BufferedInputStream  (0) 2022.08.28
BigDecimal  (0) 2022.08.28

REST API를 통해 카드 결제 등의 사용자 정보를 요청/응답하는 경우가 빈번해지며

데이터를 암호화하는 과정이 많아져 이번 기회에 알고리즘에 대한 설명보다는

사용하는 방법에 초점을 맞춰 정리를 하고자 한다.

 

1. AES (Advanced Encryptrion Standard) 암호화

현재 널리 쓰이는 암호화 방식 중 미국 표준기구(NIST)에서 만든 AES 방식을 사용하기로 한다.

AES 방식은 타 알고리즘에 비해 보편적이며 효과적인 방식이다.

이에 한국에서도 AES와 비슷하게 만든 SEED 암호화를 사용하며, 방식 또한 매우 유사하다.

AES 암호화는 대칭키를 사용한다. 즉, 암/복호화를 하는 대상이 동일한 키를 가지고 있어야 한다.

이 키는 암/복호화에 핵심적인 요소이므로 반드시 노출되어서는 안되기에 비밀키로 불린다.

 

AES는 비밀키의 크기에 따라 다르게 분류된다.

  • AES - 128 :: 16Byte 비밀키 사용 (10라운드)
  • AES - 192 :: 24Byte 비밀키 사용 (12라운드)
  • AES - 256 :: 32Byte 비밀키 사용 (14라운드)

당연히 비밀키의 크기가 클 수록 더욱 안전한 보안이 가능하다.

현재 가장 보편적으로 사용하는 암호화답게 JAVA진영에서도 표준으로 채용하여

javax.crypto 에 정의되어있다. 

  • javax.crypto.spec.SecretKeySpec
  • javax.crypto.spec.IvParameterSpec
  • javax.crypto.Cipher

 

2. BASE64 인코딩

간단히 말하자면 Binary 데이터를 ASCII 형태의 Text로 변환해주는 인코딩 방식이다.

국제 표준과 같이 사용되는 ASCII로 변환하는 경우 아래와 같은 장점이 있다.

  • 데이터를 송/수신할 때 상대방의 Character Set을 신경쓸 필요가 없다.
  • HTML/CSS에서 Binary로 전달되는 미디어 정보를 깨짐없이 전달이 가능하다.

BASE64가 인코딩 하는 방식은 생각보다 단순하다.

Binary 데이터를 6자리씩 자른 후 64진법 (2^6 = 64) 으로 변환한다.

그 후 아래의 표를 참조하여 Text 데이터로 변환한다.

디코딩의 경우로 위의 표대로 Text -> Binary 로 변환할 수 있으므로 Charater Set에 대한 영향을 받지 않는다.

이러한 장점 덕분에 REST를 사용한 API개발에서도 BASE64 인코딩 방식을 널리 사용하고 있다.

 

BASE64 인코딩은 Apache 재단에서 제공해주며 별도 라이브러리를 추가해야 한다.

메이븐 레파지토리에서 쉽게 구할 수 있다.

 

https://mvnrepository.com/artifact/commons-codec/commons-codec

 

 

3. 사용 방법

암호화 하는 과정은 단순하다.

 

# 송신측

  • 데이터를 비밀키를 이용하여 암호화 
  • 암호화된 데이터를 BASE64 인코딩

#수신측

  • 수신한 데이터를 BASE64 디코딩
  • 데이터를 비밀키를 이용하여 복호화

암호화를 하는 과정은 구체적으로 AES/CBC/PKCS5Padding 방식을 사용한다.

  • CBC(Cipher-Block Chaining)
    - 블록 암호화의 대표적 방식
  • PKCS5Padding
    - 블록 암호화를 위해 데이터를 특정 크기로 맞추는 방법으로 8Byte 단위로 블록화하며 빈공간이 발생하는 경우
      의미없는 문자로 채움.
  • IV(Initialization Vector)
    - CBC 방식은 데이터를 분할한 블록끼리 XOR 연산을 하는데 첫 블록은 XOR연산을 수행할 블록이 없으므로
       IV를 사용하여 첫 블록을 연산한다.
    - IV값은 비밀키와 함께 송/수신자가 동일하게 맞춰야 한다. IV가 비밀키와 다른 경우 외부에 공개되어도 상관없다.
    - IV는 두 번째 키로도 사용되기에 비밀키와 동일한 크기로 맞춰야 한다.

 

AES에 대한 방식이 이해되었다면 아래의 코드를 분석하여 적용하는 것에 큰 무리가 없을 것이다.

// 암호화 
public static String encrypte(String msg, String enc_key) throws Exception {
		byte[] bKey = enc_key.getBytes();
		
        // IV 생성
        IvParameterSpec ivParameterSpec = new IvParameterSpec(bKey);
		
        // 비밀키 생성
		SecretKey secretKey = new SecretKeySpec(bKey, "AES");
		
        // 암호화방식 지정 : AES/CBC/PKCS5Padding
		Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
		
		byte[] encrypted = cipher.doFinal(msg.getBytes("UTF-8"));
		
        // 암호화된 데이터를 BASE64 인코딩 
        String enc_data = new String(Base64.encodeBase64(encrypted));
		return enc_data;
	}

// 복호화
public static String decrypt(String msg, String enc_key) throws Exception{
		byte[] bKey = enc_key.getBytes();
		
        // IV 생성
		IvParameterSpec ivParameterSpec = new IvParameterSpec(bKey);
		
        // 비밀키 생성
		SecretKey secretKey = new SecretKeySpec(bKey, "AES");
		
        // 복호화방식 지정 : 암호화 방식과 동일
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
		cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
		
        // BASE64 디코딩
		byte[] decrypted = Base64.decodeBase64(msg.getBytes());
		
        // 디코딩된 데이터를 복호화
		return new String(cipher.doFinal(decrypted), "UTF-8");
    }

'JAVA' 카테고리의 다른 글

HttpURLConnection으로 POST / GET 연습  (0) 2022.10.11
JAVA / JSON 연습  (0) 2022.09.18
BufferedInputStream  (0) 2022.08.28
BigDecimal  (0) 2022.08.28
제너릭  (0) 2022.08.28

 

파일을 Byte단위로 읽어 올때 유용한 버퍼 스트림

직접 코드를 읽어 파일에 접속하는 것이 아닌,

 

8192바이트의 버퍼를 이용하여 읽어와서 훨씬 빠름.

 

BufferedInputStream br = new BufferedInputStream(isr);

 

https://hey79.tistory.com/55

이미지 썸네일 삭제
자바 BufferedInputStream [북붙따라하기]

BufferedInputStream  : byte단위로 파일을 읽어 올때 사용하는 버퍼 스트림 입니다. 사용 예제 ) 코드를 복붙 하여 실행해 보시기 바랍니다. 설명은 주석과 코드 아랫부분에 있습니다. import java.io.Buffere..

hey79.tistory.com

 

'JAVA' 카테고리의 다른 글

JAVA / JSON 연습  (0) 2022.09.18
AES 암호화 & BASE64 인코딩  (0) 2022.09.04
BigDecimal  (0) 2022.08.28
제너릭  (0) 2022.08.28
Wrapper 클래스  (0) 2022.08.28

 

소수점을 취급할 때 대부분의 프로그래밍 언어에서 지원해주는 Float, Double 를 보통 많이 사용하였다.

평범하게 사용한다면 소수점 아래의 수는 워낙 작아 큰 문제가 없었지만, 돈과 관련된 데이터를 취급하는 과정에서

0.001 정도의 오차로 인해 큰 문제가 생길 뻔 했다.

 

BigDecimal은 현재 자바 내에서 유리수를 표현하는 가장 정밀한 방법이다.

Float와 Double을 연산하게 된다면 부동소수점의 문제로 약간의 오차가 발생하는데

단 1원의 차이도 용납 안되는 금융 데이터에서는 반드시 BigDecimal 을 사용하여야 한다.

 

1. BigDecimal 초기화 및 상수

초기화는 생성자를 통한 초기화로 가능하다.

초기화할 경우 주의할 점은 파라미터로 Double Type 값을 넘겨 줄 경우 아래와 같이 문제가 발생한다.

5.01 로 초기화를 원했으나 5.00999999... 으로 나오게 된다.

Double 타입 값은 2진수로 변환되어 표현할 값과 가장 근사치로 계산되어 오차가 발생한다.

(BigDecimal은 10진수로 계산되어 가장 정확한 값을 나타낼 수 있다.)

이를 막기 위해서는 String Type 으로 파라미터를 전달하면 된다.

 

BigDecimal 에서 제공하는 기본 상수를 활용( ZERO, ONE, TEN )이 가능하다.

import java.math.BigDecimal;

public class BigDecimalTest {


	public static void main(String[] args) {
		
		BigDecimal bigInit1 = new BigDecimal(5);
		BigDecimal bigInit2 = new BigDecimal(5.01);
		BigDecimal bigInit3 = new BigDecimal("5.0");
		
		// 초기화
		System.out.println("Constructor Init : " + bigInit1);
		
		System.out.println("Double Type Construct : " + bigInit2);
		
		System.out.println("String Type Construct : " + bigInit3);
		
		// 상수
		bigInit1 = BigDecimal.ZERO;
		System.out.println("Zero Const : " + bigInit1);
		
		bigInit1 = BigDecimal.ONE;
		System.out.println("ONE Const: " + bigInit1);
		
		bigInit1 = BigDecimal.TEN;
		System.out.println("TEN Const: " + bigInit1);
	}
}
 
 

2. BigDecimal 사칙 연산

BigDecimal로 사칙연산은 메소드 호출 방식으로 이루어진다.

사용하는 메소드는 다음과 같다.

ADD , SUBTRACT, MULTIPLY, DIVIDE

import java.math.BigDecimal;

public class BigDecimalTest {
	public static void main(String[] args) {
		
		BigDecimal bigInit1 = new BigDecimal(5.0);
		BigDecimal bigInit2 = new BigDecimal(5.01);
		BigDecimal bigInit3 = new BigDecimal("5.001");
		
		// 덧셈
		System.out.println("ADD : " + bigInit1.add(bigInit3));
		// 뺄셈
		System.out.println("SUBTRACT : " + bigInit1.subtract(bigInit3));
		// 곱셈
		System.out.println("MULTIPLY : " + bigInit1.multiply(bigInit3));
		// 나눗셈 (5.001 / 5)
		System.out.println("DIVIDE : " + bigInit3.divide(bigInit1));
		// 나눗셈 (5 / 5.001)
		System.out.println("DIVIDE : " + bigInit1.divide(bigInit3));

	}
}
 

정수와 유리수의 나눗셈의 경우 연산자, 피연산자에 따라서 표현식 오류가 발생할 수 있다.

 

3. BigDecimal 비교 연산자

import java.math.BigDecimal;

public class BigDecimalTest {

	public static void main(String[] args) {
		
		BigDecimal bigInit1 = new BigDecimal(5.0);
		BigDecimal bigInit2 = new BigDecimal(5);
		BigDecimal bigInit3 = new BigDecimal("5.001");
		
		// Equals
		System.out.println("Equals : " + bigInit1.equals(bigInit2));

		// compareTo 1
		System.out.println("CompareTo : " + bigInit1.compareTo(bigInit2));
		
		// compareTo 2
		System.out.println("CompareTo : " + bigInit2.compareTo(bigInit3));
		
		// compareTo 3
		System.out.println("CompareTo : " + bigInit3.compareTo(bigInit2));
		
		// Max
		System.out.println("Max : " + bigInit1.max(bigInit3));
		
		// Min
		System.out.println("Min: " + bigInit1.min(bigInit3));
		
	}
}
 

동일 여부 확인은 BigDecimal 객체를 비교하므로 eqauls 로 비교한다.

CompareTo 의 경우 연산자와 피연산자 비교하여 같으면 0 작으면 -1 크면 1을 반환한다.

 

더 자세한 사항은 아래 블로그를 참고

https://jsonobject.tistory.com/466

이미지 썸네일 삭제
Java, BigDecimal 사용법 정리

BigDecimal? BigDecimal은 Java 언어에서 숫자를 정밀하게 저장하고 표현할 수 있는 유일한 방법이다. 소수점을 저장할 수 있는 가장 크기가 큰 타입인 double은 소수점의 정밀도에 있어 한계가 있어 값이 유실될..

jsonobject.tistory.com

 

'JAVA' 카테고리의 다른 글

AES 암호화 & BASE64 인코딩  (0) 2022.09.04
BufferedInputStream  (0) 2022.08.28
제너릭  (0) 2022.08.28
Wrapper 클래스  (0) 2022.08.28
StringBuffer  (0) 2022.08.28

+ Recent posts