[SPRING] 스프링에서 JSON 응답을 래핑하는 방법은 무엇입니까?
SPRING스프링에서 JSON 응답을 래핑하는 방법은 무엇입니까?
스프링에 두 세트의 컨트롤러가 있다고 가정합니다.
둘 다 JSON 텍스트로 해석 될 객체를 반환합니다.
이러한 종류의 컨트롤러에서 응답을 래핑하는 일종의 필터가 필요합니다.
위의 작업을 수행하기 위해 WebMvcConfigurerAdapter.configureMessageConverters에 전달 된 MappingJackson2HttpMessageConverter를 현재 사용자 지정하고 있습니다. 이 접근법이 적용되는 URL (또는 컨트롤러 클래스)에 대해 선택적인 것으로 보이지 않는 것을 제외하고는 훌륭하게 작동합니다.
이러한 종류의 래퍼를 개별 컨트롤러 클래스 나 URL에 적용 할 수 있습니까?
업데이트 : 서블릿 필터는 솔루션처럼 보입니다. 어떤 필터가 어떤 컨트롤러 메소드 또는 어떤 URL에 적용되는지 선택할 수 있습니까?
해결법
-
==============================
1.내가 당신의 질문을 이해하는 방식으로, 정확히 세 가지 선택이 있습니다.
내가 당신의 질문을 이해하는 방식으로, 정확히 세 가지 선택이 있습니다.
옵션 1
필요한 필드가있는 간단한 SuccessResponse, ErrorResponse, SomethingSortOfWrongResponse 등의 개체에 개체를 수동으로 래핑하십시오. 이 시점에서 응답 요청자의 유연성을 확보 할 수 있습니다. 응답 래퍼 중 하나의 필드를 변경하는 것은 간단하며 많은 컨트롤러 요청 메서드를 함께 그룹화 할 수 있고 함께 그룹화해야하는 경우 코드 반복이 유일한 단점입니다.
옵션 # 2
언급했듯이 필터는 더러운 작업을하도록 설계 될 수 있지만 Spring 필터는 요청 또는 응답 데이터에 대한 액세스 권한을 부여하지 않습니다. 다음과 같은 모양의 예가 있습니다.
@Component public class ResponseWrappingFilter extends GenericFilterBean { @Override public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) { // Perform the rest of the chain, populating the response. chain.doFilter(request, response); // No way to read the body from the response here. getBody() doesn't exist. response.setBody(new ResponseWrapper(response.getStatus(), response.getBody()); } }
해당 필터에서 본문을 설정하는 방법을 찾으면 네, 쉽게 마무리 할 수 있습니다. 그렇지 않으면이 옵션은 막 다른 길입니다.
옵션 # 3
아하. 그래서 너는 이걸 가지고있어. 코드 중복은 옵션이 아니지만 컨트롤러 메소드의 응답을 래핑하는 것이 좋습니다. Spring이 좋아하게 지원하는 AOP (aspect-oriented programming)라는 진정한 솔루션을 소개하고자합니다.
AOP에 익숙하지 않다면 전제는 다음과 같습니다 : 정규 표현식과 일치하는 표현식을 코드에서 정의하십시오. 이 점을 결합 점이라고 부르며, 일치하는 표현식을 점 점 (pointcut)이라고합니다. 그런 다음 pointcut 또는 pointcuts 조합이 일치하면 advice라고하는 추가 임의 코드를 실행할 수 있습니다. pointcuts와 조언을 정의하는 객체를 aspect라고 부릅니다.
Java에서 더 유창하게 자신을 표현하는 데 좋습니다. 유일한 단점은 더 약한 정적 유형 검사입니다. 더 이상 신경 쓸 필요없이 aspect 지향 프로그래밍에서의 응답 포장은 다음과 같습니다.
@Aspect @Component public class ResponseWrappingAspect { @Pointcut("within(@org.springframework.stereotype.Controller *)") public void anyControllerPointcut() {} @Pointcut("execution(* *(..))") public void anyMethodPointcut() {} @AfterReturning( value = "anyControllerPointcut() && anyMethodPointcut()", returning = "response") public Object wrapResponse(Object response) { // Do whatever logic needs to be done to wrap it correctly. return new ResponseWrapper(response); } @AfterThrowing( value = "anyControllerPointcut() && anyMethodPointcut()", throwing = "cause") public Object wrapException(Exception cause) { // Do whatever logic needs to be done to wrap it correctly. return new ErrorResponseWrapper(cause); } }
최종 결과는 사용자가 추구하는 반복되지 않는 응답 배치입니다. 하나 또는 그 이상의 컨트롤러가이 효과를 받기를 원할 경우, (@Controller 어노테이션이있는 클래스가 아닌) 해당 컨트롤러의 인스턴스 내에서만 메소드와 일치하도록 pointcut을 업데이트하십시오.
AOP 의존성을 포함하고, 구성 클래스에 AOP 사용 가능 주석을 추가하고, 구성 요소가이 클래스가있는 패키지를 스캔하는지 확인해야합니다.
-
==============================
2.나는 이것을 여러 날 동안 고민하고있었습니다. @Misha의 해결책은 저에게 효과적이지 않았습니다. 나는 ControllerAdvice와 ResponseBodyAdvice를 사용하여이 작업을 마침내 얻을 수있었습니다.
나는 이것을 여러 날 동안 고민하고있었습니다. @Misha의 해결책은 저에게 효과적이지 않았습니다. 나는 ControllerAdvice와 ResponseBodyAdvice를 사용하여이 작업을 마침내 얻을 수있었습니다.
ResponseBodyAdvice를 사용하면 컨트롤러가 반환하지만 HttpResponse로 변환되어 커밋되기 전에 사용자 지정 변환 논리를 응답에 삽입 할 수 있습니다.
이것이 내 컨트롤러 메소드의 모습입니다.
@RequestMapping("/global/hallOfFame") public List<HallOfFame> getAllHallOfFame() { return hallOfFameService.getAllHallOfFame(); }
이제는 devmessage 및 usermessage와 같은 응답에 몇 가지 표준 필드를 추가하려고했습니다. 그 논리는 ResponseAdvice에 들어갑니다.
@ControllerAdvice public class TLResponseAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { // TODO Auto-generated method stub final RestResponse<Object> output = new RestResponse<>(); output.setData(body); output.setDevMessage("ResponseAdviceDevMessage"); output.setHttpcode(200); output.setStatus("Success"); output.setUserMessage("ResponseAdviceUserMessage"); return output; } }
엔티티 클래스는 다음과 같습니다.
@Setter // All lombok annotations @Getter @ToString public class RestResponse<T> { private String status; private int httpcode; private String devMessage; private String userMessage; private T data; } @Entity @Data // Lombok public class HallOfFame { @Id private String id; private String name; }
예외를 처리하려면 ExceptionHandler를 사용하여 다른 ControllerAdvice를 작성하기 만하면됩니다. 이 링크의 예제를 사용하십시오.
이 솔루션의 장점 :
-
==============================
3.컨트롤러에서 사용자 지정 응답을 관리하는 가장 간단한 방법은 Map 변수를 사용하는 것입니다.
컨트롤러에서 사용자 지정 응답을 관리하는 가장 간단한 방법은 Map 변수를 사용하는 것입니다.
그래서 코드는 다음과 같이 보입니다.
public @ResponseBody Map controllerName(...) { Map mapA = new HashMap(); mapA.put("status", "5"); mapA.put("content", "something went south"); return mapA; }
아름다움은 당신이 그것을 천 가지 방법으로 구성 할 수 있다는 것입니다. 현재 개체 전송, 사용자 지정 예외 처리 및 데이터보고에 너무 쉽게 사용됩니다.
희망이 도움이
-
==============================
4.나는 또한 AOP와 함께 @Around를 사용하고있다. 사용자 정의 주석을 개발하고이를 포인트 컷에 사용합니다. 나는 글로벌 응답을 사용하고있다. 그것은 유형의 목록 유형 인 메시지 및 데이터 상태를 갖습니다
나는 또한 AOP와 함께 @Around를 사용하고있다. 사용자 정의 주석을 개발하고이를 포인트 컷에 사용합니다. 나는 글로벌 응답을 사용하고있다. 그것은 유형의 목록 유형 인 메시지 및 데이터 상태를 갖습니다
List <? extends parent> dataList
(귀하의 클래스 캐스트 예외를 해결할 수 있습니다). 모든 엔티티는이 Parent 클래스를 확장합니다. 이 방법으로 모든 데이터를 내 목록으로 설정할 수 있습니다. 또한 사용자 지정 주석을 사용하여 메시지 키를 param으로 사용하고 실제로 설정합니다. 희망이 도움이됩니다.
from https://stackoverflow.com/questions/24072458/how-can-i-wrap-a-json-response-in-spring by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 하나의 특수 경로에만 필터를 추가하는 방법 WebSecurityConfigurerAdapter (0) | 2019.04.01 |
---|---|
[SPRING] 스프링 배치 항목 판독기가 한 번만 실행됩니다. (0) | 2019.04.01 |
[SPRING] Spring applicationContext.xml에서 데이터 소스로 P6Spy 사용 (0) | 2019.04.01 |
[SPRING] Spring을 사용하는 CXF에서 다중 resouceBean 구성 (0) | 2019.04.01 |
[SPRING] 그것은 나를 500 던졌습니다 봄 보안에 표현 'ROLE_USER'을 평가하지 못했습니다 (0) | 2019.04.01 |