-
카테고리 지역 클릭 이후 게시물 조회, 페이징 처리졸업과제/BackEnd 2023. 3. 13. 10:42
홈페이지에서 카테고리를 클릭하면 해당 지역에 포함되어 있는 게시물만 볼 수 있도록 구현하기가 목표이다.
저번에 구현했던 검색기능에서 사용했던 JPA의 Containing을 활용하면 될 거 같다!!!
Enum
public enum AreaEnum { 강남구, 강동구, 강북구, 강서구, 관악구, 구로구, 금천구, 노원구, 도봉구, 동대문구, 동작구, 마포구, 서대문구, 서초구, 성동구, 송파구, 양천구, 영등포구, 용산구, 은평구, 종로구, 중구, 중랑구 }
서울시의 행정구들을 Enum타입으로 정의해 주었다. html코드에서 반복문으로 출력해 줄 예정이다.
Controller
@Controller public class HomeController { @GetMapping(value = "/") public String Home(Model model) { PostSearchDto postSearchDto = new PostSearchDto(); model.addAttribute("dto",postSearchDto); model.addAttribute("category",AreaEnum.values()); return "home"; } }
서울시의 행정구들의 이름을 Enum타입으로 정의해 두었다. Enum타입으로 정의한 서울시의 행정구들의 값들을 Dto로 전달해 준 뒤
반복문을 이용해 Enum타입의 값들을 출력해 줄 예정이다.
Html
<ul class="navbar-nav justify-content-start flex-grow-3 pe-3" th:each="dto : ${category}"> <li><a class="seoul" th:href="@{/post/search/{areaId}(areaId = ${dtoStat.index})}" th:text="${dto}">강남구</a></li> </ul>
카테고리를 li태그를 이용해 나열하는 html코드이다.
Controller에서 전달했던 category속에 있는 Enum타입으로 정의된 서울시의 행정구들을 출력해 줄 것이다.
사용자가 행정구들 중에 하나를 클릭하면 해당구가 어떤 구인지 서버는 알고 있어야 해서
Thymeleaf에서 제공하는 반복문의 상태변수를 이용해 값들을 행정구들을 구분할 예정이다.
th:each = "dto : ${category}에서 반복문에 상태변수를 얻고 싶다면 내가 선언한 변수이름뒤에 Stat를 선언해 주면 된다.
사용자가 정의해 줄 수도 있다. th:each = "dto, x : ${category}"와 같이 선언하면 x.index와 같이 선언하면
변수이름뒤에 Stat를 붙인 것과 같이 반복문의 index를 얻을 수 있다.
자세한 건 공식문서에 나와있다 (근데 공식문서 보기 싫은 거 나만 그런가?)
https://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#using-theachTutorial: Using Thymeleaf
1 Introducing Thymeleaf 1.1 What is Thymeleaf? Thymeleaf is a Java library. It is an XML/XHTML/HTML5 template engine able to apply a set of transformations to template files in order to display data and/or text produced by your applications. It is better s
www.thymeleaf.org
강남구가 AreaEnum타입의 첫 번째 선언돼 있므로 index는 0이 된다. 따라서 사용자가 강남구를 클릭하면
URL은 /post/search/0으로 GetMapping이 전송될 것이다.
Test
카테고리를 클릭하면 Enum타입으로 정의한 서울의 행정 구역들이 잘 출력되는 모습을 확인할 수 있다.
강북구에 마우스 커서를 올려보면 강북구는 3번째 Enum으로 정의되어 있기 때문에 index = 2이다 index가 2인 결과가
왼쪽 하단 URL에 /post/search/2로 의도했던 대로 지역구들을 구분할 수 있도록 URL에 잘 담겨있는 모습을 확인할 수 있다.
페이징 처리 및 DB 조회
이제 서울시의 행정 구역들을 URL에 담아서 구분할 수 있게 해 두었으니 구분된 URL값을 이용해
DB에서 게시물을 조회하고 조회한 게시물을 페이징 처리해서 보일 수 있도록 구현해야 한다. 좀 더 백엔드스러운 작업이랄까?
(타임리프로 데이터 넘기고 출력하는 것 프론 튼가요 백인가요? 궁금하네요)
Controller
@Controller public class PostController { private final PostService postService; private AreaEnum[] area = AreaEnum.values(); Logger logger = LoggerFactory.getLogger(PostController.class); @Autowired public PostController(PostService postService) { this.postService = postService; } @GetMapping(value = "/post/search/{areaId}") public String SearchPostUsingCategory(@PathVariable("areaId")Integer areaId, @PageableDefault Pageable pageable,Model model) { logger.info("[SearchPost]홈페이지에서 사용자가 카테고리 클릭후 해당 게시물 검색. areaID:{}",areaId); String areaName = area[areaId].toString(); logger.info("[findArea] Service 에서 사용자가 클릭한 지역게시물 Enum에서 조회. 결과: {}",areaName); Page<Post> posts = postService.SearchPostUsingCategory(areaName, pageable); logger.info("[SearchPostUsingCategory] 카테고리 클릭후 해당지역 조회 게시물 결과. 지역이름:{} 게시물 갯수:{}",areaName,posts.getTotalElements()); model.addAttribute("postList",posts); return "post/searchList"; } }
html에서 전달된 areaId 즉 Enum의 index를 이용해 값을 String으로 변환해 받아온다. 받아오고 난 뒤
해당 행정구역의 이름과 페이징 처리를 위한 Pageable객체를 Service에 전달한다.
int i; for(i = 0; i!= areaId; ++i){} String areaName = area[i].toString();
areaId로 Enum에서 값을 가져오는걸 이 코드로 맨 처음에 했었다... 블로그를 쓰다 보니 그냥 areaId index로 바로 접근하면 되는 걸 깨달은 나 자신이었다 하인즈 머쓱타드세요!
Service
public Page<Post>SearchPostUsingCategory(String areaName,Pageable pageable) { logger.info("[SearchPostUsingCategory] 카테고리에서 클릭한 지역이름을 이용해 게시물 조회 Service로직 동작 지역 이름: {}",areaName); int page = (pageable.getPageNumber()==0)?0:(pageable.getPageNumber()-1); PageRequest pageRequest = PageRequest.of(page, 4, Sort.by(Sort.Direction.DESC, "postId")); return postRepository.findByAreaContaining(areaName,pageRequest); }
Service 코드도 간단하다. 페이징 처리를 위한 elements개수와 정렬 방법을 세팅해 준 뒤 JPA repository를 호출한다.
Enum타입에서 조회해 온 지역이름을 Repository에 전달해서 DB에서 조회할 수 있도록 해준다.
Repository
Page<Post>findByAreaContaining(String area,PageRequest pageRequest);
게시물의 속성들 중에 게시물에 저장된 지역이름으로 카테고리에서 클릭된 값을 조회할 것이기 때문에
게시물의 지역을 저장하고 있는 area 속성을 이용할 것이다. 따라서 findByAreaContaining로 선언해 주었다.
이렇게 하면 JPA는 쿼리를 게시물의 area속성을 대상으로 전달된 area값을 이용해 % 쿼리를 날릴 것이다.
Test
페이징 처리가 안되무니다...;;;
페이징 처리가 되지 않았다. 로그를 확인해 보면 7개의 게시물이 출력돼야 돼서 1번째 페이지에는 4개 2번째 페이지에는 3개의
게시물이 출력되야 하는데 그렇게 되지 않았다.
두 번째 페이지의 URL이 /post/searchList? page로 돼있어서 첫 번째 페이지의 URL과 달라서 그런 건가 싶어서 페이지를 넘길 수 있는
내비게이션바의 URL에 검색하고자 하는 행정구역의 index를 포함할 수 있도록 해보았다.
<nav style="text-align: center;"> <ul class="pagination" th:with="start=${T(java.lang.Math).floor(postList.number/10)*10 + 1},last=(${start + 9 < postList.totalPages ? start + 9 : postList.totalPages})"> <li> <a th:href="@{/post/searchList/${areaId}(page=1)}" aria-label="First"> <span aria-hidden="true">First</span> </a> </li> <li th:class="${postList.first} ? 'disabled'"> <a th:href="${postList.first} ? '#' :@{/post/searchList/${areaId}(page=${postList.number})}" aria-label="Previous"> <span aria-hidden="true"><</span> </a> </li> <li th:each="page: ${#numbers.sequence(start, last)}" th:class="${page == postList.number + 1} ? 'active'"> <a th:text="${page}" th:href="@{/post/searchList/${areaId}(page=${page})}"></a> </li> <li th:class="${postList.last} ? 'disabled'"> <a th:href="${postList.last} ? '#' : @{/post/searchList/${areaId}(page=${postList.number + 2})}" aria-label="Next"> <span aria-hidden="true">></span> </a> </li> <li> <a th:href="@{/post/searchList/${areaId}(page=${postList.totalPages})}" aria-label="Last"> <span aria-hidden="true">Last</span> </a> </li> </ul> </nav>
Controller에서 postId라는 이름으로 Enum의 index를 model로 넘겨준 뒤 URL에 포함시켜 보았다. 하지만 잘되지 않았다!!
수정해서 그런 건지 아니면 원래 그랬던 건지 URL링크 자체가 이상하게 돼있었다. 보통 타임리프 링크를 잘못 적으면 저렇게 되던데 싶어
다시 한번 코드를 확인해 보았다...
억장 와르르 멘션 나의 마지막 희망으로 html코드에 직접 /0을 넣어줘 보았지만 역시나 오류가 났다. 매핑할 수 있는 URL이 없다고 오류가 나서
정상작동하는 게시물 목록 코드랑 뭐가 다른 건지 한번 확인해보는즁.. 쉬울 줄 알았는데 어렵구먼요
2시간 후...
역시 컴퓨터는 잘못하지 않는다. 오류를 발견하고 난 뒤 거친 한숨을 몰아 쉬었다!!!게시물 목록에 페이지를 넘기는 내비게이션 바에는 URL이 /post/searchList로 되어있는대
Controller에서는 /post/search로 돼있어서 매핑되는 URL이 없어서 그랬던 것이었다.....
@GetMapping(value = "/post/searchList") public String SearchPostUsingCategory(@RequestParam(value = "areaId",required = false,defaultValue = "")String areaId, @PageableDefault Pageable pageable, Model model) { int aid = 0; if(!areaId.equals("")){ aid = Integer.parseInt(areaId); } logger.info("[SearchPost]홈페이지에서 사용자가 카테고리 클릭후 해당 게시물 검색. areaID:{}",aid); String areaName = area[aid].toString(); logger.info("[findArea] Service 에서 사용자가 클릭한 지역게시물 Enum에서 조회. 결과: {}",areaName); Page<Post> posts = postService.SearchPostUsingCategory(areaName, pageable); logger.info("[SearchPostUsingCategory] 카테고리 클릭후 해당지역 조회 게시물 결과. 지역이름:{} 게시물 갯수:{}",areaName,posts.getTotalElements()); model.addAttribute("AreaId",areaId); model.addAttribute("postList",posts); return "post/searchList"; }
<ul class="navbar-nav justify-content-start flex-grow-3 pe-3" th:each="dto : ${category}"> <li><a class="seoul" th:href="@{/post/searchList(areaId = ${dtoStat.index})}" th:text="${dto}">강남구</a></li> </ul>
최종 코드이다. GetMapping 되는 url정보를 바꿔주었고 지역을 나타내는 index값을 url에 실어서 보내는 게 아니라
쿼리에 실어서 보낼 수 있도록 @RquestParam 어노테이션을 사용해 줬다.
지역을 클릭하고 들어간 뒤 페이징 처리된 게시물 목록에서 밑에 페이지를 이동하는 내비게이션 바에서는 areaId쿼리가 존재하지 않기 때문에 @RequestParam인 areaId가 없으니 required =false로 설정해 준 뒤 기본값을 ""로 세팅해 준다.
만약 areaId가 ""로 세팅되어 들어온다면 Integer.parseInt 하는 과정에서 예외가 터질 수도 있으니 areaId가 ""이 아닐 때만
int로 변환할 수 있도록 if 조건문을 걸어준다.
아까와는 다르게 7개의 강남구 지역의 게시물이 2개의 페이지에 나눠서 페이징처리 되는 것을 확인할 수 있다.
오늘도 문제를 해결했다 굉장히 뿌듯하고 기분이 좋다
내일은 어떤 오류가 날 기다리고 있을까 기대되면서 설레면서 머리가 벌써 아프기도 하지만 하나하나 해결해 나가면서
지식이 늘어가는게 보여 기분은 좋다.
그래도 예전보다 오류가 생기면 어떻게 대처해야 하는지 조금이나마 알게 된 거 같아서 기쁘다.
1년 전 나는 유튜브에서 52강짜리 컴퓨터 강의를 듣고 있었는데 그게 c++인 줄 알고 들었는데 다 듣고 보니 C언어라는 걸
알정도로 무지함 그 자체였다. 1년 전 나와 지금의 나는 그래도 많이 성장한 거 같다. 초심자 버프 같기도 하고..
진로 고민이 많다. 백엔드 개발자가 막연하게 돼야지 했는데 현직 개발자이신 이모부와 대화를 해보니 좀 더 공부해서 AI 쪽이나
데이터 사이언스 쪽으로 가보고 싶다는 생각도 했다. 그래서 다음 프로젝트는 ai를 해보고 싶다.
시간이 되면 파이썬도 해보고 google의 텐서플로우도 다뤄보고 aws도 다뤄봐야겠다. 텐서플로우나 aws둘다 자격증이 존재하니
그것을 준비하는 것도 괜찮을 것 같다.
뭐든 해봐야 하는 거 같다. 해봐야 어려운지 쉬운지 나에게 맞는지 맞지 않는지 알 수 있는 거 같다.
옆에서 언제든 응원해 주는 사람이 있기 때문에 열심히 해서 보답하고 싶고 나로 인해 주변 사람들과 우리 가족이 행복해지고
잘 살았으면 좋겠다. 열심히 해야겠다.
'졸업과제 > BackEnd' 카테고리의 다른 글
Thymeleaf + Spring JPA를 이용한 게시물 좋아요 기능 (0) 2023.03.17 JPA를 이용해 최근 게시물 불러오기 (0) 2023.03.14 Spring JPA 검색기능 구현. (0) 2023.03.12 Thymeleaf를 이용해 Option값 받아오기. (0) 2023.03.11 Thymeleaf를 이용한 게시물 댓글 출력 (0) 2023.03.10