본문 바로가기
Memo/우테코 4기

[우테코] Spring 체스 미션 1~2 단계 학습 로그

by 연로그 2022. 5. 2.
반응형

목차

1. GitHub 저장소

2. 요구사항

3. 공부한 개념들

4. 피드백

5. 셀프 회고


 

 


1. GitHub 저장소

1단계 Repository: https://github.com/yeon-06/jwp-chess/tree/step1

1단계 Pull Request: https://github.com/woowacourse/jwp-chess/pull/331

2단계 Repository: https://github.com/yeon-06/jwp-chess/tree/step2

2단계 Pull Request: https://github.com/woowacourse/jwp-chess/pull/422

 


2. 요구사항

 

img: https://pixabay.com

 

1단계 요구사항

  • 스프링 애플리케이션으로 체스 실행
  • Spring MVC를 활용 (Spark 대체)
  • JdbcTemplate 활용 (기존의 Connection 직접 생성 로직 대체)
  • 요청 받기: @Controller / @RestController 활용

 

2단계 요구사항

  • 체스방 생성
    • 제목, 비밀번호 입력받기
    • 생성 시 만들어지는 고유값은 url에 활용
  • 체스방 목록 조회
    • 제목 클릭 시 체스방 참가
    • 삭제 버튼 클릭 시 체스방 삭제
      • 비밀번호 입력받기
      • (e) 진행중인 체스방은 삭제 불가능
      • 동일한 비밀번호라면 삭제

 

 


3. 공부한 개념들

 

3-1. JdbcTemplate

 

[JDBC] JDBC가 등장한 이유

목차 1. JDBC 등장 배경 2. JDBC란 3. 표준화의 한계 4. JDBC와 최신 기술 👨‍💻 JDBC 등장 배경 애플리케이션을 개발할 때 중요한 데이터는 대부분 DB에 저장된다. 클라이언트가 DB를 호출하려면 아래

yeonyeon.tistory.com

 

3-2. @ExceptionHandler 사용하기

  • 각 예외마다 처리 방법 변경하기

 

👉 https://yeonyeon.tistory.com/218

 

[Spring] @ExceptionHandler로 API 예외 한번에 처리하기

목차 1. 서론 2. @ExceptionHandler 3. 상태 코드 바꾸기 4. Exception 한꺼번에 처리하기 5. 모든 Controller에 적용시키기 🙋‍♀️ 서론 API를 호출하다 보면 예외가 많이 발생된다. controller에서 처리하려고.

yeonyeon.tistory.com

 

3-3. 의존성 주입 방법

  • 의존성 주입 방법 3가지
  • 의존성 주입을 여러개 만든 경우, Spring은 어느 것을 사용할까?
  • 생성자 주입이 가장 좋은 이유

 

👉 https://yeonyeon.tistory.com/220

 

[Spring] 생성자 주입 vs 필드 주입 vs 수정자 주입

의존성 주입; Dependency Injection Spring에서 의존성을 주입하는 방법은 3가지가 있다. 생성자 주입; Constructor Injection 필드 주입; Field Injection 수정자 주입; Setter Injection 결론부터 말하자면 '생..

yeonyeon.tistory.com

 

3-4. @RequestBody의 매핑 과정

  • @RequestBody 사용 시 빈 생성자가 필요한 이유
  • @RequestBody의 객체 변환 과정
  • ObjectMapper의 객체 변환 과정

 

👉 https://yeonyeon.tistory.com/221

 

[Spring] @RequestBody가 빈 생성자가 필요한 이유 (hint. ObjectMapper)

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `클래스명` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delega..

yeonyeon.tistory.com

 

3-5. 에러 페이지 커스텀하기

ErrorController를 활용해 에러 페이지를 내가 지정한 페이지로 설정했다.

error.hbs라는 페이지로 이동하기 위해 "error"를 반환했는데 JSON 등으로 반환하는 것도 가능하다.

@Controller
public class CustomErrorController implements ErrorController {

    @RequestMapping("/error")
    public String handleError() {
        return "error";
    }
}

 

