www.notion.so/OAuth-1ac11441fca1492191283ef70c589b89

 

OAuth

OAuth

www.notion.so

OAuth

 

  1. OAuth

아이디나 암호가 노출되지 않고 api의 접근을 위임하는 방식

인증과 인가를 사용하는 방식

 

써드파티에 아이디 비밀번호를 넘기는건 위험하므로 api 토큰을 써드파티가 사용하게함

써드파티 어플리케이션이 api 토큰으로 api 서비스 정보를 요청하고 받아올수 있음

 

Request Token 의 요청과 발급이 이루어지고

사용자 인증 페이지 호출

사용자 로그인 완료

사용자의 권한 요청 및 수락

Access Token 발급

Access Token 을 이용해 서비스 정보를 요청

 

2. OAuth 1 과 2 의 차이점

2는 SSL을 사용함

2는 Client에서 암호화를 위한 코드를 삽입할 필요가 없음 (SHA1등)

 

1은 인증을 얻기 위해 web 환경만 지원

2는 web 말고 다른 환경도 지원함.

 

1은 보안토큰이 2개 사용되고 2는 하나만 사용됨

 

3. OAUTH2 기준 구현 방식이 뭐가 있고 어떤 시나리오에 적합한가

 

시나리오

적합한 시나리오는 서드파티 나 다른 어플리케이션 , 모바일 어플리케이션 또는

웹의 SPA 방식에서 아이디와 비밀번호를 노출하지않고 토큰으로 리소스를 가져오는 것

구현 방식

security에서 oauth 설정

인증 서버 클래스 설정

인가 서버 클래스 설정

(자세하게 추가 필요)

 

4. OAUTH2 기반으로 JWT 라는 게 있는데 이거는 뭐고 어떤 경우에 좋고 어떤 고려사항이 있는가

 

JWT 란

 

토큰을 JSON 방식으로 만들고 모든 정보 ( 토큰의 기본 정보 , 유저 정보, 토큰이 검증됐다는것을 증명해주는 시그니쳐 정보 ) 를 가지고 있고 헤더나 url에 넣어서 전달이 가능함.

총 3가지 부분으로 나뉘어져 있는데 . 으로 그것을 구분하며

 

첫번째 헤더 부분 은 토큰의 타입과 해싱 알고리즘이 등록 되어있고

 

두번째 내용 (페이로드 ) 부분은 등록된 클레임 , 공개 클레임 , 비공개 클레임이 등록되어있습니다.

 

등록된 클레임 은 서비스에서 필요한 정보들이 아닌 토큰에 대한 정보들을 담기위하여 이름이 이미 정해진 클레임들입니다.

예) 토큰발급자 iss , 토큰 제목 sub , 토큰 대상자 aud 토큰 만료시간 exp 등

 

공개 클레임은 충돌이 방지된 이름을 가지고 있어야 하므로 클레임 이름을 URI 형식으로 짓습니다.

예) "https://xxxx.xxx/aa/aa" : true

 

비공개 클레임은 클라이언트와 서버의 협의하에 사용되는 클레임 이름들입니다.

공개 클레임과는 달리 이름이 중복되어 충돌이 될수 있습니다.

예) "username" : "aaaa"

 

payload 예)

 

{

    "iss": "velopert.com",
    "exp": "1485270000000",
    "https://velopert.com/jwt_claims/is_admin": true,
    "userId": "11028373727102",
    "username": "velopert"
}

 

세번째 부분은 시그니쳐 부분입니다.

이 시그니쳐 부분은 헤더의 base64 인코딩 값 정보의 base64 인코딩 값을 합친 후 주어진 비밀키로 해쉬를 하여 생성.

 

JWT의 장점

jwt 발급 후 토큰 검증만 하면 되기 때문에 추가 저장소가 필요 없음

토큰 기반으로 하는 다른 인증 시스템에 접근이 가능

 

JWT의 고려사항

토큰의 페이로드에 3종류의 클레임을 저장하기 때문에 토큰의 길이가 엄청나게 길어질경우

네트워크에 부하를 줄수가 있다.

 

페이로드 인코딩은 자체 암호화가 아니라 base64인코딩이므로 중간에 탈취되서 디코딩하면

데이터가 보인다. 시그니쳐는 비밀키로 sha 해싱하기 때문에 알수가 없음.

 

