개발을 시작해봐요! 스프링 부트(Spring Boot ) 게시판 - 게시글 리스트...
개발을 시작해봐요! 스프링 부트(Spring Boot ) 게시판 - 게시글 리스트...
해당 포스팅에서 화면은 JSP가 아닌 타임리프(Thymeleaf) 템플릿 엔진(이하 타임리프)을 사용합니다.
이전 포스팅에서 우리는 서비스, 컨트롤러 그리고 게시글을 등록하는 뷰(화면)를 처리하는 방법과 공통 레이아웃을 처리하는 방법에 대해 알아보았습니다. 이번 포스팅에서는 게시글의 리스트를 보여주는 화면을 구현해 보도록 하겠습니다.
1. 컨트롤러
우리는 이전 포스팅에서 이미 서비스와 매퍼에 게시글 CRUD를 처리하는 메서드를 모두 구현하였기 때문에 바로 컨트롤러부터 진행하도록 하겠습니다. BoardController 클래스를 열고, 다음의 코드를 추가해 주세요.
@GetMapping(value = "/board/list.do") public String openBoardList(Model model) { List boardList = boardService.getBoardList(); model.addAttribute("boardList", boardList); return "board/list"; }
boardList
서비스에서 getBoardList 메서드를 호출한 결과를 boardList에 담아서 뷰로 전달합니다.
return 문
컨트롤러의 리턴 타입이 String이면 return 문에 지정한 경로의 HTML이 화면으로 보인다는 이야기를 했었습니다. 여기서 의미하는 board/list는 src/main/resources 디렉터리의 templates/board/list.html을 의미합니다.
2. 뷰(화면)
이제 src/main/resources 디렉터리의 templates/board 폴더 안에 list.html을 추가하고, 더보기의 코드를 입력해 주세요. 타임리프의 th 속성과 레이아웃을 사용하기 위해 네임스페이스를 선언하고, 레이아웃 파일 경로를 지정하는 부분에 대해서는 이전 포스팅에서 이미 진행했기 때문에 따로 설명하지 않도록 하겠습니다.
더보기 This page is a list page 번호 제목 작성자 등록일 조회 수 조회된 결과가 없습니다. Write « 1 2 3 4 5 »
layout:fragment="search"
리스트에서 특정 게시글을 검색할 수 있는 영역입니다. 아직은 검색 기능을 구현하지 않았기 때문에 아무런 작동을 하지 않습니다. CRUD 기능을 모두 마무리하고 페이징과 같이 진행할 예정입니다.
layout:fragment="content"
write.html과 마찬가지로 리스트 페이지의 실제 Content가 들어가는 부분입니다. 게시글 리스트는 보통 테이블 형태로 처리합니다. 타임리프의 속성이 사용된 부분을 위주로 설명하도록 하겠습니다.
태그 안의 타임리프 속성
th:if 속성과 th:unless 속성
먼저 29번 라인의 th:if 속성과 38번 라인의 th:unless 속성을 보도록 하겠습니다. th:if 속성은 우리가 흔히 알고 있는 if 문과 같고, th:unless 속성은 else 문과 같다고 볼 수 있습니다. th:unless 속성은 자바의 else 문과 다르게 th:if 문에 들어가는 조건과 같은 조건이 들어가게 됩니다. 처음에는 살~짝 헷갈릴 수 있습니다.. 결론적으로 th:if 속성의 조건이 성립되면 게시글 리스트를 출력하고, th:unless 속성의 조건이 성립되면 게시글이 하나도 없는 것이므로 "조회된 결과가 없습니다."라는 화면이 보이게 됩니다.
lists.isEmpty 함수
다음은 th:if 속성에 들어간 조건입니다. 해당 함수는 인자로 지정된 데이터가 비어있는지 확인하는 데 사용됩니다. 컨트롤러에서 전달받은 데이터뿐만 아니라 기존에 JSP를 사용할 때 JSTL에서 와 같이 변수를 선언했던 것처럼 th:with 속성으로 변수를 선언할 수 있습니다. 여기서는 BoardController의 openBoardList 메서드에서 뷰로 전달한 boardList가 비어있지 않은지 확인합니다. 함수 앞의 "not"은 부정의 표현입니다. '!' 또는 "not" 또는 #lists.isEmpty( boardList ) == false 등 여러분의 스타일에 맞는 방법을 사용해 주시면 되겠습니다. 인자에 띄어쓰기를 사용한 이유는 가독성 측면에서 한 것이기 때문에 붙여서 사용하셔도 무관합니다.
th:each 속성
JSP에서는 반복문을 와 같이 사용했었는데요, th:each 속성은 자바의 forEach와 같다고 볼 수 있습니다. 여기서는 "row라는 이름으로 boardList를 반복하겠다."의 의미를 가집니다.
1. 첫 번째
strings.equals 함수를 사용해서 공지 여부가 'Y'로 등록된 게시글이라면 "공지"를 출력하고 공지 여부가 'N'으로 등록된 게시글이라면 게시글 번호를 출력합니다.
2. 두 번째
태그에 게시글 하나를 조회하는 /board/view.do URI를 호출합니다. 보통은 href 속성에 파라미터를 포함하면 첫 번째는 '?'로 두 번째부터는 '&'로 구분합니다. 하지만 타임리프는 URI 뒤에 괄호를 열어서 파라미터를 포함시킵니다.
일반적인 GET 파라미터 추가 방식 /board/view.do?idx=${idx}&page;=${page} 타임리프 GET 파라미터 추가 방식 /board/view.do( idx=${idx}, page=${page} )
3. 세 번째
작성자를 텍스트 형식으로 출력합니다.
4. 네 번째
BoardDTO 클래스에서 시간 관련 xxxTime 인스턴스 변수는 temporals.format 함수를 사용해서 원하는 날짜 형태로 포맷할 수 있습니다. 해당 태그는 게시글 등록일을 년-월-일 형태의 텍스트 형식으로 출력합니다.
5. 다섯 번째
조회 수를 텍스트 형식으로 출력합니다.
Write 버튼
/board/write.do URI를 호출해서 신규 글 작성 페이지로 이동합니다.
layout:fragment="paging"
리스트에서 특정 페이지로 이동할 수 있는 영역입니다. 검색 영역과 마찬가지로 CRUD 기능이 모두 마무리되면 진행할 예정입니다. 아직은 페이징 처리가 되어있지 않기 때문에 번호를 클릭해도 작동하지 않습니다.
페이징 HTML
이제 애플리케이션을 실행하고, /board/list.do URI를 호출해 보면 게시글 리스트가 출력되는 것을 확인할 수 있습니다.
게시글 리스트의 가장 상단
게시글 리스트의 가장 하단
마무리
이번에는 게시글 리스트를 구현하는 시간을 가져보았습니다. 이제 CRUD에서 게시글 하나를 조회하는 기능과 게시글을 삭제하는 기능 두 가지만 남았습니다. CRUD 처리가 모두 마무리되면 로그와 인터셉터 등 스프링에서 빠질 수 없는 필수적인 기능을 적용하고, 페이징과 검색 처리, Rest API 방식의 댓글 처리, 게시글에 첨부 파일을 업로드하는 방법 등에 대해 알아보도록 하겠습니다. 감사합니다!
프로젝트를 import 해서 사용하신다면 application.properties에서 DB 정보만 올바르게 변경해서 사용해 주세요!
Board.zip 2.10MB
from http://congsong.tistory.com/17 by ccl(A) rewrite - 2020-03-24 21:20:29
댓글
댓글 쓰기