사실 이 부분에 대해서는 @ExceptionHandler 써도 되지 않냐고 StackOverflow에서 그러던데... 페이지를 찾을 수 없는 경우에 내가 만든 페이지를 보여주고 싶었던거라 내 의도대로 동작할지는 잘 모르겠다. 🤔 (테스트 해봤을 때는 안되던데.. 뭔가 잘못 테스트했을지도..) 따로 공부해보고 정리해야겠다.

 

resources/error 폴더상태코드 이름으로 파일을 만들면 해당 페이지가 반환된다.
ex: resourcses/error/404.hbs

application.properties에서 별도 설정을 하면 위치 변경도 가능하다는데...
관련 부분도 함께 추가 공부할 때 적어보겠다. 방법을 알려준 매트 감사합니다~~~!

 


4. 피드백

🙋‍♀️: 본인(연로그), 🙍‍♂️: 리뷰어(미르)

 

4-1. @Transactional 활용하기

🙋‍♀️ 여러 쿼리문을 실행시키는 경우 하나의 쿼리라도 실패하면 다른 쿼리들을 통한 DB 변경 사항도 롤백되도록 @Transactional을 활용하였습니다!

 

🙍‍♂️ (select만 하는 경우) 트랜잭션의 read only 속성을 사용해보는 건 어떨까요?

🙋‍♀️ 제가 공부하면서 이해하기로는 @Transactional은 트랜잭션의 단위를 메서드로 지정할 수 있게 도와주는 어노테이션인 것 같아요! 여기서 한가지 궁금한 점이 생겼습니다. @Transactional을 기입하지 않는 경우에 여러번 쿼리문을 실행하면 모두 다 다른 트랜잭션을 통해 실행되나요? 이 부분을 디버깅 / 콘솔에 print하며 확인해볼 방법이 있을까요?

 

🙍‍♂️ 우선 @Transaction이 없다면, Application에선 확인을 할 수 없을거예요. Application에서 따로 설정하지 않았으니 DB의 기본 Transaction전략을 따를거예요..! @Transactional을 있는 경우도 확인을 할 수 있을지 잘모르겠네요 😂 propagation을 확인해본다면 다른 트랜잭션으로 동작하는지 아닌지 생각할 수 있을 것 같아요!

저도 연로그의 질문을 받아 DB에서 처음으로 확인을 해봤네요 ㅎ_ㅎ.. performance_schema DB에서 확인해보면 될 것 같아요! Application에선 PlatformTransactionManager로 확인을 해보려 했는데 생각대로 나오지 않네요.. 😭

 

👉 이 부분에 대해서는 더 찾아보고 따로 정리할 예정

 

4-2. 테스트 코드용 DB 테이블 생성하기

Special Thanks to 오찌 & 스컬
요 방법을 알려주신 덕분에 코드가 깔끔해졌어요^ㅡ^)b

Dao에 대한 테스트 코드를 작성하려고 한다.

기존에는 테스트코드 실행할때마다 @BeforeEach를 통해 drop table, create table, insert data의 작업을 거쳤다.

테스트 코드에서 테이블을 자동으로 생성해주는 방법에 대해 알게 되어 정리한다.

 

test에 별도로 resources 폴더를 만든다.

 

application.properteis에 아래와 같은 속성을 주고