stateless 무상태이기 때문에 제어 (임의 삭제, 수정 등) 이 불가 하므로 토큰 만료시간을 꼭 넣어줘야한다.

 

토큰은 클라이언트 측에서 관리해야 하기 때문에, 토큰을 저장해야 한다.

 

 

 

5. OAUTH 토큰을 어떤 식으로 전달하고 보관하는 것이 보안에 안전한가.

 

  1. 요청 헤더나 바디에 넣어서 전달하는 방법은 빠르나 보안에 매우 취약하다.
  1. 헤더에 쿠키를 담아 보내는 방법은 1번 보다는 안전하다 마찬가지로 탈취되면 보안에 취약함
    1. 계정정보가 담기지 않았으므로 1번보다는 안전하지만 탈취된 쿠키를 이용해 http 요청을 보내면 서버의 세션 저장소가 쿠키의 탈취 여부를 알수없어 그대로 정보를 제공함
      1. 해결책은 https 를 사용해 쿠키를 읽을수 없게 하거나 세션에 유효시간을 넣어준다.
      1. 세션 저장소를 사용하므로 서버에 어느정도 부하가 생김

       

  1. JWT 방식
    1. 장점
      1. stateless 하므로 따로 저장소를 사용하지 않습니다.
      1. 확장성이 뛰어나므로 토큰기반의 다른 인증시스템에 접근이 가능합니다. ( facebook, google 등)

         

    1. 단점
      1. claims가 많을수록 jwt가 길어짐. 요청이 많아질수록 자원낭비 발생함.
      1. 중요한 정보를 payload에 넣을수 없음. base64로 인코딩 되어있기때문에 손쉽게 디코딩해서 정보를 볼수가 있음.
      1. jwt 역시 탈취되면 유효기간이 지나기 전까지 정보가 탈취됨.
        1. AccessToken의 유효기간을 짧게하고 Refresh Token을 이용해 새롭게 인증을 요청시킬수 있게 변경해야함.

     

 

6. Resource Server

실질적으로 요청이 들어오면 access_token을 확인 후 유효한지 체크 하고

요청에 알맞는 리소스를 response 해주는 서버

 

 

 

 

 

참조 출처

 

Oauth2의 암시적 허용

https://docs.microsoft.com/ko-kr/azure/active-directory/develop/v2-oauth2-implicit-grant-flow

 

JWT

https://velopert.com/2389

 

JWT 고려사항

https://mangkyu.tistory.com/56

 

OAUTH 토큰 보안

https://tansfil.tistory.com/58

'개발 > etc' 카테고리의 다른 글

네트워크 복습 1  (0) 2020.08.14
JUnit5 에서 parameter 사용하기  (0) 2020.07.21
Lombok  (0) 2020.07.19
어플리케이션 아키텍처와 객체지향 영상 후기  (0) 2020.06.28
blob  (0) 2020.04.30

www.notion.so/1-6e6df6111f574afa87c11b359b21b6ed

 

네트워크 복습 1

OSI 7계층

www.notion.so

 

OSI 7계층

  • 물리 계층
  • 데이터 링크 계층
  • 네트워크 계층
  • 전송 계층
  • 세션 계층
  • 프레젠테이션 계층
  • 어플리케이션 계층

어플리케이션 계층

  • 최종 사용자에게 네트워크 서비스를 제공하는 계층

  • 이 서비스들은 클라이언트가 사용하고 있는 데이터로 작업하는 프로토콜이다.

  • 이 프로토콜중 하나는 HTTP 이며 크롬, 파이어폭스 익스플로러와 같은 웹브라우저들과 같이 사용된다.

  • 다른 예들의 어플리케이션도 이 어플리케이션 계층을 사용하는데

  • office , outlook , skype 등이 있다.

  • 사용자와 직접 상호작용하는 계층이며 표현계층과 데이터를 주고 받는다.

프레젠테이션 계층

  • 어플리케이션 계층에서 받은 데이터 포맷을 다른 데이터 포맷으로 세션 계층포맷으로 변경하는 계층.

  • 또는 세션 계층에서 받은 데이터 포맷을 어플리케이션 계층 데이터 포맷으로 변경

  • 다양한 타입의 표현양식을 공통의 형식으로 변환시키는것.

  • 암호화 복호화 압축같은 기능도 제공.

