Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

forDevLife

[TIL]9/13(3일차) 본문

각종 회고

[TIL]9/13(3일차)

JH_Lucid 2021. 9. 13. 19:07

Springboot 2 기초


 

@ConfigurationProperties 어노테이션 사용중 갑작스러운 빨간알림 발생

-> dependencies { annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" } 해결

 

- LOMBOK cannot find symbol 에러

위 두 개 추가 필요

 

- POJO(Plain Old Java Object) : Java EE 같은 특정 프레임워크에 종속적이지 않은 자바 객체

 

- @ConfigurationProperties : application.yml에서 테스트 프로퍼티 추가 후 prefix를 통해 지정된 클래스에서 프로퍼티를 매핑할 수 있게 한다.

 


- Spring Boot auto-configuration(자동 환경 설정) : 스프링 부트의 장점이며, 매우 중요한 역할을 함. Web, H2, JDBC를 비롯한 약 100여개의 자동 설정을 제공한다. 새로 추가되는 라이브러리(JAR) 또한 스프링 부트 auto config를 통해 설정이 자동 적용된다. 

만약 H2 의존성이 클래스 경로에 존재한다면 자동으로 인메모리 데이터베이스에 접근한다. 

 

-> 이러한 설정은 @EnableAutoConfiguration(@Configuration 함께 사용 필요) 또는 이를 포함하는 @SpringBootApplication 중 하나를 사용하면 된다.

 

 

- @SpringBootApplication은 @SprigBootConfiguration + @EnableAutoConfiguration + @ComponentScan의 조합이다. 

@SpringBootApplication 구성

 

 

- @EnableAutoConfiguration

자동 설정을 지원해주는 어노테이션은 @Import안의 AutoConfig~이다. 이걸 더 자세히 살펴보자.

 

 

- AutoConfigurationImportSelector.class

AutoConfigurationImportSelector 내의 selectImports 메서드

- AutoConfigurationImportSelector 클래스는 DeferredImportSelector 인터페이스를 구현한 클래스로 오버라이드 받은 selectImports() 메서드가 자동 설정할 빈을 결정한다. 

 

 

- 모든 후보 빈을 불러온다. (META-INF/spring.factories에 정의된 자동 설정할 클래스들을 먼저 불러온다.)

 

spring-boot-autoconfigure에 정의되어 있다.

* spring.factories : 자동 설정 타깃 클래스 목록. 즉, 이곳에 선언되어 있는 클래스들이 @EnableAutoConfiguration 사용 사 자동 설정 타깃이 된다.

* spring-configuration-metadata.json : 자동 설정에 사용할 프로퍼티 정의 파일이다. 미리 구현되어 있는 자동 설정에 프로퍼티만 주입시켜주면 된다. 따라서 별도의 환경 설정 필요 없다.

* org/springframework/boot/autoconfigure : 미리 구현해놓은 자동 설정 리스트이다. 이름은 '{특정 설정의 이름}AutoConfiguration' 형식으로 되어있다. 예로, H2ConsoleAutoConfiguration과 같다.

 

 

- 예를 들어 H2를 자동 설정한다고 가정한다.

1. 먼저 spring.factories에서 자동 설정 대상에 되는지 확인한다.

자동 설정 대상인것 확인

2. spring-configuration-metadata.json에서 주요 프로퍼티 값들은 무엇이고, 어떤 타입으로 설정할 수 있는지 확인한다.

콘솔 경로 프로퍼티 정보 확인

 

3. application.properties 혹은 application.yml에서 위를 참고해서 해당 프로퍼티를 직접 변경 가능하다.

spring.h2.console.path=/h2-test

위와 같이 프로퍼티 값을 추가하는 것만으로 자동 환경 설정에 자동으로 적용되어 애플리케이션이 실행된다.

 

 

+ https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties

 

Common Application Properties

 

docs.spring.io

스프링 프로퍼티 문서를 사용해서 더 쉽게 프로퍼티 값을 확인 / 변경할 수 있다.

 

 


- 자동 설정 어노테이션 살펴보기

 

스프링 부트는 자동 설정이 적용되는 조건, 시점 등에 따라 다양한 어노테이션을 지원한다. 이를 통해 설정 관리 능력을 향상시킬 수 있다. 

 

- 자동 설정을 위한 조건 어노테이션 : 조건을 만족하면 자동 설정이 적용된다. (@ConditionalOn~)

- 자동 설정을 위한 순서 어노테이션 : 지정한 특정 자동 설정 클래스들이 적용된 이후 혹은 이전에 해당 자동 설정 적용(@AutoConfigure~)

 

H2ConsoleAutoConfiguration 클래스 예시

1. ConditionalOnWebApplication(type = Type.SERVLET) : 웹 어플리케이션일때 적용

2. ConditionalOnClass(WebServlert.class) : WebServlet.class가 클래스 패스에 있을 때

3. ContitionalOnProperty : spring.h2.console.enabled가 true일 때

4. AutoConfigureAfter(~) : 지정한(~) 특정 자동 설정 클래스들이 적용된 후에 해당 자동 설정 적용

5. EnableConfigurationProperties(~) : 자동 설정 프로퍼티가 적용될 때 H2ConsoleProperties 클래스 타입으로 H2 관련 프로퍼티 값을 매핑해서 사용하게 된다.

+ 스프링 프레임워크에서는 일일이 설정했어야 했는데, 부트에서는 이처럼 스프링 개발자가 미리 설정한 방식으로 애플리케이션에 적용하게끔 정의되어 있다.

 

 

H2 Console 자동 설정 적용하기 - 자동 설정 이전

 

1. build.gradle에 의존관계 추가

    implementation 'com.h2database:h2'

+ H2는 메모리 데이터 베이스로 보통 테스트 용으로 쓰인다. 주 저장소가 아니기 때문에 불필요하게 컴파일 의존성에 포함될 필요가 없다. 따라서 application.yml로 자동 설정을 진행했다면, 런타임 시점에만 의존하도록 변경해도 된다. -> runtime('com.h2database:h2')

 

 

2. 빈을 이용해 H2 콘솔 등록하기

 

3. console 확인 -> localhost:8080/console -> 콘솔 실행된다.

 

 

H2 Console 자동 설정 적용하기 - 자동 설정 이후

 

다시 한번 metadata.json을 통해 프로퍼티 값을 살펴보자.

spring.h2.console.enabled의 defaultValue가 false로 적용되어 있다. 따라서 해당 프로퍼티만 true로 변경해주면 위와 같이 직접 @Configuration을 통한 빈 등록이 필요가 없어진다.

 

 

앞서 진행한 @Configuration 해제 & 의존성을 compile time -> runtime으로 변경 후 yml에 위와 같이 설정해주면 h2 console을 /h2-jh로 매핑해서 사용할 수 있다.

 

 


스프링 부트 테스트

 

스프링 부트에서는 기본적인 테스트 스타터를 제공한다. 스타터에 웬만한 테스트 라이브러리들을 한데 뭉쳐놨기 때문에 편리하게 사용 가능하다. 스타터는 크게 두 가지 모듈로 구성된다.

 

0. spring-boot-starter-test(아래 두 모듈 함께 사용)

1. spring-boot-test

2. spring-boot-test-autoconfigure(테스트 관련 자동 설정 기능) 

 

스프링 부트 1.4 버전부터는 각종 테스트를 위한 어노테이션 기반 기능을 제공하여, 특정 주제에 맞게 테스트를 구현하고 관리할 수 있다.

@SpringBootTest, @WebMvcTest, @DataJpaTest, @RestClientTest, @JsonTest에 대해서 알아보자.

 

 

1. @SpringBootTest

 

- 통합 테스트를 제공하는 기본적인 스프링 부트 어노테이션이다. 여러 단위 테스트를 하나의 통합된 테스트로 수행할 때 적합하다. 스프링부트 프로젝트를 만들면 메인 클래스와 기본으로 제공된다.

 

- 실제 구동되는 애플리케이션과 똑같이 애플리케이션 컨텍스트를 로드하여 테스트하기 때문에 하고 싶은 테스트를 모두 수행할 수 있다.

 

- 단, 애플리케이션에 설정된 모든 빈을 로드하기 때문에 규모가 클 수록 느려진다. 이렇게 되면 단위 테스트라는 의미가 희석된다.

 

 

@SpringBootTest 어노테이션 파라미터를 알아보자.

- value : @Value("${value}")를 통해 적용할 프로퍼티를 주입할 수 있다. 테스트 실행 전 발생하며, 기존의 프로퍼티를 오버라이드 한다.

- properties : 테스트가 실행되기 전에 key=value 형식으로 프로퍼티를 추가할 수 있다.

* value / properties를 같이 사용하면 안된다. 위에서는 그냥 보여주기 위한 것

 

- classes : 애플리케이션 컨텍스트에 로드할 클래스를 지정할 수 있다.

   따로 지정 안하면 @SpringBootConfiguration을 찾아서 로드(main 클래스)

 

- webEnvironment : 애플리케이션이 실행될 때의 웹 환경을 설정할 수 있다. 기본값은 Mock 서블릿을 로드하여 구동되며, 예제에서는 랜덤 포트 값을 주어 구동했다.

(Mock 서블릿 : 개발 환경에 따라 다른 Mock 서블릿 환경의 애플리케이션 컨텍스트를 선택하여 로드되도록 하는 설정 값)

 

+ profile 환경(개발, QA, 운영 환경)마다 다른 데이터 소스(DB와 서버 간의 연결정보)를 갖는다면 어떻게 할까?

-> @ActiveProfiles("local")과 같은 방식으로 원하는 프로파일 환경 값을 부여할 수 있다.

 

+ test에서 @Transactional 사용하면 테스트를 마치고 나서 수정된 데이터가 롤백된다. 다만 테스트가 서버의 다른 스레드에서 실행중이면 롤백 발생하지 않는다.

 

+ @SpringBootTest는 기본적으로 검색 알고리즘을 사용하여 @SpringBootApplication / @SpringBootConfiguration을 찾는다. 

 

 

2. @WebMvcTest

 

테스트 스타터에 포함된 자동 설정 패키지인 spring-boot-test-autoconfigure를 사용하면 주제에 따라 가볍게 테스트 가능하다. 주제에 관련된 빈만 애플리케이션 컨텍스트에 로드해서 테스트를 진행한다. (웹 테스트용 : @WebMvcTest)

 

- 웹에서 테스트하기 힘든 컨트롤러를 테스트하는데 적합하다. 웹상에서 요청과 응답에 대해 테스트를 할 수 있다.

 

- 시큐리티 혹은 필터까지 자동으로 테스트하며 수동으로 추가 / 삭제가 가능하다.

 

- MVC 관련 설정인 @Controller, @ControllerAdvice, @JsonComponent, Filter, WebMvcConfigurer, HandlerMethodArgumentResolver만 로드되기때문에 가볍게 테스트가 가능하다.

 

- @WebMvcTest를 사용하기 위해 테스트 할 특정 컨트롤러 명을 명시해주어야 한다. 주입된 MockMvc는 컨트롤러 테스트 시 모든 의존성을 로드하는 것이 아닌, 특정 컨트롤러 관련 빈만 로드해서 가벼운 MVC 테스트를 수행한다. 

 

- @Service는 @WebMvcTest의 적용 대상이 아니다. 만약 컨트롤러에서 서비스를 사용한다면, @MockMvc를 활용해서 컨트롤러 내부 부 의존성 요소인 service를 가짜 객체로 대체한다. 이를 목 객체라고 한다. 

 

 

3. @DataJpaTest

 

- JPA 관련 테스트 설정만 로드한다. 

 

- 데이터 소스의 설정이 정성적인지, JPA를 사용하여 데이터를 제대로 생성, 수정, 삭제하는지 등의 테스트가 가능하다.

 

- 내장형 데이터베이스를 사용해서 실제 db 사용하지 않고 테스트데이터 베이스로 테스트가 가능하다.

 

- 기본적으로 인메모리 임베디드 데이터베이스(메인 메모리를 데이터 저장소로 활용)를 사용하여, @Entity 클래스를 스캔해서 Spring Data JPA Repository를 구성한다. 

 

- 별도의 데이터 소스를 사용해서 테스트하려면 다음과 같이 설정한다.

@ActiveProfiles("...")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class JpaTest {
   ...
}

@AutoConfigureTestDatabase의 기본 설정인

Replace.Any를 사용 -> 내장 데이터베이스 사용

Replace.None을 사용 -> @ActiveProfiles에 설정한 프로파일 환경값에 따라 데이터 소스가 적용된다.

 

+ application.yml에서 프로퍼티 설정을 spring.test.database.replace: NONE으로 설정도 가능하다.

 

 

- @DataJpaTest는 JPA 테스트 끝날 때마다 자동으로 테스트에 사용한 데이터를 롤백한다. 따라서 테스트 후 실제 데이터가 변경되었는지 걱정할 필요 없다.

 

 

4. @RestClientTest

 

- REST 통신의 데이터형으로 사용되는 JSON 형식이 예상대로 응답을 반환하는지 등을 테스트할 수 있다.

 

- MockRestServiceServer : 클라이언트와 서버 사이의 REST 테스트를 위한 객체이다. 내부에서 restTemplate을 바인딩하여 실제로 통신이 이루어지게끔 구성할 수도 있다. 여기에서는 목 객체와 같이 통신이 이루어지진 않지만, 지정한 경로에 예상되는 반환값 혹은 에러를 반환하도록 명시하여 간단하게 테스트를 진행했다.

 

 

 

5. @JsonTest

 

- JSON의 직렬화 / 역직렬화를 수행하는 라이브러리인 Gson, Jackson API의 테스트를 제공한다.

 

- 각각 GsonTester, JacksonTester를 사용하여 테스트를 수행한다.

 

- JSON 테스트는 다음과 같이 두 가지로 나눌 수 있다.

   -. 문자열로 나열된 Json 데이터를 객체로 변환하여 반환된 객체값을 테스트

   -. 객체를 문자열로 변환하여 테스트

 

 

6. 정리

 

스프링 부트의 테스트 어노테이션은 Junit 자체에 내장된 테스트 메서드를 스프링에서 사용하기 편하도록 가공한 것이다.

스프링의 모든 빈을 올리는 대신, 각 테스트에 필요한 가짜 객체를 만들어 테스트 하는 방법을 사용해보자.

 

 


스프링 부트 웹

 

스프링 부트 웹을 이용해서 게시판을 만들어본다. 웹은 주로 뷰 페이지나 API 서비스의 구현에 사용된다. API는 '스프링 부트 데이터 레스트'를 사용해서 다루고, 이번에는 뷰 페이지를 만드는 법을 다룬다.

 

- 커뮤니티 게시판 설계하기

- 커뮤니티 게시판 프로젝트 준비하기

- 커뮤니티 게시판 구현하기

 

 

1. 커뮤니티 게시판 설계

 

1) 클라이언트 -> 서버 데이터 요청

