React 로 공부를 하던 중 갑자기 오류가 발생되었다.

 

  Delete `CR` prettier/prettier 

 

해당 오류는 '줄 시퀀스의 끝문자' 이 어떻게 셋팅되어 있느냐 문제이다. 

이전에 개발 시에는 문제가 없었는데, 남들 다 한다는 eslint & prettier 을 설치 후 문제가 발생되었다. 

 

아래는 문제의 오류 화면이다. 

브라우저 오류화면
소스코드 내 오류화면

 

문제의 원인은 EsLint 와 Prettier 이다. 

 

때문에 ESLint 또는 Prettier 에 '줄 시퀀스 끝문자' 에 대한 규칙을 추가해주자. 

 

eslint 의 설정 파일인 .eslintrc.js 또는 .eslint.json 파일을 열고 rules 에 endOfLine: 'auto' 를 추가해주자.

eslintrc.js 에 rule 추가

만약 eslint를 사용하지 않고 prettier 만 사용한다면 .prettierrc.js 파일을 열고 동일하게

endOfLine: 'auto' 를 추가한다. 

.prettierrc.js 파일

 

 

우선 자신의 PC 또는 서버에서 돌아가는 React 버전을 확인해보자

이유는 React 버전에 따라 Deprecate 된 함수가 있기 때문이다. 

 

- React 프로젝트에서 확인 : {React.version} 

- 터미널에서 확인 :   yarn info react    ( 단, yarn 이 설치되어 있어야 한다. )

  * 터미널에서 yarn 확인 시 훨씬 (압도적으로) 많은 정보가 나온다.   

 

터미널에서 react 버전 확인

 

가장 좋은것은 React 홈페이지의 공식 문서를 보는것이다. 

기술적인 문서는 상당수가 영문만 지원되는 경우가 많지만, React 는 한글도 아주 풍부하게 제공하고 있다. 

 

'React 공식 한글 문서 링크'

 

위 문서 링크에 있는 내용 중 일부를 발췌 하겠다. 

 

(주의: React17 부터는 componentWillMount, componentWillUpdate, componentWillReceiveProps 라이프 사이클이

          deprecate 된다. )

 

Mount

컴포넌트가 처음 실행될 때 그것을 Mount라고 표현합니다. 컴포넌트가 시작되면 우선 context, defaultProps와 state를 저장합니다. 그 후에 componentWillMount 메소드를 호출합니다. 그리고 render로 컴포넌트를 DOM에 부착한 후 Mount가 완료된 후 componentDidMount가 호출됩니다.

주의할 점은, componentWillMount에서는 props나 state를 바꾸면 안 됩니다. Mount 중이기 때문이죠. 그리고 아직 DOM에 render하지 않았기 때문에 DOM에도 접근할 수 없습니다.

componentDidMount에서는 DOM에 접근할 수 있습니다. 그래서 여기에서는 주로 AJAX 요청을 하거나, setTimeout, setInterval같은 행동을 합니다.

정리하면 다음 순서로 실행됩니다.

  1. state, context, defaultProps 저장
  2. componentWillMount
  3. render
  4. componentDidMount

Props Update

props가 업데이트될 때의 과정입니다. 업데이트되기 전에 업데이트가 발생하였음을 감지하고, componentWillReceiveProps 메소드가 호출됩니다. 그 후 shouldComponentUpdate, componentWillUpdate가 차례대로 호출된 후, 업데이트가 완료(render)되면 componentDidUpdate가 됩니다. 이 메소드들은 첫 번째 인자로 바뀔 props에 대한 정보를 가지고 있습니다. componentDidUpdate만 이미 업데이트되었기 때문에 바뀌기 이전의 props에 대한 정보를 가지고 있습니다.

shouldcomponentUpdate에서는 아직 render하기 전이기 때문에 return false를 하면 render을 취소할 수 있습니다. 주로 여기서 성능 최적화를 합니다. 쓸데없는 update가 일어나면 여기서 걸러내는 거죠.

주의사항이 있는데, componentWillUpdate에서는 state를 바꿔서는 안 됩니다. 아직 props도 업데이트하지 않았으므로 state를 바꾸면 또 shouldComponentUpdate가 발생합니다. componentDidUpdate에서는 render이 완료되었기 때문에 DOM에 접근할 수 있습니다.

  1. componentWillReceiveProps
  2. shouldComponentUpdate
  3. componentWillUpdate
  4. render
  5. componentDidUpdate

State Update