세션 계층

  • 응용 프로그램 간의 연결을 성립하게 하고 연결이 안정되게 유지 , 관리 하며 작업 완료후 연결을 종료시키는 계층

  • 네트워크 중단이 발생한 경우는 인증과 재연결뿐만 아니라 여러 유형의 연결을 지원한다.

  • 세션이 설정 된후 데이터는 전송계층으로 이동 되거나 전송계층에서 전달된다.

전송 계층

  • 네트워크 연결을 통한 데이터 전송을 책임진다.

  • 이 계층은 전송해야 할 데이터 양, 전송 속도, 이동 위치, 이런 종류의 것들을 조정한다.

  • 인터넷 애플리케이션에 대해 가장 널리 알려진 프로토콜 들로 이 서비스는 "전송 제어 프로토콜" 또는 TCP와 "사용자 데이터그램 프로토콜" 또는 UDP에 의해 제공될 수 있다. 다른 프로토콜은 오류 복구, 데이터 흐름 및 재전송을 포함한 추가적인 기능을 제공할 수 있다.

  • 전송 계층이 그것의 기능을 완성하면, 데이터는 네트워크 계층으로 또는 네트워크 계층으로부터 전달된다.

네트워크 계층

  • 이 계층의 대표적인 프로토콜로는 IP 가 있다.

  • 전송 계층에서 만들어진 패킷을 전달 받아 목적지 컴퓨터의 논리적인 주소를 네트워크 계층의 헤더에 추가하는 역할

  • 데이터가 이 계층에 도착한 후, 데이터의 각 프레임을 조사하여 데이터가 최종 목표에 도달했는지 결론을 내린다. 이 계층은 송신 전송 시 데이터를 정확한 목적지로 전송하고 수신 전송도 수신한다.

  • 또한 이 계층은 IP 주소의 논리적 주소와 물리적 주소 간의 매핑을 관리하는데, 이는 주소 결정 프로토콜 또는 ARP를 통해 이루어진다.

데이터 링크 계층

  • 데이터 링크 계층은 네트워크 위의 개체들 간 데이터를 전달하고, 물리 계층에서 발생할 수 있는 오류를 찾아내며 수정하는 데 필요한 기능적·절차적 수단을 제공한다

  • 계층을 두는 목적은 간단히 말해서 잡음이 없는 인접한 노드 간의 물리적인 회선을 망계층(3 Layer)이 사용할 수 있도록 전송에러가 없는 통신 채널로 변화 시키는 것이다.

  • 궁극적으로 데이터 링크 프로토콜들은 인접하여 접속된 기기 사이의 통신을 관리하고, 신뢰하고 낮은 전송로를 신뢰도가 높은 전송로로 전환시키는데 주로 사용된다.

  • 물리적 네트워크를 통해 링크를 설정한다. 이 계층이 물리적 계층으로부터 데이터를 수신하면 전송 오류를 확인한 다음 데이터 프레임으로 비트를 패키징한다.

  • 이때 오류를 발견하면 재전송 기능으로 다시 전송해준다.

  • 여기서부터 이 계층은 MAC 또는 LLC 계층의 물리적 주소 지정 방법을 관리한다. MAC 계층의 예는 이더넷뿐만 아니라 802.11 무선 사양을 포함한다.

물리계층

  • 단말기기와 전송매체 사이의 인터페이스를 정의하고 데이터링크 계층 엔티티 간의 비트 전송을 위한 기계적, 전기적, 기능적, 절차적인 수단을 제공하는 계층을 말한다.
  • 디지털 데이터 비트를 소스 또는 송신 장치로부터 전송한다. 물리 계층, 전기, 기계 또는 라디오가 될 수 있는 네트워크 통신 매체를 통해 수신 또는 대상 장치로 전송한다.
  • 장비로는 허브, 리피터, 케이블 등이 있다.

 

 

참조

 

https://leejoongwon.tistory.com/31

https://winyong.tistory.com/37

https://m.blog.naver.com/PostView.nhn?blogId=yosi3world&logNo=50077248595

https://realpars.com/osi/

'개발 > etc' 카테고리의 다른 글