2) 컨트롤러 -> 서비스 -> 리포지토리 -> DB를 거쳐 데이터가 돌아오고, 다시 컨트롤러에서 타임리프 뷰를 호출하여 브라우저에 반환한다.

 

간단한 CRUD 기능만 제공하는 게시판을 구현하도록 한다.

 

커뮤니티 게시판 기능 설계도

 

2. 게시판 구현하기

 

2.1 구현 요구 사항

 

1. 회원 기능 없음(로그인할 때 권한 인증 / 접근등의 권한 부여기능) -> 이후에 배우도록 하고, 우선 내용 위주로 진행한다.

2. Board(게시판), User(회원) 엔티티 및 테이블을 만든다. 회원의 pk를 게시판에서 FK로 사용하고, OneToOne mapping을 진행한다.

 

 

 

2.2 구현 순서

 

1. 프로젝트 의존성 구성

2. 스프링 부트 웹 스타터 살펴보기

3. 도메인 매핑하기

4. 도메인 테스트 하기

5. CommandLineRunner 이용해서 DB에 데이터 넣기

6. 게시글 리스트 기능 만들기

7. 타임리프 자바 8 날짜 포맷 라이브러리 추가

8. 페이징 처리

9. 작성 폼 만들기 

 


2.2.1 프로젝트 의존성 구성

 