setState 호출을 통해 state가 업데이트될 때의 과정입니다. props update와 과정이 같지만, componentWillReceiveProps 메소드는 호출되지 않습니다. 그리고 메소드의 두 번째 인자로는 바뀔 state에 대한 정보를 가지고 있습니다. componentDidUpdate는 두 번째 인자로 바뀌기 이전의 state에 대한 정보를 가지고 있습니다.

  1. shouldComponentUpdate
  2. componentWillUpdate
  3. render
  4. componentDidUpdate

Unmount

컴포넌트가 제거되는 것은 Unmount라고 표현합니다. 더는 컴포넌트를 사용하지 않을 때 발생하는 이벤트가 있습니다. componentWillUnmount가 그것입니다. componentDidUnmount는 없습니다. 이미 제거된 컴포넌트에서 이벤트를 발생시킬 수는 없겠죠? componentWillMount에서 주로 연결했던 이벤트 리스너를 제거하는 등의 여러 가지 정리 활동을 합니다.

  1. componentWillUnmount

다행히도 용도에 맞지 않는 메소드를 사용하면 React에서 자체적으로 에러 메시지를 띄워 줍니다. componentDidMount나 render에 setState를 사용한 경우도 에러 메시지를 띄웁니다. 그래도 혹시나 모를 상황에 대비하여 용도를 항상 알고 있는 게 좋겠습니다. 다음 시간에는 React-router에 대해 알아봅시다.

Error

에러 발생 시를 위한 componentDidCatch도 있습니다. 리액트 16에서 추가되었습니다.

componentDidCatch(error, info) {
  console.error(error, info);
}

위와 같이 사용하고, 최상위 컴포넌트에 한 번만 넣어주면 됩니다. 에러 발생 시 어떻게 대처할 것인지를 정의할 수 있습니다. 최소한 에러를 로깅하는 것만으로도 사용 가치가 있습니다.

 

아래는 공식 사이트에서 발췌된 내용중 일부이다.

 

마운트 (Mount)

아래 메서드들은 컴포넌트의 인스턴스가 생성되어 DOM 상에 삽입될 때에 순서대로 호출됩니다.

 

( Mount란 컴포넌트를 특정 영역에 삽입하는 행위이다. 

  예로 ReactDOM.render 함수를 통해서 DOM의 특정 영역에 React 컴포넌트를 삽입할 수 있고

  이러한 과정을 마운트(Mount) 한다고 얘기한다. )

 

* Deprecate 함수 설명 및 대체 함수 

componentWillMount()

componentWillMount()는 마운트가 발생하기 전에 호출된다.
render() 가 실행되기 전에 호출되므로, 이 메서드 내에서 setState()를 동기적으로 호출하더라도
추가적인 렌더링이 발생되지 않는다. 

공식 문서에서 권장하는것은 componentDidMount() 를 대신 사용하라고 한다. 
* componentDidMount() 는 서버 렌더링에서 호출되는 유일한 생명주기 메서드 이다. 

 

 

 

업데이트

props 또는 state가 변경되면 갱신이 발생합니다. 아래 메서드들은 컴포넌트가 다시 렌더링될 때 순서대로 호출됩니다.

 

* Deprecate 함수 설명 및 대체 함수/방법

componentWillReceiveProps()

componentWillReceiveProps() 는 마운트된 컴포넌트가 새로운 props를 전달받기 전에 호출된다. 
그러나 이 메서드를 사용하면 버그를 만들거나 일관성을 해칠 수 있다. 

- props 변화에 대응한 효과를 발생시켜야 한다면 (Ex: 데이터를 가져오기 또는 에니메이션 등...) 
  componentDidUpdate() 생명주기를 사용하기를 권한다. 

- props가 변화할 때 일부 state를 재설정하기 위해서는
   완전 제어 컴포넌트 또는 Key를 사용하는 완전 비제어 컴포넌트를 만들어서 사용하라고 
  공식 문서는 권한다. 

 

componentWillUpdate()

componentWillUpdate() 는 새로운 props 또는 state가 전달되어서 렌더링이 이루어지기 전에 호출된다. 
이 메서드는 초기 렌더링에서는 호출 되지 않는다. 

또한 이 메서드 내에서는 this.setState() 를 호출 할 수 없다. 또한 React 컴포넌트가 
갱신되도록 만드는 그 어떤 작업eh componentWillUpdate() 가 결과값을 반환하기 전에 
이루어 져서는 안된다. 

componentWillUpdate() 는 shouldComponentUpdate() 메서드가 false 를 반환한다면 호출되지 않는다.  

componentWillUpdate()componentDidUpdate() 로 대체할 수 있다. 
만약 메서드내에서 DOM 에 대한 정보 획득 (Ex: 스크롤 위치 저장 등..) 을 하려 한다면
getSnapshotBeforeUpdate() 를 사용하는것이 가능하다.

 