OAUTH - 1  (0) 2020.08.21
JUnit5 에서 parameter 사용하기  (0) 2020.07.21
Lombok  (0) 2020.07.19
어플리케이션 아키텍처와 객체지향 영상 후기  (0) 2020.06.28
blob  (0) 2020.04.30

노션 주소

www.notion.so/JUnit5-parameter-3c97b3d4318741bfb4eabb0f6c1f4eb7

 

pom.xml에 디펜던시 추가

<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params --> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-params</artifactId> <version>5.6.2</version> <scope>test</scope> </dependency>

등록 후 메소드 위에 @Test 대신 @ParameterizedTest 등록

Parameter가 1개일 경우

@ValueSource(strings = {"", ""})

@ValueSource(ints= {"", ""})

@ValueSource(boolean= {"", ""})

각자 type에 맞게 적용

Parameter가 2개 이상일 경우

@MethodSource 사용

@MethodSource 사용시 따로 팩토리 메소드를 만들어줘야한다.

private static Stream<Arguments> domainFreeTest() { return Stream.of( Arguments.of(0 , 0 , true), Arguments.of(100 , 0 , false), Arguments.of(0 , 100 , false) ); }

팩토리 메소드와 테스트 메소드의 메소드 이름이 같을경우에

@MethodSource에 따로 팩토리 메소드 이름을 안적어줘도 된다.

하지만 다를 경우엔 @MethodSource에 팩토리 메소드 이름을 적어줘야한다.

Parameter로 Enum을 사용할 경우

  • Enum 전체 사용시

@ParameterizedTest @EnumSource(Month.class) // passing all 12 months void getValueForAMonth_IsAlwaysBetweenOneAndTwelve(Month month) { int monthNumber = month.getValue(); assertTrue(monthNumber >= 1 && monthNumber <= 12); }

  • 특정 enum의 값만 사용시

@ParameterizedTest @EnumSource( value = Month.class, names = {"APRIL", "JUNE", "SEPTEMBER", "NOVEMBER", "FEBRUARY"}, mode = EnumSource.Mode.EXCLUDE) void exceptFourMonths_OthersAre31DaysLong(Month month) { final boolean isALeapYear = false; assertEquals(31, month.length(isALeapYear)); }

  • enum에 조건을 줄 경우

@ParameterizedTest @EnumSource(value = Month.class, names = ".+BER", mode = EnumSource.Mode.MATCH_ANY) void fourMonths_AreEndingWithBer(Month month) { EnumSet<Month> months = EnumSet.of(Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER, Month.DECEMBER); assertTrue(months.contains(month)); }

Paramter 에 주입할 소스를 csvfile로 사용할 경우

@ParameterizedTest @CsvFileSource(resources = "/data.csv", numLinesToSkip = 1) void toUpperCase_ShouldGenerateTheExpectedUppercaseValueCSVFile( String input, String expected) { String actualValue = input.toUpperCase(); assertEquals(expected, actualValue); }

  • csv파일 내용

input,expected test,TEST tEst,TEST Java,JAVA

  • 더 다양한 경우는 하단의 첨부한 출처에서 확인

Enum 부터 출처

'개발 > etc' 카테고리의 다른 글

OAUTH - 1  (0) 2020.08.21
네트워크 복습 1  (0) 2020.08.14
Lombok  (0) 2020.07.19
어플리케이션 아키텍처와 객체지향 영상 후기  (0) 2020.06.28
blob  (0) 2020.04.30

@EqualsAndHashCode 의 of를 사용하는 이유

상호 참조된 class가 필드로 등록되어 있을경우 중복으로 hashcode가 생성되어

stackoverflowerror가 발생하게 된다.

(무한 재귀로 hashcode가 생성됨)

lombok annotation을 custom 한 annotation을 만들어 줄이지 못하는 이유

lombok annotation은 meta annotation으로 작동하지 않기때문에 줄일수 없다.

spring이 제공하는 annotation들은 meta annotation으로 작동하기 때문에 가능함.

@Builder 사용시 @AllArgsConstructor이 필요한 이유

builder 사용시 객체를 생성할때 기본생성자가 모든 필드를 참조해야 만들수있는 생성자로 되어있는데 생성자의 접근제어가 default로 되어있어 외부에서 만들수가 없다. ( builder로 생성안할경우만)

그렇기때문에 AllargsConstructor와 noArgsConstructor을 추가해준다.