plugins : 필요한 플러그인을 적용한다.(기본으로 되어있는거 그대로 사용)

dependencies : 프로젝트 내에 사용할 라이브러리의 의존성을 설정한다. 메인 부트 버전에 맞는 호환성을 가져오기 위해 디폴트 버전 사용한다.

 

 

2.2.2 스프링 부트 웹 스타터 살펴보기

 

Spring-boot-starter는 다음 의존성을 제공했었다.

- spring-boot : 스프링 부트 기존 제공 의존성

- spring-boot-autoconfigure : 스프링 부트 자동 환경 구성에 필요한 의존성

- spring-boot-starter-logging : 각종 로그를 사용하는데 필요한 의존성

- javax.annotation-api : 소프트웨어의 결함을 탐지하는 어노테이션을 지원하는 의존성

- spring-core : 스프링 코어 사용시 필요한 의존성

- snakeyaml : yaml을 사용하는 데 필요한 의존성

 

 

Spring-boot-web-starter는 다음과 같은 의존성을 제공한다.

- spring-boot-starter : 위의 6가지 포함

- spring-boot-starter-tomcat : 내장 톰캣 사용 위한 스타터

- hibernate-validator : 어노테이션 기반의 표준화된 제약 조건 및 유효성 검사 규칙을 표현하는 라이브러리