위 내용들은 아래 링크인 React 공식 홈페이지에서 발췌해 왔다.

아래 링크를 통해 공식 문서를 천천히 살펴보기를 강력하게 권한다. 

 

 

 

React.Component – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

 

 

마지막으로 React LifeCycle 에 대한 이미지로 마무리 하겠다. 

 

[ 일반적인 React LifeCycle ]

일반적인 React LifeCycle

 

[ 덜 일반적인 React Life Cycle ]

약간 일반적이지 않는 Life cycle

 

 

VSCode 를 이용하여 React 를 개발하려 마음먹었다. 

VSCode 내 terminal 에서는 yarn start 실행 시 오류가 발생되었다. 

 

Windows 의 command 창에서는 yarn start / npm start 로 React 화면이 정상적으로 연동되는데

VSCode 의 terminal 창에서는 아래와 같은 오류가 발생되는 것이다. 

( 참고로 npm start 는 정상적으로 작동한다. )

오류 내용을 보니 yarn을 로드 할수 없고 권한이 없다고 얘기한다. 

그러면서 친절하게 참조 URL도 알려준다. 

https://go.microsoft.com/fwlink/?LinkID=135170

 

위 사이트를 들어가서 천천히 보면 Windows의 Script 사용권한이 제한되어 발생되는것을 알 수 있다. 

go.microsoft.com

 

위 링크로 들어가서 페이지 내용을 쭉 보는것이 가장 좋우나, 

현재 문제만을 우선적으로 해결해보자. 

 

1. Windows 에서 PowerShell 을 관리자 권한으로 실행한다. 

(관리자 권한으로 PowerShell 실행)

2. 현재 스크립트 정책이 어떻게 설정되어 있는지 확인한다. 

   PowerShell 에서 ExecutionPolicy 를 입력하면 알 수 있다. 

 

   > ExecutionPolicy  

 결과는 Restricted 이다. 

  * Restricted  ( 링크된 Microsoft 페이지에서 발췌 )

     - 클라이언트 컴퓨터 Windows에 대한 기본 실행 정책

     - 개별 명령을 허용 하지만 스크립트를 허용하지 않는다. 

     - 서식 지정 및 구성 파일( .ps1xml ), 모듈 스크립트 파일( .psm1 ) 및 PowerShell 프로필 () 을 비롯한 

        모든 스크립트 파일의 실행을 방지 .ps1 한다. 

 

3. 위 microsoft 링크에서 '실행 정책 변경' 부분을 찾으면 자세히 나오나

   나는 PowerShell 에 아래와 같이 명령을 입력 하였다. 

 

    > Set-ExecutionPolicy Remotesigned   

PowerShell 에서 권한 변경

4. 이렇게 권한을 변경한 후 VSCode 의 터미널에서 yarn start 명령어 수행 시 

    정상적으로 구동된다. 

 

* 조금 귀찮을 수도 있지만, Windows 스크립트 실행 권한에 대해서 좀더 자세히 알아보는것을 추천한다. 

  관련 링크 : https://go.microsoft.com/fwlink/?LinkID=135170

'Development > React Issue' 카테고리의 다른 글

React Delete `CR` prettier/prettier 이슈  (0) 2021.10.21

[ 전 세계 프로그래머들이 도전 ]

https://www.topcoder.com/

 

Top Technology Talent On-Demand

Topcoder is home to the world’s largest community of designers, developers, and data scientists. Allowing you the freedom to start and execute faster.

www.topcoder.com

 

[ 주어진 문제들을 해결하여 코딩실력을 늘려보자 (유료가입) ]

https://coderbyte.com ( 유료 : 월 35$ )

 

Coderbyte | Code Screening, Challenges, & Interview Prep

Improve your coding skills with our library of 300+ challenges and prepare for coding interviews with content from leading technology companies.

coderbyte.com

 

[ Train coding skill ]

https://app.codility.com/programmers/

 

Programming Online Training In Coding Skills | Codility - Codility

Find longest sequence of zeros in binary representation of an integer.

app.codility.com

 

[ 수학적인 문제들을 프로그래밍으로 해결하는 사이트 ]

https://projecteuler.net/ ( 번역 : euler.synap.co.kr )

 

About - Project Euler

The page has been left unattended for too long and that link/button is no longer active. Please refresh the page.

projecteuler.net

 

 

본론부터 가자

양방향 암호화 (복호화 가능) 과 단방향 Hash 데이터가 있다.

 

우선 Hash 에 대해 간단히 설명하자

 

