AOP 관점지향 프로그래밍 - 전처리, 후처리
전처리와 후처리를 나누기 전 클라이언트에서 userName, Password 등 데이터를 입력해서 요청하면 서버와 DB를 걸친 뒤에 응답한다. 이런 경우, userName이나 Password에 설정한 길이 또는 userName의 동일 여
bpeach.tistory.com
전에 작성한 AOP 관점지향 프로그래밍을 이제 객체 지향 프로그래밍과 합해 코드를 간단하게 만들어 보려고 한다.
먼저 전처리와 후처리, 그리고 공통 기능을 파악해야 한다.
로그인 | 회원가입 | |
전처리 | 유효성 검사, 보안처리 | 유효성 검사, 보안처리 |
핵심 | username, password | username, password, address, name ... |
DB - SELECT | DB - INSERT | |
로그인 완료(세션 만드는 것) | ||
후처리 | 로그(언제 로그인 했는 지 등) | 로그(언제 회원가입 했는 지 등) |
예시로 로그인과 회원가입 기능을 보며 전처리와 후처리가 동일한 기능을 한다. 공통기능으로 묶어 필터링 처리를 하면 된다.
@RequiredArgsConstructor
@Controller
public class AuthController{
private static final Logger log = LoggerFactory.getLogger(AuthController.class);
private final AuthService authService;
....
@PostMapping("auth/signup")
public String signup(@Valid SignupDto signupDto, BindingResult bindingResult){
if(bindingResult.hasErrors()){ //Valid에서 선정한 max, notbink의 에러가 발생한다면
Map<String, String> errorMap = new HashMap<>();
for(FieldError error : bindingResult.getFieldErrors()){
errorMap.put(error.getField(), error.getDefaultMessage());
}
//사용자에게 보이면 좋은 UX가 아니기 때문에 Exception을 가로채는 Handler패키지 만듦
throw new CustomValidationException("유효성검사 실패함", errorMap);
}else{
User user = signupDto.toEntity(); //User에 대한 데이터 넣음
User userEntity = authService.회원가입(user);
return "auth/singin"; //회원가입 성공 시 로그인 페이지로 이동
}
}
}
기존에는 Controller에서 유효성 검사가 필요한 메서드에 하나하나 작성했다.
이제는 위에서 말한 것처럼 공통기능을 묶어서 핸들러 할 수 있게 하려고 한다.
먼저 ValidationAdvice라는 클래스 하나를 생성하고 여기서 Advice은 공통기능이라는 뜻
@Component
@Aspect
public class ValidatonAdvice{
@Around("execution(* com.cos.photogramstart.web.api.*Controller.*(..))")
public Object apiAdive(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
Object[] args = proceedingJoinPoint.getArgs();
for(Object arg : args){
if(arg instanceof BindingResult){
System.out.println("유효성 검사하는 함수입니다");
BindingResult bindingResult = (BindingResult) arg;
if(bindingResult.hasErrors()){
Map<String, String> errorMap = new HashMp<>();
for(FieldError error : bindingResult.getFieldErrors()){
errorMap.put(error.getField(), error.getDefaultMessage());
}
throw new CustomValidationApiException("유효성 검사 실패", errorMap);
}
}
}
return proceedingJoinPoin.proceed(); //그 함수로 다시 돌아가라
}
@Around("execution(* com.cos.phtogramstart.web.*Controller.*(..))")
public Object advice(ProceedingJoinPoint proceedingJoinPoint) throw Throwable{
Object[] args = proceedingJoinPoint.getArgs();
for(Object arg : args){
if(arg instanceof BindingResult){
System.out.println("유효성 검사하는 함수입니다.");
BindingResult bindingResult = (Binding)arg;
if(bindingResult.hasError()){
Map<String, String> errorMap = new HashMap<>();
for(FieldError error : bindingResult.getFieldErrors()){
errorMap.put(error.getField(), error.getDefaultMessage());
}
throw new CustomValidationException("유효성 검사 실패함", errorMap);
}
}
}
return proceedingJoinPoint.proceed();
}
}
- @Component : RestController, Service 모든 것들이 Component를 상속해서 만들어져 있다.
- @Aspect : AOP 할 수 있는 Handler 애너테이션
- @Around : @Before와 @After 모두 사용해서 앞과 뒤에서 체크 가능한 애너테이션, (처음에 나온 * 은 public, proctected, private 등 함수 정하는 건데 모두 사용할 거니까 * 로 표시, *(..)은 모든 컨트롤러가 작동할 때 모든 함수가 작동한다는 것을 의미함)
- ProceedingJoinPoint : 함수의 파라미터뿐만 아니라 내부 정보에 접근할 수 있는 파라미터(여기서는 Controller 안에 있는 함수의 모든 곳에 접근할 수 있는 변수로, Controller 안에 있는 함수들보다 먼저 실행함)
ProceedingJoinPoint를 좀 더 자세히 설명하면, 공통기능인 Advice를 실행할 때 사용되는 지점에서 나타나고, Adivce가 적용될 수 있는 지점(메서드 호출, 예외 발생 등)을 가리키며, Advice가 실행되는 동안 해당 지점에서의 실행 흐름을 제어할 수 있음. 이를 통해 AOP를 사용하여 로깅, 트랜잭션 관리, 보안 등과 같은 횡단 관심사를 분리된 모듈로 처리할 수 있다.
@RequiredArgsConstructor
@Controller
public class AuthController{
private static final Logger log = LoggerFactory.getLogger(AuthController.class);
private final AuthService authService;
....
@PostMapping("auth/signup")
public String signup(@Valid SignupDto signupDto, BindingResult bindingResult){
log.info(signupDto.toString());
User user = signupDto.toEntity();
authService.회원가입(user);
return "auth/singin"; //회원가입 성공 시 로그인 페이지로 이동
}
}
위의 Adivce 클래스를 따로 구현하면 원래 작성했던 authControllerr의 signup 함수를 간단하게 작성할 수 있다.
'WEB > spring' 카테고리의 다른 글
Spring Security란? (1) (0) | 2024.01.18 |
---|---|
페이스북 로그인 연동 (0) | 2023.12.22 |
JPA open-in-view와 Lazy 연관 (0) | 2023.12.14 |
JPA에서 사용되는 EAGER(즉시로딩)과 LAZY(지연로딩) (0) | 2023.12.14 |
웹 페이지를 만들 때, 사진에서 엑박 생기는 이유와 UUIID 사용해서 이미지 이름 지정 (0) | 2023.12.14 |