- spring-boot-starter-json : jaskson 라이브러리 지원하는 starter

- spring-web : Http integration, servlet filters, spring Http invoker 및 Http core를 포함시킨 라이브러리

- spring-webmvc : request를 전달하는 MVC로 디자인 된 DispatcherServlet 기반의 라이브러리

 

 

2.2.3 도메인 매핑하기

 

뷰에 바인딩하여 반환하는 흐름을 알아본다.

도메인 매핑은 JPA를 사용해서 DB와 도메인 클래스를 연결해주는 작업이다. DB에서 (도메인을 활용하여) 리포지토리까지의 데이터 처리 흐름은 다음과 같다. 

 

* 리포지토리 : 스프링이 관리하는 컴포넌트에서 퍼시스턴스 계층에 대해 더 명확하게 명시하는 특수 제네릭 스테레오 타입이다.

(퍼시스턴스 : 물리적 저장 공간. 영속성을 가진 파일이나 DB에 로직을 구현하는 것을 의미하기도 한다.)

 

JPA 활용한 H2 DB 매핑 구성도

 

Board / User를 각각 Serializable을 implements하여 구현한다. (Builder 패턴 이용)

 

 

2.2.4 도메인 테스트 하기

 

- 앞서 배운 @DataJpaTest를 사용해서 도메인 테스트를 진행한다. 테스트 후 자동 롤백으로 DB에 반영되지 않는다.

 