- Hash Algorithm을 이용하여 원문 데이터 길이와 무관하게 항상 고정된 길이로 Hash 데이터를 생성한다.

 

- Hash Algorithm 은 모두 공개되어 있기 때문에 사용해서는 안되는 Algorithm 이 있다.

  ( 권장되지 않는 Hash Algorithm : MD5, SHA-1, HAS-180 )

 

- 위에서 언급한 대로 원문(입력값) 은 무한대 이지만 Hash 된 값은 항상 고정된 길이 값으로

   나타내기 때문에 중복되는 Hash 값이 나올 수가 있다. (확률은 낮고, 중복 최소화를 위해 Algorithm 이 생겨난듯...)

 

- Hash 데이터는 복호화가 되지 않는다. 즉 데이터의 무결성을 검증 할 수 있는 Signatrue 데이터 이다. 

 

여기서는 Hash 데이터 생성 방법 중 SHA-256HMAC 에 대한 간단한 샘플을 기재한다. 

 

[ SHA-256 ]

 

: SHA ( Secure Hash Algorithm )

import java.security.MessageDigest;

import java.securit.NoSuchAlgorithmException;

import java.util.Base56;


public class SHA256Test
{
    public static void main( String[] args )
    {
        String plainData = "ABCDEFG^1234^!@#$";
        
        SHA256Test shaTest = new SHA256Test();
        String hashData = shaTest.sha256Hash( plainData );

        System.out.println( "SHA_256 : " + hashData );
        System.out.println( "SHA_256.len : " + hashData.getBytes().length );
    }

