목록Spring (72)
똑같은 삽질은 2번 하지 말자
개인 프로젝트를 하면서 업무를 할 때 처럼 로그들을 남겨보려다...... 생각보다 술술 잘 안되서 개념을 한번 정리해보고자 한다. 로거 vs 로깅 퍼사드 로깅 퍼사드 로거를 자유롭게 교체하기 위해 쓰는 친구 Commons Logging, SLF4j 이 있다. 로거 JUL, Log4J2 로그를 찍는 친구들 Spring은 기본적으로 Commons Logging 을 쓴다고 한다. but 어찌됬든 위 사진을 보면 logback은 slf4j의 구현체 이며, log4j를 쓰든 JUL을 쓰든 로그는 Logback 로거로 찍힌다. 그럼 Logback 설정 파일을 만들어서 커스텀화를 해보자 logback-spring.xml 나의 기본 패키지 logging 레벨을 DEBUG로 설정한 것이다. 이 설정 파일을 이용하면 아주..
Lombok(롬복)을 사용하는 이유 ? 밑의 사진을 보면 코드가 상당히 짧고 읽기 쉽지만, 롬복을 사용 안하고 직접 코드로 구현하려고 한다 하면? 이렇게 애노테이션들을 코드로 다 구현한 것도 아닌데, 이미 코드가 상당히 길어지고 있다. 여기서 이 클래스에 비지니스 로직이라도 들어있으면 점점 코드는 길어져서 가독성이 떨어진다. 그러므로 우리는 롬복이라는 친구를 사용하고 있다. 그럼, Lombok은 어떻게 동작하는 걸까? Lombok은 컴파일 시점에 애노테이션 프로세서를 사용하여 소스코드의 AST(abstract syntax tree)를 조작한다. 애노테이션 프로세서 문서 https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/Proces..
@ControllerAdvice, @RestControllerAdvice 둘다 @Component이기 때문에 자동으로 빈으로 등록되며, 기본적인 차이는 @Controller @RestController 의 차이와 비슷하다고 생각한다. ArrayIndexOutOfBoundsException이 발생하면 내가 만든 커스텀 핸들러로 처리를 한다. AppError 객체는 에러내용을 담기위해 임시로 만들어준 클래스 @RestControllerAdvice public class GlobalExceptionController { @ExceptionHandler(ArrayIndexOutOfBoundsException.class) public ResponseEntity AIOOBHandler(ArrayIndexOutOfB..
1. 기본적인 동적 쿼리 SELECT * FROM KH.EMPLOYEE WHERE ${searchType} = #{keyword} SELECT * FROM KH.EMPLOYEE WHERE ${searchType} = #{keyword} map 형식으로 검색 타입과 키워드를 받아와서 처리했다. WHERE 절에서 검색 타입은 ${ } 로 전달하며 키워드는 #{ } 로 전달한다. ${ } 는 파라미터 값이 그대로 들어가며 #{ } 는 파라미터 값이 ' ' 으로 감싸진다. 달라지는 검색 조건에 대응할 수 있다. 2. if문을 이용한 동적 쿼리 SELECT * FROM EMPLOYEE WHERE 1=1 AND NAME LIKE '%' || #{keyword} || '%' AND GENDER = #{gender} ..
https://docs.spring.io/spring-restdocs/docs/2.0.2.RELEASE/reference/html5 Spring REST Docs Document RESTful services by combining hand-written documentation with auto-generated snippets produced with Spring MVC Test. docs.spring.io REST Docs -> 테스트를 하면서 문서 조각(snippets)를 만들 수 있으며, 이것들을 모아 문서화를 할 수 있다. 의존성은 프로젝트를 생성할 때 이미 추가했기 때문에 추가할 필요는 없고, REST Docs를 적용하기 위해서는 @AutoConfigureRestDocs 어노테이션을 추가하면..
HATEOAS 란? 어떤 계좌를 조회하는 요청이 있다. GET /accounts/12345 HTTP/1.1 Host: bank.example.com Accept: application/vnd.acme.account+json 그에 대한 응답 HTTP/1.1 200 OK Content-Type: application/vnd.acme.account+json Content-Length: ... { "account": { "account_number": 12345, "balance": { "currency": "usd", "value": 100.00 }, "links": { "deposit": "/accounts/12345/deposit", "withdraw": "/accounts/12345/withdraw", ..
지정된 값 이외의 값이 들어왔을때, 지정된 값이 들어오지 않았을 때 @Test public void createEvent_is_BadRequest() throws Exception { Event event = Event.builder() .id(100) // 들어오면 안되는 값 .name("Spring") .description("REST API") .beginEnrollmentDateTime(LocalDateTime.of(2020,6,28,14,11)) .closeEnrollmentDateTime(LocalDateTime.of(2020,6,29,14,11)) .beginEventDateTime(LocalDateTime.of(2020,6,30,14,11)) .endEventDateTime(LocalDat..
도메인 구현 @Builder @AllArgsConstructor @NoArgsConstructor // public default 생성자 @Getter @Setter // @Data에는 EqualsAndHashCode가 기본적으로 정의되어있어서 겹침 @EqualsAndHashCode(of = "id") // 기본적으로 객체의 모든 필드로 Equals, HashCode를 비교하는데 그럼 // 나중에 연관관계에서 (상호참조하는) StackOverFlow가 발생할 수 있으므로 ID로만 비교한다. public class Event { private Integer id; private String name; private String description; private LocalDateTime beginEnro..
https://www.youtube.com/watch?v=RP_f5dMoHFc 영상의 내용을 간략히 하면 현재 REST API라고 주장하는 REST API들은 조건들을 만족하지 않는다. 이다. 그럼 어떤 조건들을 만족하지 않는가? 1. Self-Describtive Message 2. HATEOAS(Hypermedia as the engine of application state) 이 두가지를 모두 만족하는 REST API는 드물다고 하신다. Self-descriptive message 메시지 스스로 메시지에 대한 설명이 가능해야 한다. 서버가 변해서 메시지가 변해도 클라이언트는 그 메시지를 보고 해석이 가능하다. 확장확장 가능한 가능한 커뮤니케이션 커뮤니케이션 HATEOAS 하이퍼미디어(링크)를 통해 ..
select * from board SELECT P.* FROM (SELECT * FROM BOARD WHERE B_TITLE LIKE CONCAT('%',#{searchKeyword},'%') ORDER BY B_CODE ASC) AS P LIMIT #{perPageNum} OFFSET #{pageStart} select count(*) from board INSERT INTO BOARD(b_title,b_content,b_writer,b_kind) VALUES( #{b_title}, #{b_content}, #{b_writer}, #{b_kind, typeHandler = org.apache.ibatis.type.EnumOrdinalTypeHandler} ) DELETE FROM BOARD WHERE..