spring.sql.init.platform=test
spring.sql.init.platform: 기본 스키마 또는 데이터 스크립트 위치 schema-${platform}.sql 및 data-${platform}.sql에서 사용할 플랫폼. (출처: https://runebook.dev/ko/docs/spring_boot/application-properties)

 

  • shcema.sql을 생성해 테스트 코드 실행 시 테이블을 drop & create 해준다.
  • data.sql을 이용해 insert할 데이터 등을 삽입한다.

 

4-3. 쿼리 실행 결과가 없으면 무엇을 반환해야 할까?

queryForObject는 query와는 다르게 조회 결과가 없으면 Exception이 발생한다.

이를 try-catch로 감싸서 null을 반환했는데 null을 반환이 너무 불편했다.

(API를 호출하는 쪽에서 null 처리를 해줘야하기 때문에)

try {
    return jdbcTemplate.queryForObject(sql, paramSource, rowMapper);
} catch (EmptyResultDataAccessException e) {
    return null;
}

 

🙍‍♂️: 반환을 꼭 해야할까하는 생각이드네요 ㅎ_ㅎ..

만약 에러가 발생하는거라면 에러를 발생해도 괜찮지 않을까요?

 

👉 해당 의견에 동의하고 ExceptionHandler로 처리하도록 변경

@ExceptionHandler
public ResponseEntity<String> handleException(EmptyResultDataAccessException e) {
    logger.error(EMPTY_STRING, e);
    return new ResponseEntity<>(NO_DATA_EXCEPTION_MESSAGE, HttpStatus.NOT_FOUND);
}

 

4-4. e.printStackTrace() 사용

오류가 발생하는 경우 콘솔에서 찾기 편하게 하기 위해 e.printStackTrace()를 사용했다.

미르가 SLIPP의 한 글을 알려주시면서 다른 방법을 생각해볼 것을 제안해주셨다.

 

e.printStackTrace()는 {TOMCAT_HOME}/logs/catalina.out에만 기록이 남는다.

직접 로그 파일을 관리하기 위해서 Log4j나 Slf4j 같은 로깅 프레임워크를 사용하는 것이 좋다.

 

4-5. @PathVariable 적극 활용하기

@PathVariable로 가져올 수 있는 값을 DTO에 넣어서 @RequestBody로 가져오는 부분이 있었다.

큰 의미가 있는건 아니고 DTO에 한번에 넣어서 보내면 편하겠지~ 라는 생각에서 아래와 같은 코드가 발생했다.

@DeleteMapping("/{id}")
public void delete(@RequestBody DeleteGameRequest deleteGameRequest) {
    // ...
}
public class DeleteGameRequest {
    private int id;
    private String title;
    private String password;
    // ...
}

 

🙍‍♂️: 객체안에 있으면, 가독성이 떨어진다고 생각하는데 연로그의 생각은 어떤가요?

PathVariable 관련 내용을 사용했는지 사용하지 않았는지 한눈에 알기 어렵다고 생각해요!
기존 도메인을 파악할 때, 탐색을 한 단계라도 줄이기 위해 저는 따로 사용하는 편입니다 😄

 

👉 이에 동의하고 @PathVariable을 통해 id 값 불러옴

 


5. 셀프 회고

Twitter @painter_of_100

 

 이번 미션은 1, 2단계를 나누기 애매해서 같이 정리하게 되었다. 미션 자체는 어렵지 않았으나 프런트 화면을 건드리거나 Spring의 새로운 개념들을 익히는게 어려웠다. Java를 1시간 하면 Javascript를 3시간 하는 기묘한 현상이....^ㅡ^...... 1단계를 빠르게 끝내줄 수 있게 도와준 페어 정에게 Special Thanks... 덕분에 2단계 할 시간을 더 벌었어요

 

 브리의 갓 강의를 통해 Spring의 이런저런 기능을 맛보기 해봤지만 이를 실제로 내 프로젝트에 적당한 것을 선택해 적용시키는 것은 너무 헷갈리는 일이었다. 나중에 실무에서도 이런 기능들도 사용하게 될까? 아직은 배우는 단계라 잘 모르겠다. 레거시든 뭐든 JdbcTemplate도 많이 쓰려나... MyBatis를 쓸 것 같기도 하고?🤔

 

 공부할 키워드가 너무 많다. @Transactional, 커스텀 에러 페이지, @ComponentScan, Java vs Spring bean... 스터디를 별로 신청 안한게 그나마 다행이다. HTTP도 공부해야 하는데^-T.... 공부+운동을 병행하는게 너무 어렵다 여태는 온라인이라 가능했던거구나... 선릉에서 살고싶다... 의식의 흐름...

 

 내일 새 페어와 함께 미션하게 될텐데 막막하다. 페어 기간이 짧아서 걱정된다ㅠㅠ 미래의 제 페어 잘 부탁드려요..

반응형