    public String sha256Hash( String plainData )
    {
        try {
            MessageDigest md = MessageDigest.getInstance( "SHA-256" );
            md.update( plainData.getBytes() );
            return bytesToHex( md.digest() );
        } catch( NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // byte 데이터를 16진수 String 데이터로 변환    
    public String bytesToHex( byte[] btArrData )
    {
        StringBuffer strBuf = new StringBuffer();
        
        for( byte bt : btArrData )
        {
            strBuf.append( String.format( "%02x", bt ) );
        }

        return strBuf.toString();
    }
    
}

 

[ SHA256 결과 ]

SHA_256 : 218d186.................................~~.......................................2835ceeb
SHA_256.len : 64

위와 같은 결과가 나온다. 

위에서 plainData 값을 늘리거나 줄이거나 하여도 길이는 항상 64가 나온다. 

이유는 간단하다.

sha-256 알고리즘은 데이터를 hash 할 때 항상 256 bit 로 변환이 된다. 

 

16진수는 1자리가 4 bit 이며, sha-256 문자열 길이가 64 byte 이면

64 * 4 = 256 bit 가 되기 때문이다.

 

 

[ HMAC ]

 

HMAC : Hash based Message Authentication Code - 인증된 메세지 코드 라는 뜻이다

- 위 처럼 HMAC 는 hash 기반의 인증이 포함된 메세지이다.

  HMAC 은 위 SHA-256 과 달리 Key가 필요하며, Hash based 의 무결성과 Key 을 이용한 인증 

  2가지를 다 제공하고 있다. 

 

아래 예제는 HMAC_SHA256 데이터를 만드는 샘플이다. 

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class HMAC_SHA256Test
{
    public static final String HMAC_ALG = "HmacSHA256";


    public static void main( String[] args )
    {
        String plainData = "ABCDEFG^1234^!@#$";
        String hmacKey  = "TEST1234567890";
        
        HMAC_SHA256Test hmacTest = new HMAC_SHA256Test();

        String hmacData= hmacTest.getHMacData( plainData, hmacKey );

        System.out.println( "HMAC_SHA_256 : " + hashData );
        System.out.println( "HMAC_SHA_256.len : " + hashData.getBytes().length );
    }


    public String getHMacData( String plainData, String hmacKey )
    {
        try {

            // HMAC Hash 알고리즘 & Key 설정
            Mac mac = Mac.getInstance( HMAC_ALG );
            mac.init( new SecretKeySpec( hmacKey.getBytes(), HMAC_ALG ) );

            // HMAC 데이터 생성.
            byte[] btArrHmacData = mac.doFinal( plainData.getBytes() );

            String hmacData = bytesToHex( btArrHmacData );


        } catch( NoSuchAlgorithmException e ) {
            e.printStackTrace();
            return null;
        } catch( InvalidKeyException e ) {
            e.printStackTrace();
            return null;
        }

    }


    // byte 데이터를 16진수 String 데이터로 변환    
    public String bytesToHex( byte[] btArrData )
    {
        StringBuffer strBuf = new StringBuffer();
        
        for( byte bt : btArrData )
        {
            strBuf.append( String.format( "%02x", bt ) );
        }

        return strBuf.toString();
    }


}

 

위 main 함수 실행 시 다음과 같은 결과가 나온다. 

HMAC_SHA_256 : 1424fe73f7e ~~~  426b87b
HMAC_SHA_256.len : 64

 

결론 : Hash 를 암호화라고 생각할 수 있으나 위에서 언급했던것 과 같이 Hash 는 복호화가 불가능하며, 

        Hash 데이터 검증을 위해서는 원문데이터가 필요하거나 또는 원문 + Key 값이 필요하다. 

 

이렇게 간단히 Hash 데이터를 만드는 방법을 알아보았다. 

이 방식 외 공개키 개인키로 Signatrue 데이터를 만들어 verify 하는 방법도 있으나, 해당 내용은

다음에 알아보도록 하겠다. 

'Development > JAVA' 카테고리의 다른 글

Oracle OpenJDK 11 버그로 인한 AdoptJDK 다운  (0) 2021.01.16
java 날짜 계산 (java.time)  (0) 2020.11.03
PKCS 표준 정보  (0) 2020.10.26
Open JDK 다운로드  (0) 2020.04.22
Java Caller & Callee 확인하기  (0) 2020.04.17

OpenJDK 를 이용해서 서비스를 개발해야 했다. 

예전에 JDK 1.8 에서 Licence 문제로 인하여 OpenJDK 로 바꿔야 하는 이슈였다. 

 

OpenJDK 는 아래 사이트에서 다운받았다. 

 

Java Platform, Standard Edition 11 Reference Implementations

Java Platform, Standard Edition 11 Reference Implementations The official Reference Implementation for Java SE 11 (JSR 384) is based solely upon open-source code available from the JDK 11 Project in the OpenJDK Community. This Reference Implementation a

jdk.java.net

참고로 밴더사는 Oracle 로 알고 있다. 

위 사이트에서 openjdk-11+28_windows-x64_bin 파일을 받아 실행하였고, 

서비스를 운영중 뜻하지 않는 문제를 발견하였다. 

 

바로 TCP 통신을 위하여 Connection 객체를 생성하였고, 통신 완료 후 SSLSocket 을 종료 시키려 해더

종료가 되지 않는것이다.

( Finally 에서 close() 를 선언하였는데도 Socket 이 여전히 살아 있다. )

 

때문에 FD 에  ( 리눅스 CentOS 환경에서 운영중.. ) 에 해당 Process 가 사라지지 않고 누적되었으며, 

결국 FD 가 Full 되서 서버가 다운되는 현상이었다. 

 

위 이슈는 해당 버그 Fix 페이지에 나와 있다. 

URL : bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8246031

 

재미있는건 Oracle Licence 가 적용된 JDK 11.0.8 버전에서는 해결을 했다고 하나, 내가 사용하는

OpenJDK 11 ( openjdk-11+28_windows-x64_bin ) 에서는 문제가 발생되고 있는것이다. 

 

Oracle 벤더에서 OpenJDK 명명법이 어떻게 되는지 모르겠다. ( 다시 말하지만 파일 명은 openjdk-11+28... 이다. )

아무튼 해당 이슈를 해결하기 위하여 OpenJDK 를 바꾸었다.

 

벤더사는 Adopt 이며 버전은 OpenJDK 11

Adopt 의 OpenJDK 11.0.9 (LTS) 를 사용 후 문제는 사라졌다. 

 

AdoptOpenJDK

AdoptOpenJDK provides prebuilt OpenJDK binaries from a fully open source set of build scripts and infrastructure. Supported platforms include Linux, macOS, Windows, ARM, Solaris, and AIX.

adoptopenjdk.net

P.S)  LTS (Long Term Support ) : 장기간 해당 버전에 대한 지원을 하는것이다. 

 

 

'Development > JAVA' 카테고리의 다른 글

SHA-256 & HMAC  (0) 2021.04.19
java 날짜 계산 (java.time)  (0) 2020.11.03
PKCS 표준 정보  (0) 2020.10.26
Open JDK 다운로드  (0) 2020.04.22
Java Caller & Callee 확인하기  (0) 2020.04.17

java에서는 날짜를 추출/계산 할 수있는 여러가지 방법이 있지만, 익히 알고 있는 방법은

Calendar 클래스를 이용하는 것이다. 

 

Calendar 은 JDK 1.1 부터 제공되었고 유용하게 사용되었으나, 몇가지 문제점이 있다. 

- Calendar 인스턴스는 불변 객체가 아니어서 수정이 가능하다. 

- 윤초와 같은 특별한 상황은 고려되지 않았다. 

- Calendar 은 1월 ~ 12월 을 0 ~ 11 로 표현해야 한다. 

 

JDK 8 이후 버전부터는 새로운 날짜와 시간 API 인 java.time 패키지를 제공한다. 

아래는 java.time 이하 에서 제공되는 하위 패키지 들이다. 

아래 내용은 gbsb.tistory.com/302에서 발췌하였다. 

 

- chrono : ISO-8601 에 정의된 표준달력 외 달력시스템 사용 시 이용되는 클래스 패키지

- format  : 날짜와 시간에 대한 데이터를 분석하고 형식화 하는 클래스 집합 패키지.

- temporal : 날짜와 시간에 대한 연산에 사용되는 보조 클래스들 집합 패키지

- zone : Time-Zone 에 관련 클래스 집합 패키지

 

패키지 외 여러 클래스들이 존재하지만 자주 사용되는 몇가지에 대해 정의한다. 

- LocalDate : 날짜를 표현 시 사용. ( 타임존에 따른 시간 변환 불가 )

- LocalTime : 시간을 표현 시 사용 ( 타임존에 따른 시간 변환 불가 )

- LocalDateTime : 날짜와 시간을 한 번에 표현 시 사용. ( 타임존에 따른 시간 변환 불가 )

- ZonedDateTime : 특정 Time-zone 에 해당하는 날짜와 시간을 다룰 때 사용.

- Instant : 특정 시점의 날짜와 nanosecond 단위로 표현하는 time-stamp 다룰 때 사용.

- Period : 두 날짜 사이의 차이를 표현 시 사용

- Duration : 두 시각 차이를 표현 시 사용

- TemporalField : 월(month-of-year) 과 시(hour-of-day) 와 같이 날짜, 시간과 관련된 필드를 정의한 인터페이스.

