백엔드 17일차 - 실습 : 게시판 만들기

parang·2025년 5월 3일

LG CNS AM Inspire Camp 2기

목록 보기
28/50

이번 강의 시간에는 배운 것들을 총점검하는 시간으로 게시판 만들기 과제가 주어졌다. 만들면서 배웠던 것을 복기하고 어떤 시행착오가 있는지 간단히 정리하려 한다.

페이징 기법

전통 방식

한 페이지당 글 개수 10개.

@GetMapping("pagination") 
public String pagination(Model model, @RequestParam(defaultValue = "1") int page) { 
    int startPage = (page-1) / 10 * 10 + 1; 
    int endPage = startPage + 9; 
    model.addAttribute("startPage", startPage); 
    model.addAttribute("endPage", endPage); 
    model.addAttribute("page", page); 
    return "pagination"; 
}

JPA 기반 페이징

  • Pageable 이용
  • Page<T> 객체로 페이지 정보 및 데이터 제공
  • 검색, 정렬도 자동 연동
@GetMapping("/board/list")
public String boardList(
    @RequestParam(defaultValue = "0") int page,
    Model model) {
    Pageable pageable = PageRequest.of(page, 10, Sort.by("id").descending());
    Page<Board> boardPage = boardRepository.findAll(pageable);

    model.addAttribute("boardPage", boardPage);
    model.addAttribute("currentPage", page);
    return "board/list";
}

두 방식의 비교

항목전통 페이징Spring JPA 페이징
페이징 처리수동(offset 계산)자동(Pageable)
블럭 페이징 (1~10 등)가능 (직접 계산)가능 (계산 필요)
총 페이지 수 계산직접 필요자동 처리
검색/정렬 연동직접 구현메서드명 or @Query
유지보수어려움쉬움
실무 적합도낮음👍 높음

따라서, jpa 방식을 더 많이 사용한다고 함!

Model model

코드를 작성하면서 Model 객체로 넘기는 코드는 필수인데, 개념이 명확하지 않아 헷갈릴 때가 많았다.

Model model 이란?

MVC에서 controller -> view로 데이터를 전달하는 객체.

@GetMapping("/hello")
public String hello(Model model) {
    model.addAttribute("name", "둘리");
    return "hello"; 
    -> hello.html에서 ${name} 으로 접근 가능
}

*
뷰에서 사용 코드 : 
<p th:text="${name}">기본값</p> 

필드 주입 vs 생성자 주입

나는 보통 @Autowired UserRepository userRepository; 이런식으로 필드를 주입해서 작성하는데 나의 gpt 선생님께서는 생성자를 생성해서 코드를 작성하길래 궁금해서 차이를 정리해보았다.

항목필드 주입 (@Autowired)생성자 주입 (final, 생성자)
권장도❌ 비추천 (테스트 어려움)✅ Spring 공식 권장 방식
불변성 보장불가능 (final 아님)가능 (final 필드로 설정)
테스트 용이성Mock 주입 어려움✅ 테스트에서 생성자 통해 직접 주입 가능
컴파일 시점 체크❌ 주입 누락 시 런타임 오류✅ 컴파일 시점에 누락 확인 가능
가독성코드 짧지만 의존성 불투명명확한 의존성 구조 보장
리팩토링 안정성변경 시 영향 범위 넓음안정적인 리팩토링 가능

@Autowired 방식은 테스트 코드에서 의존성 주입을 Mock으로 하기가 어렵기 때문에 테스트할때 좋지 않다.

그와 달리 생성자 주입 방식은

private final UserRepository userRepository;
-> final이 붙어서 반드시 초기화

public UserService(UserRepository userRepository) {
    this.userRepository = userRepository;
}
---
테스트에서
UserService service = new UserService(mockUserRepository); 
이렇게 테스트에서 직접 주입 가능 하고, 
이것이 DI에 가장 잘 부합하는 방법이다.

결론은, 필드 주입 방식보다 생성자 + final 방식으로 작성하는 것이 유지 보수, 테스트 용이 등을 생각하면 훨씬 권장되는 방식이라고 한다.

또한, @RequiredArgsConstructor 를 사용하면 생성자 주입을 더 간결하게 작성 할 수 있다.

RedirectAttributes

오류

  1. 쿼리 오류

UserRepository에서 자꾸 오류가 나서 오류코드를 분석해보니,
No property 'password' found for type 'User' 이런 문구가 났다. User entity에서 정의한 password를 pwd라고 작성한 것을 잊어버렸다가 다르게 작성해서 오류가 난 것이다.

  1. 오타와의 전쟁
    가령 entity에 속성을 created라고 해놨는데 repository 에서 create로 쿼리메소드를 작성했다던지.. 그런 작은 오타가 큰 오류로 돌아온다. ㅎ 꼼꼼하게 처음부터 잘 작성해야 한다!

  2. post 후 실패 시 돌아올 때
    HTML의

    는 POST 방식인데,
    사용자가 한 번 제출 후 뒤로가거나 새로고침을 누르면,
    브라우저는 GET /comment/delete를 시도해 → 이 경로는 없는 GET 핸들러라 오류가 나는 거야.

profile
파랑입니다.

0개의 댓글