인터셉터 + 공통 레이아웃
@PostMapping("/board/write")
public String write(...) {
if (session.getAttribute("loginUser") == null) return "redirect:/login";
... 작성 처리 ...
}
@PostMapping("/board/update")
public String update(...) {
if (session.getAttribute("loginUser") == null) return "redirect:/login";
... 수정 처리 ...
}
@PostMapping("/board/delete")
public String delete(...) {
if (session.getAttribute("loginUser") == null) return "redirect:/login";
... 삭제 처리 ...
}
같은 코드가 컨트롤러마다 반복. 5 곳에 있다면 5 번, 10 곳에 있다면 10 번. 한 곳 빠뜨리면 보안 구멍.
로그인 후 헤더에 「hong123 님 환영합니다」 — 아이디를 그대로 노출. 표시용 닉네임이 필요해진 시점.
→ Member 에 nick 필드 추가 + 테이블 ALTER ADD COLUMN.
-- v3 → v4: 표시용 닉네임 컬럼 추가
ALTER TABLE mymember ADD COLUMN nick VARCHAR(30) AFTER pwd;
package com.smhrd.domain;
@Data @AllArgsConstructor @NoArgsConstructor
public class Member {
private String id;
private String pwd;
private String nick; // ← 추가
}
👉 회원가입 폼에도 <input name="nick"> 한 줄 추가. 폼의 name 만 맞으면 백엔드는 자동.
요청이 컨트롤러 메서드에 도달하기 전에 끼어들어서, 비로그인 사용자를 차단하는 부품. 「식당 입구의 가드」 비유.
package com.smhrd.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.*;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
HttpSession session = request.getSession();
if (session.getAttribute("loginUser") == null) {
// 비로그인 → 로그인 페이지로
response.sendRedirect(request.getContextPath() + "/login");
return false; // ⭐ Controller 호출 안 함
}
return true; // ⭐ 통과 — Controller 호출
}
}
preHandle = 컨트롤러 호출 「전」 실행
👉 다른 메서드도 있음 (postHandle, afterCompletion) 이지만 인증 가드엔 preHandle 만으로 충분.
<!-- servlet-context.xml -->
<beans xmlns:mvc="http://www.springframework.org/schema/mvc" ...>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/board/write"/>
<mvc:mapping path="/board/update"/>
<mvc:mapping path="/board/delete"/>
<mvc:mapping path="/mypage/**"/>
<!-- 예외 -->
<mvc:exclude-mapping path="/login"/>
<mvc:exclude-mapping path="/signup"/>
<beans:bean class="com.smhrd.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
| 패턴 | 의미 |
|---|---|
/board/write | 정확히 이 URL |
/board/* | /board/ 직속 한 단계 |
/mypage/** | /mypage/ 하위 모든 깊이 |
/api/boards/*/comments | 중간 한 단계 와일드카드 |
@PostMapping("/board/write")
public String write(Board b, HttpSession session) {
if (session.getAttribute("loginUser") == null) {
return "redirect:/login"; // ← 가드 코드
}
Member u = (Member) session.getAttribute("loginUser");
b.setWriter(u.getId());
service.insert(b);
return "redirect:/board/list";
}
👉 글쓰기·수정·삭제·마이페이지마다 같은 if 가 반복됩니다.
@PostMapping("/board/write")
public String write(Board b, HttpSession session) {
// if 체크 사라짐 — 인터셉터가 보장
Member u = (Member) session.getAttribute("loginUser");
b.setWriter(u.getId());
service.insert(b);
return "redirect:/board/list";
}
👉 가드 코드가 사라졌습니다. 컨트롤러는 「업무 그 자체」만 표현.
<!-- /WEB-INF/views/common/header.jsp -->
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<header>
<a href="/">홈</a>
<a href="/board/list">게시판</a>
<c:choose>
<c:when test="${not empty sessionScope.loginUser}">
<span>${sessionScope.loginUser.nick}님</span>
<a href="/logout">로그아웃</a>
<a href="/mypage">마이페이지</a>
</c:when>
<c:otherwise>
<a href="/login">로그인</a>
<a href="/signup">회원가입</a>
</c:otherwise>
</c:choose>
</header>
<!-- /WEB-INF/views/board/list.jsp -->
<%@ page contentType="text/html; charset=UTF-8" %>
<html>
<body>
<%@ include file="/WEB-INF/views/common/header.jsp" %>
<h1>게시판</h1>
<table>...</table>
<%@ include file="/WEB-INF/views/common/footer.jsp" %>
</body>
</html>
👉 모든 JSP 가 같은 헤더를 공유. 헤더 수정 시 한 곳만 고치면 모든 페이지가 즉시 반영.
| 방식 | <%@ include %> | <jsp:include> |
|---|---|---|
| 처리 시점 | 컴파일 타임 | 런타임 |
| 변수 공유 | 가능 | 불가 |
| 성능 | 빠름 | 약간 느림 |
| 수정 반영 | 전체 재컴파일 | 즉시 |
| 쓰임 | 정적 영역 (헤더/푸터) | 동적 영역 |
👉 본 과정의 헤더/푸터는 <%@ include %> 로 충분.
| 측면 | v3 | v4 |
|---|---|---|
| 로그인 가드 코드 | 각 컨트롤러에 반복 | 인터셉터 한 곳 |
| URL 추가 시 | 가드 코드도 추가 (잊으면 보안 구멍) | 매핑 한 줄만 |
| 화면 헤더 | 각 JSP 에 반복 | 한 파일 |
| 로그인 사용자 표시 | 없음 | 모든 페이지에 자동 |
/board/write 직접 접속 → 자동으로 /login 으로 이동/login👉 「공통 처리」가 필요한 모든 곳에 인터셉터.
v4 는 「코드 정돈」의 차시입니다. 새 기능 추가는 없지만:
동작은 같지만 코드는 훨씬 깔끔. 실무에서 매일 보는 코드 품질의 단계.
인증은 동작한다. 하지만 컨트롤러마다 가드 코드가 반복. 헤더에 로그인 표시 없음.
인터셉터 한 곳이 모든 가드. 헤더 한 곳이 모든 페이지의 로그인 상태 표시. 코드 깔끔.
<mvc:interceptors> 등록<%@ include %> 로 공통 레이아웃다음: v5 최소 게시판 — Create + Read 만 (인가 없음).