기본생성자와 모든 필드를 참조하는 생성자를 만들수 있게된다.

@Data 를 사용하지 않는 이유

@Data 사용시 equalsAndhashCode란 annotation이 포함되어 있는데 of를 사용하는 이유와 마찬가지로 상호참조로 인한 무한생성으로 stackoverflow error가 발생하고

마찬가지로 toString annotation에서도 위와 같은 이유로 stackoverflow error가 발생하게 된다.

'개발 > etc' 카테고리의 다른 글

OAUTH - 1  (0) 2020.08.21
네트워크 복습 1  (0) 2020.08.14
JUnit5 에서 parameter 사용하기  (0) 2020.07.21
어플리케이션 아키텍처와 객체지향 영상 후기  (0) 2020.06.28
blob  (0) 2020.04.30

유투브 조영호님의 강의 영상 후기

레이어 아키텍쳐

 

일반적으로 레이어 아키텍쳐는

 

프레젠테이션 ( 사용자 입력을 받는 부분 , 화면쪽)

도메인 ( 주요 로직)

데이터 소스 ( 디비쪽)

 

으로 나뉘고 주요 로직인 도메인 레이어가 가장 중요함.

 

도메인 레이어

 

이 도메인 레이어는 두가지 설계 방법이 있는데

  1. 절차지향 → (트랜잭션 스크립트 모델)
  1. 객체지향 → (도메인 모델)

두가지 방법이 있고 괄호안은 모델 패턴의 이름.

 

우리나라는 대부분 데이터와 로직이 나뉘어져 있는 절차지향.

 

절차지향

 

  1. 절차지향은 서비스에 주요로직이 있고 데이터 모델이 따로 있고 DAO를 통해서 데이터를 가져옴

→ 프로세스와 데이터가 나뉘어져 있음.

 

객체지향

2. 객체지향은 로직과 데이터모델이 하나로 존재함.

→ 프로세스와 데이터가 합쳐져있음. (객체)

→ 다른 객체( 프로세스와 데이터) 들과의 서로 상호작용 할수있는 구조.

 

객체지향 설계

CRC Card

책임과 협력을 표현하기 위한 객체지향 설계도구

C. Candidate = 역할 또는 객체

R. Responsibility = 객체가 맡은 역할 ( 로직 )

C. Collaborator = 객체가 맡은 역할을 수행하기 위해 필요한 객체

 

 

객체지향 설계 방법

  1. 로직을 수행할때 필요한 데이터들을 가장 많이 갖고있는 객체에 로직을 할당. ( creator 패턴)

    → 객체에 로직을 넣기 힘들경우 팩토리 객체를 만든다.

  1. 1번의 객체에 로직을 수행하는데 다른 데이터가 필요할 경우 다른 객체의 협력이 필요. ( 호출 )

 

 

객체지향 결론

절차지향에서 처럼 하나의 서비스에 모든 로직을 다 집어넣는것이 아닌

각각 알맞는 객체 ( 로직을 수행할 데이터를 가장 많이갖고있는 객체) 에 로직을 할당하며

객체간의 협력관계로 로직을 수행하는것.

 

 

도메인 레이어와 아키텍쳐

 

도메인 레이어를 어떻게 설정하느냐에 따라서 아키텍쳐가 조금씩 틀려진다.

 

1. 어플리케이션 플로우 로직

도메인 로직을 처리 하기 위한 전후 작업 ( 디비에 넣는다던지 , 푸쉬후 카톡이나 메신저에 전송할때)

어플리케이션 로직을 도메인 로직에 넣으면 의존성( 디비에 넣을땐 디비쪽 의존성)이 생기므로 테스트가 어려워지고 결합도가 높아지고 응집도가 떨어지므로 도메인 로직에 넣지 않음.

 

2.도메인 레이어 캡슐화

도메인과 관계없는 로직들은 접근 못하게 막아야한다.

 

3.서비스 레이어

그래서 나온것이 서비스 레이어.

어플리케이션 플로우 로직을 서비스 레이어에 넣는다.

 


프레젠테이션

서비스

도메인

데이터소스


 

도메인 레이어 위에 서비스 레이어가 붙는다.

 

서비스 레이어는 달라도 도메인 로직은 사용이 가능하므로 도메인 로직의 재사용성이 높아진다.