@ExtendWith(SpringExtension.class)
@DataJpaTest
public class JpaMappingTest {
    private final String boardTestTitle = "테스트";
    private final String email = "test@gmail.com";

    @Autowired
    UserRepository userRepository;

    @Autowired
    BoardRepository boardRepository;

    @BeforeEach
    public void init() {
        User user = userRepository.save(User.builder()
                .name("havi")
                .password("test")
                .email(email)
                .createDate(LocalDateTime.now())
                .build());

        boardRepository.save(Board.builder()
                .titie(boardTestTitle)
                .subTitle("서브 타이틀")
                .content("콘텐츠")
                .boardType(BoardType.free)
                .createdDate(LocalDateTime.now())
                .updatedDate(LocalDateTime.now())
                .user(user).build()
        );
    }

    @Test
    public void 정상_생성_테스트() {
        User user = userRepository.findByEmail(email);
        assertThat(user.getName()).isEqualTo("havi");
        assertThat(user.getPassword()).isEqualTo("test");
        assertThat(user.getEmail()).isEqualTo(email);

        Board board = boardRepository.findByUser(user);
        assertThat(board.getTitie()).isEqualTo(boardTestTitle);
        assertThat(board.getSubTitle()).isEqualTo("서브 타이틀");
        assertThat(board.getBoardType()).isEqualTo(BoardType.free);
    }
}

