[Tistory] 카테고리 조회 (카테고리가 없으면 redirect)

yuzu sim's avatar
Oct 05, 2024
[Tistory] 카테고리 조회 (카테고리가 없으면 redirect)

1. 게시글 쓸 때, 카테고리 조회

notion image
💡
여기에 categoryList 뿌릴 것이다.
 

2. CategoryJPARepository

// 카테고리 리스트 뿌리기 @Query("select new site.metacoding.blogv3.category.CategoryResponse$CategoryNameDTO(c.id, c.categoryName) " + "from Category c where c.user.id = :sessionUser order by c.categoryName") List<CategoryResponse.CategoryNameDTO> findByUserId(@Param("sessionUser") Integer sessionUser);
💡
DTO로 바로 받을 때 생성자 있어야함~

CategoryResponse.CategoryNameDTO 쿼리 오류??…

원래 쿼리를 이렇게 썼는데…
// 카테고리 리스트 뿌리기 @Query("select new site.metacoding.blogv3.category.CategoryResponse.CategoryNameDTO(c.id, c.categoryName) " + "from Category c where c.user.id = :sessionUser order by c.categoryName") List<CategoryResponse.CategoryNameDTO> findByUserId(@Param("sessionUser") Integer sessionUser);
CategoryResponse.CategoryNameDTO 오류가 터진다?!!
Validation failed for query for method public abstract java.util.List 쿼리 유효성에 실패?????
CategoryResponse$CategoryNameDTO 쓰니가 오류 안터지고 CategoryResponse.CategoryNameDTO 쓰니까 오류 터지는데 이유
 

[ 중첩 클래스?? 무슨 차이지?? ]

CategoryResponse$CategoryNameDTOCategoryResponse.CategoryNameDTO의 차이는 문법적인 관점에서 접근

[ 해결 ]

notion image
화면을 보면 게시판 쓸때 카테고리 리스트가 안에 있기 때문에

1. 구조적 관계

PostResponse.WriteFormDTO는 게시판(Post) 작성에 필요한 데이터 폼을 표현하는 DTO이고 이 안에 카테고리 리스트(List<CategoryResponse.CategoryNameDTO>)를 필드로 가지고 있죠. 하지만 CategoryResponse.CategoryNameDTO는 독립된 클래스이며, 단지 이 필드에서 카테고리 정보를 포함하는 용도로 사용되는 것 (CategoryResponse에서만 클래스가 정의 된 것)

2. 쿼리의 $ 사용 이유

이와 상관없이 JPQL에서는 중첩 클래스처럼 보일 때 바이트코드 표기법을 사용해야 하기 때문에 CategoryResponse$CategoryNameDTO처럼 $ 표기법을 사용해야 했던 것이며, 이것은 클래스의 실제 구조와는 상관없이 JPQL의 동작 방식에 따른 규칙
 

3. 결론

CategoryResponse를 참고해서 내부적으로 CategoryNameDTO 찾는다는 것!!
 

3. DTO 만들기

  • CategoryResponse
@Data public static class CategoryNameDTO{ private Integer id; private String categoryName; public CategoryNameDTO(Integer id, String categoryName) { this.id = id; this.categoryName = categoryName; } }
 
  • PostResponse
@Data public static class WriteFormDTO { private List<CategoryResponse.CategoryNameDTO> categoryNameDTO; public WriteFormDTO(List<CategoryResponse.CategoryNameDTO> categoryNameDTO) { this.categoryNameDTO = categoryNameDTO; } }
💡
PostResponse에서 CategoryNameDTO를 innerDTO 만들어서 사용할 수도 있을거 같은데… 일단 CategoryResponse 에서 CategoryNameDTO 만들어줌 게시판 작성할때 카테고리랑 같이 insert시키려면 나중에 변경할 수 도 있을 것 같음
 

4. PostService