서비스 레이어가 시작할때 트랜잭션이 시작하고 서비스 레이어가 끝날때 트랜잭션이 끝난다.

 

 

데이터 소스 레이어

 

객체모델과 db스키마 사이의 불일치

객체 모델과 DB 스키마 사이의 불일치.

객체 패러다임과 관계 패러다임 간의 불일치.

 

데이터는 중복 제거하기 용이함.

객체는 유연하다. 수정이 쉽다.

 

객체지향적으로 볼수록 둘사이는 관점이 다르므로 불일치가 일어남.

이럴경우 datamapper를 두고 양쪽의 불일치를 해결하게함.

datamapper를 사용함으로써 객체와 데이터의 결합도를 낮춘다.

결합도가 낮으므로 서로가 다르게 발전함.

 

ORM

ORM = datamapper

대표적인 ORM = HIBERNATE , JPA

 

 

절차지향의 단점

 

1. 로직을 찾기가 힘들고 알아보기도 힘듬.

 

2.수정하기가 힘듬.

 

객체지향의 장점

 

1. 로직을 찾기도 쉽고 수정하기도 쉽다.

 

2. OCP open-closed principle

수정은 닫혀있지만 행동을 변경하고 확장하는것엔 열려있다.

추상화를 기준으로 분리.

 

3.dependency-inversion principle 의존성 역전 원칙

추상화를 기준으로 분리하면 상위 레벨의 모듈은 하위 레벨의 모듈에 의존성을 전혀 갖지 않는다.

의존성은 같은 레벨단계에서만 가짐.

 

의존성을 추상화로 향하게 하면 시스템의 확장성이 늘어남. ( 2020.06.28 확실하게 이해가 되진않음 )

 

4. 추상화를 이용한 효율적인 커뮤니케이션이 가능.

하이레벨모듈로만 얘기 가능하고 더 디테일하게 내려갈경우에 로우레벨모듈에 대한 설명이 가능하다.

 

계속해서 추상화를 만들다 보면 이것들이 모여서 도메인 레이어가 됨.

 

객체지향의 단점

객체지향으로 설계할때는 최대한 쉽게 로직을 짜야한다.

하지만 이런경우는 거의없다. 그래서 매번 리팩토링을 해야한다.

어느정도 방향성이 보이기 시작하면 그때부터 편해진다.

 

 

 

https://www.youtube.com/watch?v=26S4VFUWlJM&feature=youtu.be

 

2020.06.28 - 어느정도 윤곽과 개념이 잡힘.

'개발 > etc' 카테고리의 다른 글

OAUTH - 1  (0) 2020.08.21
네트워크 복습 1  (0) 2020.08.14
JUnit5 에서 parameter 사용하기  (0) 2020.07.21
Lombok  (0) 2020.07.19
blob  (0) 2020.04.30

blob 의 객체에 이미지 또는 동영상 등의 바이너리 데이터를 넣을수 있음.

그렇기 때문에 따로 파일을 보관 안해도됨.

 

장점은 데이터 정보 , url 등을 숨길수 있으며

createBlobUrl로 blob url을 생성시킨 후 쓸모가 없어진 url을

revokeObjectUrl로 삭제시킬수가 있음.

( createBlobUrl로 생성한 url은 자동으로 삭제되지 않으므로

revokeObjectUrl로 삭제시켜야함)

 

blob객체는 slice 해서 부분부분 가져올수 있으며

바이너리 데이터를 읽고 싶은 경우는 FileReader 객체를 사용하면 된다.

 

blob url은 src url처럼 사용하면 된다.

 

그리고 blob url은 생성한 window가 아닌 다른 widow에서 작동하지 않는다.

 

 

api정리 잘된곳

https://developer.mozilla.org/ko/docs/Web/API/Blob

 

Blob

Blob 객체는 파일류의 불변하는 미가공 데이터를 나타냅니다.

developer.mozilla.org

 

 

 

'개발 > etc' 카테고리의 다른 글

OAUTH - 1  (0) 2020.08.21
네트워크 복습 1  (0) 2020.08.14
JUnit5 에서 parameter 사용하기  (0) 2020.07.21
Lombok  (0) 2020.07.19
어플리케이션 아키텍처와 객체지향 영상 후기  (0) 2020.06.28

+ Recent posts