                     이 인터페이스를 구현하여 날짜와 시간을 나타낼 때 사용하는 열거체가 ChronoField 이다

 

앞서 얘기한데로 Canendar 클래스는 1월 - 0 , 12월 - 11 로 표현하였으나, 

java.time 부터는 1월 - 1, 12월 - 12로 표현한다.  또한 요일은 월요일 - 1, 일요일 - 7 로 

표기한다. 

 

[ LocalDate 생성 & 사용 ]

위 클래스들은 public 생성자를 제공하지 않기 때문에 객체를 생성할 때 now(), of(), parse() 과 같은 

정적 메소드를 사용해야 한다. 

LocalDate currDate = LocalDate.now();

System.out.println( "Today : " + currDate ); 

>>> 2020-11-06

LocalDate targetDate = LocalDate.of(1981, 2, 9);
System.out.println( "targetDate : " + targetDate );
>>> 1981-02-09

LocalDate parseDate = LocalDate.parse("1981-02-09");
System.out.println( "parseDate : " + parseDate );>>> 1981-02-09

now()  : 현재 날짜 또는 시간을 이용하여 새로운 객체를 생성 및 리턴

of()     : 지정한 날짜와 시간을 표현하는 객체를 생성 및 리턴

parse() : 지정한 날짜와 시간을 표현하는 객체를 생성 및 리턴

 

[ LocalTime 생성 & 사용 ]

- LocalDate 와 매우 유사하며, 기본 포멧은 HH:mm:ss.SSS  이다.

LocalTime currTime = LocalTime.now();

System.out.println( "currTime : " + currTime );

>>> 02:30:27.123

LocalTime seoulTime = LocalTime.now( ZoneId.of("Asiz/Seoul") ) );

System.out.println( "seoulTime : " + seoulTime );

>>> 02:30:27.124

LocalTime targetTime = LocalTime.parse( 02, 30, 10 );

System.out.println( "targetTime : " + targetTime );

>>> 02:30:10

LocalTime targetPlusTime = targetTime.plusHour(8);

System.out.println("targetPlusTime : " + targetPlusTime );

>>> 10:30:10

LocalTime targetMinusTime = targetTime.minusHour(1);

System.out.println( "targetMinumTime : " + targetMinumTime );
>>> 01:30:10

위 샘플들은 LocalDate, LocalTime 으로 분리하였으나 실제 사용되는 함두는 두 클래스(LocalDate, LocalTime)

다 유사하다.

즉, LocalDate 클래스에도 plusDays(..), plus(..), plusHours(..) 등 plusXxxx(...) 와 minusXxxx(...) 함수들이 제공된다. 

 

[ LocalDateTime 객체 생성 & 사용 ]

