[Routine] 13 주차 시작!

[Routine] 13 주차 시작!

2023년 4월 10일 부터 4월 16일 까지의 나의 루틴.

#목차

2023-04-10

  • 오늘도 어김없이 영한 님과, 동욱 님과 함께 출근하였다.
  • 요새 동욱 님의 책을 보는데, TDDSpring Security, GoogleNaverID, PW를 활용한 인증 절차인 OAuth 사용 방법을 읽고 있다.
  • 내가 회사에서 할 땐 엄청 어려웠던 거 같은데, 역시 고수분들이 하는 건 엄청 쉽게 하는 거 같은 느낌이 든다.
  • 결국 반복의 중요성 같다.
  • 해당 내용을 나의 사이드 프로젝트에 적용시켜야겠다.

2023-04-11

  • 오늘도 어김없이 영한 님과, 향로 님과 함께!

HelloControllerTest로 알아보는 Test 어노테이션

//@RunWith(StringRunner.class)  // JUnit4 버전 <-> JUnit5 버전 @ExtendWith(SpringExtension.class)
@ExtendWith(SpringExtension.class) // 1) JUnit5 버전 <-> JUnit4 버전 //@RunWith(StringRunner.class) 
@WebMvcTest(controllers = HelloController.class) // 2)
public class HelloControllerTest {
    @Autowired // 3)
    private MockMvc mvc; // 4)
    
    @Test
    public void hello가_리턴된다() throws Exception {
        String hello = "hello";
        mvc.perform(get("/hello"))  // 5)
                .andExpect(status().isOk()) // 6)
                .andExpect(content().string(hello)); // 7)
    }
}
  1. @ExtendWith(SpringExtension.class) : JUnit5에서 @RunWith(StringRunner.class)@ExtendWith(SpringExtension.class)로 바뀌었다.
    • @RunWith(StringRunner.class) : JUnit4에서 사용
      • 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행
      • 여기서는 SpringRunner라는 스프링 실행자를 사용
      • 즉, 스프링 부트 테스트JUnit 사이에 연결자 역할
  2. @WebMvcTest
    • 여러 스프랭 테스트 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션.
    • 선언할 경우 @Controller, @ControllerAdvice등을 사용할 수 있다.
    • 단, @Service, @Component, @Respository등은 사용할 수 없다.
    • 여기서는 Controller만 사용하기 때문에 선언
  3. @Autowired : 스프링이 관리하는 빈(Bean)을 주입
  4. private MockMvc mvc;
    • Web API를 테스트 할 때 사용
    • 스프링 MVC 테스트의 시작점
    • 이 클래스를 통해 HTTP GET, POST등에 대한 API테스트
  5. mvc.perform(get("/hello"))
    • MockMvc를 통해 /hello 주소로 HTTP GET 요청
    • 체이닝이 지원되어 아래와 같이 여러 검증 기능을 이어서 선언
  6. .adnExpect(status().isOk())
    • mvc.perform의 결과를 검증
    • HTTP HeaderStatus를 검증
    • 우리가 흔히 알고 있는 200, 404, 500등의 상태를 검증
    • 여기선 OK 즉, 200인지 아닌지를 검증
  7. .adnExpect(content().string(hello))
    • mvc.perform의 결과를 검증
    • 응답 본문의 내용을 검증
    • Controller에서 "hello"를 리턴하기 때문에 이 값이 맞는지 검증

Commit with 60~65p test 코드의 어노테이션 설명 및 테스트

2023-04-12

  • 오늘도 어김없이 영한 님과, 향로 님과 함께!
  • 오늘 향로님의 책을 읽고 테스트하는 도중 gradle 버전에 따른 lombok 이슈를 발견하였다.

// file: "build.gradle"
dependencies {
   // Gradle 5.x 미만
   // implementation 'org.projectlombok:lombok'
   // Gradle 5.x 이상
   compileOnly 'org.projectlombok:lombok'
   annotationProcessor 'org.projectlombok:lombok'
}
  • 위 코드 처럼 gradle 버전에 따른 Lombok 설정이 다르다.
  • gradle 버전 확인은 터미널에서 ./gradlew --version로 확인 가능하다.

Commit with 66~77p 롬복설정 및 dto 테스트

2023-04-13 스터디 발표

  • 오늘도 어김없이! 영한 님, 동욱 님과 함께!

spring boot 프로젝트에 인메모리형 데이터베이스 h2 추가


// file: "build.gradle"
dependencies {
   // JPA 설정
   implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

   // h2 database
   runtimeOnly 'com.h2database:h2'
}
  • 위 스프링 버전과 gradle 버전에 따른 jpa 설정 방법과 h2 database 설정 방법이 다를 수 있다.

자바빈 규약의 Getter/Setter

  • 자바빈 규약을 생각하면서 getter/setter를 무작정 생성하는 경우가 있는데, 이렇게 되면 해당 클래스의 인스턴스 값들이 언제 어디서 변화하는지 코드상으로 명확하게 구분할 수가 없어, 차후 기능 변경 시 정말 복잡해진다.
  • 그래서 Entity 클래스에서는 절대 Setter 메서드를 만들지 않는다.
  • 대신, 해당 필드의 값 변경이 필요하면 명확히 그 목적과 의도를 나타낼 수 있는 메서드를 추가해야만 한다.
// file: "자바빈 규약의 잘못된 예.java"
public class Order {
    public void setStatus(boolean status) {
        this.status = status;
    }
}