@Transactional public PostResponse.WriteFormDTO writeform(Integer sessionUserId){ User sessionUser = userJPARepo.findById(sessionUserId) .orElseThrow(() -> new RuntimeException("회원 정보가 존재하지 않습니다.")); // categoryJPARepo에서 sessionUser.getId()로 유저의 카테고리 목록을 조회하여 categoryList에 담음 List<CategoryResponse.CategoryNameDTO> categoryList = categoryJPARepo.findByUserId(sessionUser.getId()); System.out.println("categoryList = " + categoryList); // categoryList를 사용하여 PostResponse.WriteFormDTO 객체를 생성하고, 이를 writeFormDTO 변수에 할당 PostResponse.WriteFormDTO writeFormDTO = new PostResponse.WriteFormDTO(categoryList); return writeFormDTO; }
 

5. PostController

@GetMapping("/s/post/write-form") public String postWriteForm(HttpServletRequest request) { User user = (User) session.getAttribute("sessionUser"); PostResponse.WriteFormDTO writeFormDTOList = postService.writeform(user.getId()); System.out.println("writeFormDTOList = " + writeFormDTOList); request.setAttribute("model", writeFormDTOList); return "post/writeForm"; }
 

writeFormDTOList가 비어 있으면 카테고리 생성 페이지로 리다이렉트

notion image
@GetMapping("/s/post/write-form") public String postWriteForm(HttpServletRequest request) { User user = (User) session.getAttribute("sessionUser"); PostResponse.WriteFormDTO writeFormDTOList = postService.writeform(user.getId()); System.out.println("writeFormDTOList = " + writeFormDTOList); // 리스트가 비었으면 카테고리 생성 페이지로 리다이렉트 if (writeFormDTOList.getCategoryNameDTO().isEmpty()) { return "redirect:/s/category/write-form"; // 카테고리 생성 페이지로 리다이렉트 } request.setAttribute("model", writeFormDTOList); return "post/writeForm"; }

[ isEmpty ] → 컬렉션이 비어있는지 여부를 확인

notion image

[ 값 잘 받아옴 ]

notion image

6. writeForm.mustache

notion image
 

7. 화면

notion image
 

8. 어라? 카테고리 네임도 공백으로 등록하면 등록됨..

notion image
notion image
 

8-1. CategoryService 로직 추가

@Transactional public void save(String categoryName, Integer sessionUserId) { if (categoryName == null || categoryName.trim().isEmpty()) { throw new RuntimeException("카테고리 이름을 입력해주세요."); } User sessionUser = userJPARepo.findById(sessionUserId) .orElseThrow(() -> new RuntimeException("회원 정보가 존재하지 않습니다.")); Optional<Category> categoryOP = categoryJPARepo.findByCategoryNameAndUserId(categoryName, sessionUserId); if (categoryOP.isPresent()) { throw new RuntimeException("이미 존재하는 카테고리입니다.");} categoryJPARepo.save(Category.builder() .categoryName(categoryName) .user(sessionUser) .build()); }
notion image
 

그런데 생각해보니까 바로 폼 제출 막으면 되잖아!!

8-2. category - writeForm.mustache 스크립트 추가

  • trim() 함수??
    • JavaScript 문자열 함수로, 문자열의 양 끝에 있는 공백 문자(스페이스, 탭, 줄바꿈 등)를 제거
      즉, 사용자가 입력한 값에 불필요한 공백이 있을 경우, 이를 제거하여 깨끗한 문자열을 얻을 수 있다.
// JavaScript를 통해 폼 유효성 검사 $("#categoryForm").on("submit", function (e) { const categoryName = $("#categoryName").val().trim(); if (!categoryName) { alert("카테고리명을 입력해주세요."); e.preventDefault(); // 폼 제출 막기 } });
  • 폼 유효성 검사에서 공백을 제거하지 않으면, 사용자가 빈 문자열이나 공백만 입력해도 폼이 제출될 수 있다. 이를 방지하기 위해 trim()을 사용해, 입력된 내용이 진짜로 있는지 확인할 수 있게 한다.
 

8-3. 화면 - 폼 제출 안됨! 굿

notion image
 

9. SweetAlert을 사용 - 카테고리가 없으면 알림 alert창 띄우고 싶다

notion image
 

9-1. post - writeForm.mustache 스크립트 추가

아… swal.fire 안써서 ㅜㅜ alart창 안띄워져서 한참 헤맸네 ㅜㅜ 아.. 바보 연달아서 안하니까
바로 까먹어버림 ㅜㅜ .fire 잊지말자!!!
notion image
서버가 전달한 noCategory 값을 받아와서 JavaScript 변수로 사용
이 값은 서버에서 전달된 true 또는 false 값

9-2. PostController 수정

//게시글 쓰기 폼 @GetMapping("/s/post/write-form") public String postWriteForm(HttpServletRequest request) { User user = (User) session.getAttribute("sessionUser"); PostResponse.WriteFormDTO writeFormDTOList = postService.writeform(user.getId()); request.setAttribute("model", writeFormDTOList); // 카테고리 네임 비어 있는지 확인 if (writeFormDTOList.getCategoryNameDTO().isEmpty()) { request.setAttribute("noCategory", true); } else { request.setAttribute("noCategory", false); } return "post/writeForm"; }
noCategory 값이 true일 경우 (즉, 카테고리가 없는 경우) SweetAlert을 사용하여 경고창을 띄움. 사용자가 경고창의 확인 버튼을 누르면 카테고리 생성 페이지로 리다이렉트 됨

10. 화면 - 등록 잘됨

notion image
 
notion image
 
Share article

Coding_study