- LocalDateTime 클래스는 LocalDate 와 LocalTime 2개의 기능을 모두 제공하는 클래스라고 생각하면 된다. 

  또한 제공되는 함수도 유사하다. ( 기본 포멧은 yyyy-MM-ddTHH:mm:ss.SSS 이다. )

LocalDateTime currLDT = LocalDateTime.now();

System.out.println( "currLDT : " + currLDT );

>>> 2020-11-05T02:30:10.235

LocalDateTime targetLDT = LocalDateTime.parse("2020-11-05T02:30:10.123");

System.out.println( "targetLDT : " + targetLDT );

>>> 2020-11-05T02:30:10.123

LocalDateTime targetLDT2 = LocalDateTime.of(1891, 2, 9, 6, 10, 11);

System.out.println( "targetLDT2 : " + targetLDT2 );

>>> 1981-02-09T06:10:11

 

with() : 생성된 객체( Local.... ) 의 특정 필드값을 변경하기 위해서 사용.

 

- with(TemporalField field, long newValue) : LocalDate 객체에서 특정 필드(TemporalField) 를 새로운 값(long)

     으로 설정한 객체를 반환한다. 

- withYear(int year) : LocalData 객체에서 연도 필드를 새로운 값(int) 로 설정 및  반환

- withMonth(int month) : LocalDate 객체에서 월(MONTH_OF_YEAR) 필드를 새로운 값(int) 으로 설정 및 반환 

- withDayOfMonth(int dayOfMonth) : LocalData 객체에서 일(DAY_OF_MONTH) 필드를 새로운 값(int) 으로 설정 및 반환.

- withDayOfYear(int dayOfYear) : LocalDate 객체에서 DAY_OF_YEAR 필드를 새로운 값(int) 으로 설정 및 반환

 

LocalTime 에서는 with(...) withHour(...), withMinute(...), withSecond(...), withNano(...) 등이 존재한다. 

 

with..(...) 함수 외에 plus(), minus() 함수도 제공하고 있다. 

 

[ 날짜 & 시간 객체의 비교 ]

- isEqual() : 오직 날짜가 같은지 비교하며, LocalDate 클래스에서만 제공. ( boolean )

- isBefore() : 객체를 비교하여 이전인지 여부 확인 ( boolean )

- isAfter() : 객체를 비교하여 이후 인지 여부 확인 ( boolean )

 

 

[ java.time.Instant ]

 

Instant.now() 를 호출 시 현재 시간 Instant 를 획득할 수 있다. (UTC 기준 ISO 포멧이다.)

또한 초단위 또는 밀리초 단위의 Timestamp 값을 long 타입으로 얻을 수 있다. 

Instant currInstant = Instant.now();

System.out.println( "UTC+0 기준 현재 시간 : " + currInstant );
--> 2020-11-09T23:20:46.80619700Z    

( 현재 한국 시간은 2020-11-10 08:21 이다. )

System.out.println( "UTC+0 기준 현재 시간 Timestamp (초) : " + currInstant.getEpochSecond() );
--> 1604964046

System.out.println( "UTC+0 기준 현재 시간 Timestamp (밀리초) : " + currInstant.toEpochMilli() );
--> 1604964046806

 

 

Instant 클래스와 ZoneDateTime 클래스는 특정 메서드를 통해 객체가 서로 변환이 가능하다.

바로 atZone(..) 메소드와 toInstant() 메소드 이다. 

Instant currInstant = Instant.now();
ZoneDateTime zdt = currInstant.atZone( ZoneId.of("Asia/Seoul") );

System.out.println( "한국 현재 시간 : " + zdt );
--> 2020-11-10T08:21:45.403111800+09:00[Asiz/Seoul]

Instant korInstant = zdt.toInstant();
System.out.println( "한국 현재 시간 Instant: " + korInstant );
--> 2020-11-09T23:20:46.80619700Z

 

[ java.time.ZoneDateTime ]

ZoneDateTime 클래스는 타임존 또는 시차가 적용되는 필요한 날짜와 시간정보를 나타낼 때 사용하면 용이하다. 

public 생성자는 제공하지 않으며, 정적 메소드를 통하여 객체를 생성한다. 

또한 format() 메소드에 DateTimeFormatter 객체를 사용하여 원하는 문자열로 포멧 변환이 가능하다.

DateTimeFormatter 은 ofPattern(...) 을 이용하여 원하는 포멧을 정의하거나 DateTimeFormatter 에서 제공하는

정적 필드( Ex: DateTimeFormatter.ISO_DATE_TIME.. ) 를 이용할 수 있다. 

날짜 시간에 대한 언어 표현은 withLocale( Locale.~ ) 함수를 사용하여 다양하게 구현할 수 있다. 

