![[Tistory] 카테고리 조회 (카테고리가 없으면 redirect)](https://image.inblog.dev?url=https%3A%2F%2Finblog.ai%2Fapi%2Fog%3Ftitle%3D%255BTistory%255D%2520%25EC%25B9%25B4%25ED%2585%258C%25EA%25B3%25A0%25EB%25A6%25AC%2520%25EC%25A1%25B0%25ED%259A%258C%2520%28%25EC%25B9%25B4%25ED%2585%258C%25EA%25B3%25A0%25EB%25A6%25AC%25EA%25B0%2580%2520%25EC%2597%2586%25EC%259C%25BC%25EB%25A9%25B4%2520redirect%29%2520%26logoUrl%3Dhttps%253A%252F%252Finblog.ai%252Finblog_logo.png%26blogTitle%3DCoding_study&w=2048&q=75)
Contents
1. 게시글 쓸 때, 카테고리 조회2. CategoryJPARepository3. DTO 만들기4. PostService5. PostController6. writeForm.mustache7. 화면8. 어라? 카테고리 네임도 공백으로 등록하면 등록됨..8-1. CategoryService 로직 추가8-2. category - writeForm.mustache 스크립트 추가8-3. 화면 - 폼 제출 안됨! 굿9. SweetAlert을 사용 - 카테고리가 없으면 알림 alert창 띄우고 싶다9-1. post - writeForm.mustache 스크립트 추가9-2. PostController 수정10. 화면 - 등록 잘됨1. 게시글 쓸 때, 카테고리 조회

여기에 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$CategoryNameDTO
와 CategoryResponse.CategoryNameDTO
의 차이는 문법적인 관점에서 접근[ 해결 ]

화면을 보면 게시판 쓸때 카테고리 리스트가 안에 있기 때문에
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가 비어 있으면 카테고리 생성 페이지로 리다이렉트

@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 ] → 컬렉션이 비어있는지 여부를 확인

[ 값 잘 받아옴 ]

6. writeForm.mustache

7. 화면

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


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());
}

그런데 생각해보니까 바로 폼 제출 막으면 되잖아!!
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. 화면 - 폼 제출 안됨! 굿

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

9-1. post - writeForm.mustache 스크립트 추가
아…
swal.fire
안써서 ㅜㅜ alart창 안띄워져서 한참 헤맸네 ㅜㅜ 아.. 바보 연달아서 안하니까 바로 까먹어버림 ㅜㅜ .fire 잊지말자!!!

서버가 전달한 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. 화면 - 등록 잘됨


Share article