- ExtendWith를 통해 JUnit에 내장된 러너가 아닌 어노테이션에 정의된 클래스를 호출한다. 또한 JUnit의 확장 기능을 지정하여 각 테스트 시 독립적인 애플리케이션 컨텍스트를 보장한다.

* 애플리케이션 컨텍스트 : 빈의 생성과 관계 설정 같은 제어를 담당하는 IOC 객체를 빈 팩토리라 부르며, 이를 더 확장한 개념이다.

 

 

BoardService 생성

@Service
public class BoardService {

    private final BoardRepository boardRepository;

    public BoardService(BoardRepository boardRepository) {
        this.boardRepository = boardRepository;
    }

    public Page<Board> findBoardList(Pageable pageable) {
        pageable = PageRequest.of(pageable.getPageNumber() <= 0 ? 0 : pageable.getPageNumber() - 1, pageable.getPageSize());
        return boardRepository.findAll(pageable);
    }

    public Board findBoardByIdx(Long idx) {
        return boardRepository.findById(idx).orElse(new Board());
    }
}

- findBoardList :

pageable로 넘어온 pageNumber 객체가 0 이하일 때 0으로 초기화. 기본 페이지 크기인 10으로 새로운 PageRequest 객체를 만들어 페이징 처리된 게시글 리스트를 반환한다.

 

- findBoardByIdx :

board의 idx 값을 사용하여 board 객체를 반환한다.

 

 

BoardController 생성

@Controller
@RequestMapping("/board")
public class BoardController {

    @Autowired
    BoardService boardService;

    @GetMapping({"", "/"})
    public String board(@RequestParam(value = "idx", defaultValue = "0") Long idx, Model model) {
        model.addAttribute("board", boardService.findBoardByIdx(idx));
        return "/board/form";
    }

    @GetMapping("/list")
    public String list(@PageableDefault Pageable pageable, Model model) { // pageableDefault 어노테이션의 파라미터인 size, sort 등을 이용해서 페이징 처리에 대한 규약을 정의한다.
        model.addAttribute("boardList", boardService.findBoardList(pageable));
        return "/board/list";
    }
}

Pageable 객체를 생성하기 위해서 사용되는 요청 파라미터

  • page : 가져올 페이지 (기본값 : 0)
  • size : 페이지의 크기 (기본값 : 20)
  • sort : 정렬 기준으로 사용할 속성으로 기본적으로 오름차순으로 한다. 정렬 기준 속성이 2개 이상인 경우에는 sort 파라미터를 2개 이상 넣어주면된다. 예) sort=firstname&sort=lastname,asc.

 

- 간단히 알아보면, 위와 같은 쿼리 파라미터를 기반으로 pageable 객체를 생성 & 서비스 메서드로 전달한다.

 

서비스 메서드에서는 전달받은 Pageable 객체를 대상으로 페이지 / 크기 / 정렬 기준 등의 정보를 추출한다.

PageRequest.of에서, PageRequest는 pageable을 상속받는 클래스이다. of를 통해 위에서는 새로운 unsorted 된 PageRequest를 생성해서 repository로 넘겨준다.

 

 

boardRepository에서는 전달받은 Pageable 객체를 대상으로  findAll 메서드를 실행 & 페이징 처리 된 Page를 반환한다.

(*Page : Object list의 sublist)

 

 

2.2.5 CommandLineRunner를 사용하여 DB에 데이터 넣기

 

- 애플리케이션 구동 후 CommandLineRunner로 테스트용 데이터를 DB에 넣을 수 있다. 이 인터페이스는 애플리케이션 구동 후 특정 코드를 실행시키고 싶을 때 직접 구현하는 인터페이스이다. 

 