System.out.println( "한국 현재 시간 ZoneDateTime: " + ZoneDateTime.now() );
--> 2020-11-10T08:38:51.751179300+09:00[Asia/Seoul]

String zdtFormat = ZoneDateTime.now().format( DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss") );
System.out.println( "ZoneDateTime.format: " + zdtFormat  );
--> 2020.11.10 08:43:49

DateTimeForamtter dtf_1 = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss a z");
System.out.println("DTF_1 : " + ZoneDateTime.now().format( dtf_1 ) );
--> 2020.11.10 08:43:49 오전 KST

DateTimeForamtter dtf_2 = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss a z").withLocale(Locale.ENGLISH);
System.out.println("DTF_2 : " + ZoneDateTime.now().format( dtf_2 ) );
--> 2020.11.10 08:43:49 AM KST

 

[ ZoneId & ZoneOffset ]

ZoneId 는 타임존으로 지정한 지역의 시간코드, ZoneOffset 은 UTC 기준 시간차 (양수/음수) 를 나타낸다.

예로 한국 서울의 ZoneId : Asia/Seoul & ZoneOffSet : +0900 이다. 

System.out.println( "ZoneOffset.of('+09:00') : " + ZoneDateTime.now(ZoneOffset.of("+09:00")) );
--> 2020-11-10T08:38:51.751179300+09:00

System.out.println( "ZoneDateTime.format: " + ZoneDateTime.now( ZoneId.of("Asia/Seoul")  );
--> 2020-11-10T08:38:51.751179300+09:00[Asiz/Seoul]

 

'Development > JAVA' 카테고리의 다른 글

SHA-256 & HMAC  (0) 2021.04.19
Oracle OpenJDK 11 버그로 인한 AdoptJDK 다운  (0) 2021.01.16
PKCS 표준 정보  (0) 2020.10.26
Open JDK 다운로드  (0) 2020.04.22
Java Caller & Callee 확인하기  (0) 2020.04.17

앞에서 확인했듯이 SSL 통신은 Client 에서 Server 에 대한 검증을 수행한다.

하지만 Server 측에서의 Client에 대한 검증과정은 별도 존재하지 않는다. 

 

일반적인 웹서비스에는 해당되지 않으나, Server 측에서 제한된 Client 만 

접속을 허용하기 위해서 Client 검증을 해야 한다면 MTLS (Mutual TLS) 를 사용하는 것이다. 

즉, Client 에서 접속하는 Server 에 대한 검증과 Server 에서 Client 에 대한 검증을

서로 하는 것이다. 

 

아래 통신과정을 살펴보자

MTLS 통신과정

SSL 통신과정과 유사하나 몇개 추가된 부분이 보인다.

 

Certificate Request

Client 에게 인증서를 제공해달라고 요청하는 역활이다. 

이 메세지를 받은 Client 는 Server 에 인증서를 제공해야 한다. 해당 메세지는 ㅗ뭉노맏 ㅖ개새채ㅣdp 

속하는 메세지이며 두 가지 필드가 있다. 

1. 서버가 인식 할 수 있는 인증서 타입 리스트

2. 서버가 인식 할 수 있는 DN 타입 리스트

 

Client certificate

Server가 Client에게 보낸것과 동일하며 여기에는 Client 인증서와 인증서 체인에 속한 모든 인증서가

들어 있다. 

 

Certificate verify

Client가 Server에 자신이 보낸 인증서의 주인이 정말 Client 라는것을 입증하는 메세지이다. 

ClientVerify 메세지는 Handshake Protocol 에 속하는 메세지로 이 안에는 서명값이 들어 있다. 

서명값은 클라이언트가 서버에게 보낸 모든 메세지들을 압축한 Hash 값을 Client 개인키로

암호화 하여 생성한 값이다. 

 

이 서명값은 서버에게 클라이언트의 인증서 안에 기입된 공개키와 쌍이되는 개인키를 클라이언트가 

가지고 있다는것을 증명한다. 

즉, 공개키와 쌍이되는 개인키를 가지고 있다는 것은 클라이언트가 그 공개키가 있는 인증서의 

주인임을 증명하는 것이다. 

'Development > Security (보안)' 카테고리의 다른 글

SSL 통신원리  (0) 2020.10.14
SSL 이란?  (0) 2020.09.22
X.509 인증서  (0) 2020.09.18
JAVA 사설인증서 MTLS 통신 ( Server )  (0) 2020.09.16
Java 사설인증서 MTLS 통신 ( Client )  (0) 2020.09.15

+ Recent posts