[SPRING] 봄 AOP : 어떻게 측면에서 URI 템플릿에서 경로 변수 값을 읽을 수 있습니까?
SPRING봄 AOP : 어떻게 측면에서 URI 템플릿에서 경로 변수 값을 읽을 수 있습니까?
사용자 정의 주석에 의해 주석 처리 된 메서드 매개 변수를 URI 템플릿의 ID로 식별되는 특정 클래스의 인스턴스로 설정하는 Spring aspect를 생성하려고합니다. 경로 변수 이름은 주석의 매개 변수입니다. Spring @PathVariable과 매우 비슷합니다.
그래서 컨트롤러 메소드는 다음과 같습니다.
@RestController
@RequestMapping("/testController")
public class TestController {
@RequestMapping(value = "/order/{orderId}/delete", method = RequestMethod.GET)
public ResponseEntity<?> doSomething(
@GetOrder("orderId") Order order) {
// do something with order
}
}
클래식 대신 :
@RestController
@RequestMapping("/testController")
public class TestController {
@RequestMapping(value = "/order/{orderId}/delete", method = RequestMethod.GET)
public ResponseEntity<?> doSomething(
@PathVariable("orderId") Long orderId) {
Order order = orderRepository.findById(orderId);
// do something with order
}
}
주석 소스 :
// Annotation
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface GetOrder{
String value() default "";
}
애스펙트 소스 :
// Aspect controlled by the annotation
@Aspect
@Component
public class GetOrderAspect {
@Around( // Assume the setOrder method is called around controller method )
public Object setOrder(ProceedingJoinPoint jp) throws Throwable{
MethodSignature signature = (MethodSignature) jp.getSignature();
@SuppressWarnings("rawtypes")
Class[] types = signature.getParameterTypes();
Method method = signature.getMethod();
Annotation[][] annotations = method.getParameterAnnotations();
Object[] values = jp.getArgs();
for (int parameter = 0; parameter < types.length; parameter++) {
Annotation[] parameterAnnotations = annotations[parameter];
if (parameterAnnotations == null) continue;
for (Annotation annotation: parameterAnnotations) {
// Annotation is instance of @GetOrder
if (annotation instanceof GetOrder) {
String pathVariable = (GetOrder)annotation.value();
// How to read actual path variable value from URI template?
// In this example case {orderId} from /testController/order/{orderId}/delete
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder
.currentRequestAttributes()).getRequest();
????? // Now what?
}
} // for each annotation
} // for each parameter
return jp.proceed();
}
}
업데이트 04 / Apr / 2017 :
Mike Wojtyna가 제공 한 답변이이 질문에 답합니다 -> 따라서 받아 들여집니다.
OrangeDog가 제공 한 답변은 새로운 측면의 구현 문제를 위험에 빠뜨리지 않고 기존 Spring 도구와 다른 관점에서 문제를 해결합니다. 이전에 내가 알았 으면이 질문에 답을 얻지 못했습니다.
고맙습니다!
해결법
-
==============================
1.HttpServletRequest에 이미 액세스 할 수있는 경우 HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE spring 템플릿을 사용하여 요청의 모든 속성에 대한 맵을 선택할 수 있습니다. 다음과 같이 사용할 수 있습니다.
HttpServletRequest에 이미 액세스 할 수있는 경우 HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE spring 템플릿을 사용하여 요청의 모든 속성에 대한 맵을 선택할 수 있습니다. 다음과 같이 사용할 수 있습니다.
request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE)
결과는 Map 인스턴스입니다 (불행히도 캐스팅해야 함). 따라서이를 반복하고 필요한 모든 매개 변수를 얻을 수 있습니다.
-
==============================
2.이런 종류의 일을하는 가장 쉬운 방법은 @ControllerAdvice를 여러 컨트롤러간에 공유 할 수있는 @ModelAttribute를 사용하는 것입니다.
이런 종류의 일을하는 가장 쉬운 방법은 @ControllerAdvice를 여러 컨트롤러간에 공유 할 수있는 @ModelAttribute를 사용하는 것입니다.
@ModelAttribute("order") public Order getOrder(@PathVariable("orderId") String orderId) { return orderRepository.findById(orderId); } @DeleteMapping("/order/{orderId}") public ResponseEntity<?> doSomething(@ModelAttribute("order") Order order) { // do something with order }
또 다른 방법은 Order를 지원하는 자신의 PathVariableMethodArgumentResolver를 구현하거나 기존의 @PathVariable 시스템이 사용할 수있는 Converter
를 등록하는 것입니다. -
==============================
3.주석이 항상 첫 번째 매개 변수라고 가정하면 어쩌면 이렇게 할 수 있습니다.
주석이 항상 첫 번째 매개 변수라고 가정하면 어쩌면 이렇게 할 수 있습니다.
package de.scrum_master.aspect; import java.lang.annotation.Annotation; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import de.scrum_master.app.GetOrder; @Aspect @Component public class GetOrderAspect { @Around("execution(* *(@de.scrum_master.app.GetOrder (*), ..))") public Object setOrder(ProceedingJoinPoint thisJoinPoint) throws Throwable { MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature(); Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations(); for (Annotation[] annotations : annotationMatrix) { for (Annotation annotation : annotations) { if (annotation instanceof GetOrder) { System.out.println(thisJoinPoint); System.out.println(" annotation = " + annotation); System.out.println(" annotation value = " + ((GetOrder) annotation).value()); } } } return thisJoinPoint.proceed(); } }
콘솔 로그는 다음과 같습니다.
execution(ResponseEntity de.scrum_master.app.TestController.doSomething(Order)) annotation = @de.scrum_master.app.GetOrder(value=orderId) annotation value = orderId
매개 변수 주석이 임의의 위치에 나타날 수있는 경우에는 pointcut 실행 (* * (..))을 사용할 수도 있지만 응용 프로그램의 각 구성 요소에 대한 모든 메소드 실행을 캡처하므로 매우 효율적이지는 않습니다. 그래서 적어도 다음과 같이 요청 매핑이있는 REST 컨트롤러 및 / 또는 메소드로 제한해야합니다.
@Around("execution(@org.springframework.web.bind.annotation.RequestMapping * (@org.springframework.web.bind.annotation.RestController *).*(..))")
이것의 변종은
@Around( "execution(* (@org.springframework.web.bind.annotation.RestController *).*(..)) &&" + "@annotation(org.springframework.web.bind.annotation.RequestMapping)" )
from https://stackoverflow.com/questions/43183537/spring-aop-how-to-read-path-variable-value-from-uri-template-in-aspect by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 스프링 프레임 워크 로깅을 활성화 할 수 없습니다. (0) | 2019.05.24 |
---|---|
[SPRING] 기본 키의 일부가 외래 키인 JPA에서 복합 기본 키를 매핑하는 방법 (0) | 2019.05.24 |
[SPRING] 왜 @Service가 bean을 만들지 않는 것처럼 클래스에 주석을 붙이겠습니까? (0) | 2019.05.24 |
[SPRING] @RequestMapping이 올바르게 매핑되지 않았습니다. (0) | 2019.05.24 |
[SPRING] HttpServletRequest에서 XML 가져 오기 및 끝점에 사용 (0) | 2019.05.24 |