public void 주문서비서의_취소이벤트() {
    order.setStatus(false);
}
  • 위 코드는 setter 메서드를 이용하여 status의 값을 직접 변경하고 있다.
  • 이러한 코드는 추후 값들이 변경 될 때마다 다른 쪽에서 사용할때 엉뚱한 값이 나타낼 수 있는 이슈가 발생하게 된다.
  • 특히 중요한 결제와 같은 돈에 관련된 문제가 발생할 수 있기 때문에 주의해야 한다.
// file: "자바빈 규약의 올바른 사용 예.java"
public class Order {
   public void cancelOrder() {
       this.status = false;
    }
}

public void 주문서비서의_취소이벤트() {
   order.cancelOrder();
}
  • 그렇다면 위 문제 Setter가 없는 상황에서 어떻게 값을 채워 DB에 삽입(insert)을 해야 할까?
  • 기본적인 구조는 생성자를 통해 최종값을 채운 후 DB에 삽입하는 것이며, 값 변경이 필요한 경우 해당 이벤트에 맞는 public 메서드를 호출 하여 변경하는 것을 전제로 한다.
  • 또 다른 방법은 @Builder를 통해 제공되는 빌터 클래스를 사용하게 된다.
  • 생성자나 빌더나 생성 시점에서 값을 채워주는 역할은 똑같지만, 생성자의 경우 지금 채워야 할 필드가 무엇인지 명확히 지정할 수 가 없다.
// file: "생성자의 경우 지금 채워야할 필드가 무엇인지 명확히 지정할 수 없는 문제.java"
public class ExampleCode {
    public Example(String a, String b) {
        this.a = a;
        this.b = b;
    }
}
// file: "@Builer를 사용하여 어떤 값을 채워야 할지 명확하게 인지.java"
public class ExampleCode {
    public Example ex() {
        return Example.builder()
                .a(a)
                .b(b)
                .build();
    }
}
  • JpaRepository<Entity 클래스, PK 타입>를 상속하면 기본적인 CRUD 메서드가 자동으로 생성
  • @Repository를 추가할 필요도 없다.
  • 주의!
  • Entity 클래스와 기본 Entity Repository는 함께 위치해야 하는 점.
  • 둘은 아주 밀접한 관계이고, Entity 클래스는 기본 Repository 없이는 제대로 역할을 할 수 가 없다.
  • 나중에 프로젝트 규모가 커져 도메인별로 프로젝트를 분리해야 한다면 이때 Entity 클래스와 기본 Repository는 함께 움직여야 하므로 도메인 패키지에 함께 관리하게 된다.

  • 예를 들어 new Example(b, a)처럼 ab의 위치를 변경해도 코드를 실행하기 전까지는 문제를 찾을 수 없는 문제가 발생한다.
  • 하지만 @Builder를 사용하게 되면 어느 필드에 어떤 값을 채워야 할지 명확하게 인지 할 수 있다.


스터디 발표

  1. 승연씨 - OSI 7 계층 TCP/IP
    • 4계층 : Application Layer
    • 3계층 : Transport Layer
      • LISTEN : 열려 있음(=/= 통신중) 즉, 응답 대기 상태
      • ESTABLISHED : 통신중 즉, 상호 연결상태
      • CLOSED : 연결이 끊어짐
      • SYS-SENT : 연결을 요청한 상태
      • SYN_RECEIVED : 연결 요청에 응답후 확인을 기다리고 있음
      • TIME_WAIT : 연결은 종료되었으나 원격의 수신 보장을 위해 기다리고 있는 상태
      • netstat –an | grep LISTEN (현재 열려있는 모든 포트)
      • netstat –an | grep ESTABLISHED | wc –l (모든 서비스 동시 접속자 수)
      • netstat –an | grep :80 | ESTABLISHED | wc –l (웹 동시 접속자 수)
      • netstat –an | grep –E “포트번호|포트번호|….” (원하는 포트의 네트워크 상태만 보고 싶을 때 사용)
    • 2계층 : 인터넷 계층
    • 1계층 : 네트워크 계층(링크)
      • NIC 장치를 통해 이더넷의 주소를 뽑아낸 것이 MAC 주소이다.
  2. 코드 지우개 - 람다식
    • @FunctionalInterface -> @FunctionalInterface 어노테이션을 사용하면 하나의 추상 메소드만 가지는지 컴파일러가 체크하도록 하여 두 개 이상의 추상 메소드가 선언되어 있으면 컴파일 오류를 발생시킨다.
    • jquery 이벤트 함수 연속 호출

2023-04-14

  • 오늘도 어김없이! 영한 님, 동욱 님과 함께!

@Transactional 이란

  • @Transactional이 붙은 메서드는 메서드가 포함하고 있는 작업 중에 하나라도 실패할 경우 전체 작업을 취소한다.
  • Test 환경에서의 (TestTransaction.제공메서드)는 메서드가 종료될 때 자동으로 RollBack 된다.

2023-04-15


JPA Auditing이란

  • JPA가 createDate, modifyDate를 자동으로 설정해주게 된다.

2023-04-16

스프링 부트와 AWS로 혼자 구현하는 웹 서비스

  • 해당 책에서는 mustache를 이용하여 view를 구성하지만 thymeleaf를 사용하여 view를 구성 할 예정.

Back to [Routine] 12 주차 시작!

Continue with [Routine] 14 주차 시작!