- 구동 시 테스트 데이터를 함께 생성하여 데모 프로젝트를 실행 / 테스트하고 싶을 때 편리하다. 

 

- 또한 여러 CommandLineRunner를 구현하여 같은 애플리케이션 컨텍스트의 빈으로 사용할 수 있다.

 

 

한 명의 회원을 생성 & 그 회원의 글 200개를 작성하는 쿼리를 생성해보자. 

 

@SpringBootApplication
public class SpringBootCommunityWebApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootCommunityWebApplication.class, args);
    }

    @Bean // 스프링은 빈으로 생성된 메서드에 파라미터로 DI 시키는 메커니즘이 존재한다. 생성자를 통해 의존성을 주입시키는 방법과 유사하다. 이를 이용해서 CommandLineRunner를 빈으로 등록 후, 두 repo를 주입 받는다.
    public CommandLineRunner runner(UserRepository userRepository,
                                    BoardRepository boardRepository) throws Exception {

        return (args -> {
            // 메서드 내부에 실행이 필요한 코드를 작성한다. User 객체를 빌더 패턴을 사용해서 생성한 후, 저장한다.
            User user = userRepository.save(User.builder()
                    .name("havi")
                    .password("test")
                    .email("havi@gmain.com")
                    .createDate(LocalDateTime.now())
                    .build());

            // 페이징 처리 테스트를 위해 빌더 패턴을 이용한다. IntStream의 rangeClosed를 사용해서 index 순서대로 Board 객체 200개를 생성해서 저장한다.
            IntStream.rangeClosed(1, 200).forEach(index ->
                    boardRepository.save(Board.builder()
                            .titie("게시글" + index)
                            .subTitle("순서" + index)
                            .content("콘텐츠")
                            .boardType(BoardType.free)
                            .createdDate(LocalDateTime.now())
                            .updatedDate(LocalDateTime.now())
                            .user(user)
                            .build()
                    ));
        });
    }
}

- CommandLineRunner는 어떤 방법을 사용하든 빈으로 등록해야 한다!

 

 

2.2.6 게시글 리스트 기능 만들기 ~ 2.2.8 페이징 처리

 

@는 타임리프의 기본 링크 표현 구문이다.

 

$를 통해 컨트롤러에서 model을 통해 전달된 값을 파싱할 수 있다. #을 통해 thymeleaf 제공 함수를 사용할 수 있다.

 

th:with 안에서 ul 태그 안에서 사용할 변수를 정의한다. startNumber, endNumber 변수로 페이지의 처음과 끝을 동적으로 계산해서 초기화 한다.

 

Pageable 객체는 해당 페이지가 처음인지(isFirst) 마지막인지(isLast)에 대한 데이터 불린 형을 제공한다. 이를 사용해서 이전 / 다음 페이지 화살표의 미노출 여부를 결정한다.

- boardList.first가 해당 페이지의 처음이라면 아무것도 노출 안함(display:none)

- 처음이 아니라면 /board/list?page=boardList.number의 링크를 제공한다. 

    - &laquo : <<

    - &lsaquo : <

    - &rsaquo : >

    - &&raquo : >>

 

 

page와 boardList.number + 1이 동일하면 class에 active를 할당해서 강조되도록 한다.

 

page = 7                   number = 6(0부터 시작)

 

2.2.9 작성 폼 만들기

 

$(...?) 처럼 구문 뒤에 "?"를 붙여서 null 체크를 추가할 수 있다. 값이 null인 경우에는 빈 값이 출력되도록 할 수 있다.

 

값이 있으면 수정 시 출력되고, 없으면 빈 칸으로 나오게 된다.(위는 값이 있는 경우)

 

 

 

 

'각종 회고' 카테고리의 다른 글

[TIL]9/15 - AOP  (0) 2021.09.29
[TIL]9/15(5일차) - WEB2 : OAuth 2.0  (0) 2021.09.15
[TIL]9/14(4일차) - Spring Boot Security + OAuth  (0) 2021.09.14
[TIL] 9/10 (2일차)  (0) 2021.09.10
[TIL] 9/9 (1일차)  (0) 2021.09.09
Comments