AOP (Aspect-oriented Programming) 관점 지향 프로그래밍
관점 지향 프로그래밍으로 여러 관점에 따라 사용되는 기능들을 모듈화하여 처리하는 프로그래밍 패러다임이다.
예를 들어 게시판 기능을 만든다고 했을 때, 파란색 박스는 회원, 비회원이 모두 이용 가능한 기능이고 빨간색 박스는 회원만 이용 가능한 기능이라면 이 또한 관점 지향 프로그래밍에 해당한다. 기능 분리말고도 컨트롤러, 리파지토리, 컴포넌트 관점 등 역할로도 관점을 분리하여 여러 관점으로 묶어 볼 수 있다. 당연히 회원 + 비회원 기능은 모든 사용자가 접근 할 수 있지만, 회원 기능은 비회원은 접근하지 못하는 기능이다. 이 관점에서 볼 때 간섭을 하여 작업을 추가하면 회원이 이용할 수 있는 기능과 비회원이 이용할 수 있는 기능을 모두 분리할 수 있다. 간섭은 대상을 찾아 그 대상의 행위를 바꾸는 것을 말한다.
Interceptor
지정한 주소에 대해서 특정 시점에 개입할 수 있는 도구
- `HandlerInterceptor` 인터페이스를 상속받아 구현
- `@Service`를 등록하여 복잡한 작업을 한번에 수행하는 도구를 의미
- `preHandle()`, `postHandle()`, `afterCompletion()` 재정의
@Service
public class TestLogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("TestLogInterceptor 실행!");
return false;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("Handler = " + handler);
System.out.println("MAV = "+ modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("handler = " + handler);
System.out.println("exception = " + ex);
}
}
HandlerInterceptor
HTTP 요청을 처리하는 과정에서 특정 작업을 수행할 수 있도록 도와주는 인터페이스
preHandle()
컨트롤러 실행 이전 시점(3번)에 간섭하는 메서드 (`true`, `false`를 반환하여 접근 제한 처리)
- `HttpServletRequest request` - HTTP 요청에 대한 정보를 담고 있는 객체
- `HttpServletResponse response` - HTTP 응답을 제어하는 객체
- `Object handler` - 현재 요청을 처리할 핸들러(컨트롤러)를 나타내는 객체
postHandle()
컨트롤러 실행 완료 시점(6번)에 간섭하는 메서드
- 로그 확인하는데 사용
afterCompletion()
화면 생성 완료 시점(8번)에 간섭하는 메서드
- 로그 확인하는데 사용
preHandle() 처리 방법
@Service
public class MemberLoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession();
String userId = (String) session.getAttribute("userId");
if(userId != null) {
return true;
}
else {
//1. 로그인 페이지로 리다이렉트
//response.sendRedirect("/member/login");
//return false;
//2. HTTP 상태코드를 반환 (401)
//response.sendError(401);
//return false;
//3. 커스텀 예외처리
throw new NoPermissionException("로그인 후 이용 가능합니다");
}
}
}
로그인 성공 시
`true`로 반환하여 통과
로그인 실패 시
1. 로그인 페이지로 리다이렉트
response.sendRedirect("/member/login");
return false;
2. HTTP 상태코드 반환
response.sendError(401);
return false;
3. 커스텀 예외처리 (`RuntimeException`을 상속)
throw new NoPermissionException("로그인 후 이용 가능합니다");
preHandle() request 사용 예시
@Service
public class BoardOwnerInterceptor implements HandlerInterceptor {
@Autowired
private BoardDao boardDao;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession();
String userId = (String) session.getAttribute("userId");
if(userId == null) {
throw new NoPermissionException("로그인이 필요합니다");
}
Long boardNo = Long.parseLong(request.getParameter("boardNo"));
BoardDto boardDto = boardDao.selectOne(boardNo);
if(boardDto == null) {
throw new NoPermissionException("존재하지 않는 글입니다");
}
if(boardDto.getBoardWriter() == null) {
throw new NoPermissionException("탈퇴한 사용자의 글입니다");
}
if(userId.equals(boardDto.getBoardWriter())) {
return true;
}
throw new NoPermissionException("글을 수정할 권한이 없습니다");
}
}
request.getSession()
현재 Http 요청과 관련된 세션 객체 (`Session Object`)를 반환하는 메서드
HttpSession session = request.getSession();
request.getParameter()
HTTP 요청의 쿼리 파라미터 또는 폼 데이터에서 인자로 들어온 `key`의 값을 가져오는 메서드
Long boardNo = Long.parseLong(request.getParameter("boardNo"));
Configuration
`application.properties`에서 할 수 없는 복잡한 설정을 구현할 때 사용
- `@Configuration` 등록
- `WebMvcConfiguerer` 인터페이스를 상속받아 구현
- 인터셉터 주입 (DI)
- `addInterceptors()` 재정의
@Configuration
public class InterceptorConfiguration implements WebMvcConfigurer {
@Autowired
private MemberLoginInterceptor memberLoginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(memberLoginInterceptor)
.addPathPatterns(List.of(
"/member/**",
"/game-user/**"
))
.excludePathPatterns(List.of(
"/member/join*",
"/member/login",
"/member/exitFinish"
));
}
}
@Configuration
Spring의 설정 클래스임을 명시하는 어노테이션
WebMvcConfigurer
웹 애플리케이션의 설정을 구성할 수 있도록 도와주는 인터페이스
addInterceptors()
HTTP 요청 처리 전에 특정 로직을 실행할 수 있는 인터셉터를 추가하는 메서드
InterceptorRegistry
인터셉터를 등록하고 경로 패턴을 지정하는 클래스
.addInterceptor()
인터셉터를 등록하는 메서드
.addPathPatterns()
해당 경로 패턴에 인터셉터를 적용하는 메서드
.excludePathPatterns()
특정 경로 패턴을 인터셉터에서 제외하는 메서드
- /member/** - /member 하위 주소 모두 차단
- /member/* - /member가 엔드포인트인 주소만 차단
- /member* - member가 포함된 주소 차단
'Java > Spring Boot' 카테고리의 다른 글
[Java / Spring Boot] Service (0) | 2025.02.10 |
---|---|
[Java / Spring Boot] DBCP (0) | 2025.02.10 |
[Java / Spring Boot] Session (0) | 2025.01.15 |
[Java / Spring Boot] Model과 MVC 패턴 (0) | 2025.01.14 |
[Java / Spring Boot] Forward와 Redirect (0) | 2025.01.14 |