로그인 게시판 하나를 처음부터 끝까지 — 1차 기본 구조부터 3차 심화 리팩토링까지, 단계별 진화 흐름 전체 정리
하나의 게시판 프로젝트를 4단계로 점진적으로 발전시킨다. 매 단계마다 이전 단계의 문제를 해결하는 방식으로 진행되기 때문에, 순서대로 따라가면 "왜 이렇게 만드는가"가 자연스럽게 이해된다.
각 단계의 핵심 목적, 해결하는 문제, 새로 등장하는 기술을 한눈에 정리했다.
Spring Boot 프로젝트의 전체 레이어 구조를 이해한다. Controller → Service → Repository → Entity 흐름이 어떻게 연결되는지, 서버가 HTML을 직접 만들어서 브라우저에 보내는 방식이 어떻게 동작하는지 직접 경험한다.
@Controller — 뷰 이름(String) 반환, Thymeleaf 렌더링HttpSession — 로그인 상태를 서버 메모리에 보관@ModelAttribute — HTML form 데이터를 DTO로 자동 바인딩Thymeleaf — 서버 사이드 템플릿 (th:each, th:if, @{}, ${})Page<Board> — JPA Pageable로 목록 페이징BCryptPasswordEncoder — 비밀번호 단방향 암호화@PrePersist — 저장 전 자동 실행되는 생명주기 메서드더티체킹 — UPDATE 없이 필드만 변경해도 자동 DB 반영session.getAttribute("loginUser") 반복1차의 두 가지 문제를 동시에 해결한다. React로 화면을 분리해서 백엔드는 JSON만 반환하도록 바꾸고, JwtFilter 하나로 인증 반복 코드를 없앤다. 백엔드와 프론트엔드가 완전히 독립적으로 동작하는 구조를 경험한다.
@RestController — JSON(ResponseEntity) 반환@RequestBody — JSON 요청을 DTO로 자동 변환JWT — Header.Payload.Signature 구조, 서버 저장 없는 인증JwtUtil — 토큰 생성/검증/파싱JwtFilter (OncePerRequestFilter 상속) — 요청마다 토큰 검증FilterRegistrationBean — 필터 수동 등록, URL 패턴 지정@Value — application.properties 값 주입Page<BoardDto> — Entity → DTO 변환 후 반환axios interceptor — 모든 요청에 토큰 자동 첨부PrivateRoute — 토큰 없으면 로그인 페이지로 강제 이동jwtDecode — 프론트에서 토큰 Payload 읽기 (본인 글 여부 확인)request.getAttribute("loginUser") 직접 꺼내야 함2차의 임시방편 JwtFilter를 Spring Security 표준 방식으로 교체한다. ROLE_USER / ROLE_ADMIN 역할 기반 권한 분리, AdminController 추가, SecurityConfig 하나로 인증/권한/CORS 통합 관리. Controller 코드가 훨씬 깔끔해진다.
spring-boot-starter-security — Security 전체 도입SecurityConfig — FilterChain, CSRF/CORS/권한 통합 설정UserDetails 인터페이스 — Spring Security 표준 인증 객체CustomUserDetails — User Entity를 UserDetails로 감싸는 래퍼CustomUserDetailsService — loadUserByUsername() 구현JwtAuthenticationFilter — SecurityContextHolder에 인증 저장SecurityContextHolder — 스레드 단위 인증 정보 저장소@AuthenticationPrincipal — Controller에 인증 주체 자동 주입hasRole("ADMIN") — URL별 역할 기반 접근 제어SessionCreationPolicy.STATELESS — 세션 미사용 설정addFilterBefore() — FilterChain에 커스텀 필터 삽입User.role 필드 — ROLE_USER / ROLE_ADMINAdminController / AdminService — 유저/게시글 관리 기능deleteByUser() — JPA 쿼리 메서드 자동 생성기능을 추가하는 게 아니라 기존 3차 코드를 실무 수준으로 리팩토링한다. 기존 코드 한 줄도 건드리지 않고 AOP로 자동 로깅을 추가하고, 흩어져 있던 예외 처리를 한 곳으로 모으고, DTO 생성 방식을 Builder 패턴으로 개선한다.
spring-boot-starter-aop 추가3차 심화까지 완성하면 실무 백엔드 기본기는 완성된 상태다. Docker·AWS 배포는 인프라 영역으로, 취업 목표와 관심사에 따라 선택적으로 진행한다.
| 항목 | 1차 | 2차 | 3차 | 3차 심화 |
|---|---|---|---|---|
| 화면 담당 | Thymeleaf (서버 렌더링) | React (클라이언트 렌더링) | React (동일) | React (동일) |
| 인증 방식 | HttpSession (서버 메모리) | JWT 토큰 (localStorage) | JWT + Security (동일) | 동일 |
| 인증 필터 | 없음 (Controller마다 직접 체크) | JwtFilter (수동 등록) | JwtAuthenticationFilter (Security 통합) | 동일 |
| 로그인 사용자 가져오기 | session.getAttribute() 반복 |
request.getAttribute() 반복 |
@AuthenticationPrincipal 자동 주입 |
동일 |
| 권한 관리 | 없음 | 없음 | ROLE_USER / ROLE_ADMIN | 동일 |
| 예외 처리 | Controller마다 try/catch | Controller마다 try/catch | Controller마다 try/catch | GlobalExceptionHandler 통합 |
| 로깅 | 없음 | 없음 | 없음 | AOP LogAspect 자동 |
| DTO 변환 | 직접 Setter | 직접 Setter | 직접 Setter | @Builder 패턴 |
| 컨트롤러 반환 | String (뷰 이름) | ResponseEntity (JSON) | ResponseEntity (JSON) | ResponseEntity (JSON) |
| 데이터 수신 | @ModelAttribute (form) | @RequestBody (JSON) | @RequestBody (JSON) | @RequestBody (JSON) |
| 관리자 기능 | 없음 | 없음 | AdminController + AdminPage | 동일 |
| 포트 구성 | 통합 8081 | 8082 / 3001 분리 | 8083 / 3002 분리 | 8083 / 3002 분리 |
이 HTML 학습 문서 시리즈의 권장 학습 순서다. 프로젝트 파일(04~05)은 기초 개념(01~03)을 먼저 이해한 후 보는 것을 권장하지만, 프로젝트가 먼저 궁금하다면 04부터 봐도 무방하다.
처음부터 끝까지 한 가지 프로젝트(게시판)의 진화 흐름을 따라가며 Spring Boot 백엔드 개발의 핵심을 익힌다. 각 파일은 독립적으로 볼 수도 있지만, 순서대로 보면 "왜 이렇게 만드는가"가 자연스럽게 연결된다. 모든 내용은 실제 프로젝트 코드 기준으로 작성되었다.