스프링 부트 시 컨트롤러에 도달하기 전에 요청 본문을 변경하는 방법
스프링 부트 어플리케이션이 있습니다.나는 모든 포스트 요청의 요청 본문을 변경합니다.요구가 컨트롤러에 도달하기 전에 요청 본문을 변경할 수 있습니까?예를 들어주세요.
다른 방법으로는 HttpServletRequest 객체에 Atribut을 추가하는 방법이 있습니다.그런 다음 컨트롤러 클래스에서 @RequestAttribute 주석을 사용하여 해당 속성을 읽을 수 있습니다.
인터셉터 내
@Component
public class SimpleInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException, IOException {
String parameter = request.getParameter("parameter");
if (parameter == "somevalue") {
request.setAttribute("customAttribute", "value");
}
return true;
}
}
컨트롤러 내
@RestController
@RequestMapping("")
public class SampleController {
@RequestMapping(value = "/sample",method = RequestMethod.POST)
public String work(@RequestBody SampleRequest sampleRequest, @RequestAttribute("customAttribute") String customAttribute) {
System.out.println(customAttribute);
return "This works";
}
}
이는 요청 본문을 변경하지 않는다는 장점이 있습니다.
★★
는 않아요.
정보
컨트롤러의 핸들러 메서드에 도달하기 전에 요청 본문을 변경하는 세 가지 옵션을 알고 있습니다.
- 메서드를 호출하기 전에 요청을 변경하려면 AOP를 사용합니다.
- HTTP 필터를 만듭니다.
- 커스텀 스프링 핸들러 작성가로채기.
이미 스프링 부트를 사용하고 있기 때문에 옵션 3, 커스텀 스프링 핸들러요격기, 자네에게 가장 좋은 선택인 것 같군
스프링 핸들러를 다룬 백등기사에 대한 링크입니다.가로채기.
Baldung을 수 에 대한 . 왜냐하면 당신은 오직 읽기만 할 수 있기 때문입니다.InputStrem returned returned returned returned returned returned returned returned returnedHttpServletRequest★★★★★★★★★★★★★★★★★★.
경우 래퍼 를 만들어야 .HttpServletRequest 핸들러 .인터셉터 또는 커스텀필터(필터가 여기에 가는 방법일 수 있습니다).
래퍼 클래스
- 글을 읽어보세요.
HttpServletRequest클래스 - 필요에 따라 본문을 수정합니다.
- .
ByteArrayOutputStream. toByteArray을byte[]개울에서요.- ByteArrayOutputStream을 닫습니다(리소스로 시도하면 좋습니다).
- 「」를 .
getInputStream★★★★★★ 。 - 를를 wrap wrap
byte[]ByteArrayInputStream이 ByteArrayInputStream을 사용할 됩니다.getInputStream줄기를 을 사용하다
요구를 랩하는 방법
- 필터에서 래퍼 클래스를 인스턴스화하고 원래 요청(doFilter 메서드의 매개 변수)을 전달합니다.
- 원래 요청이 아닌 chain.doFilter 메서드에 래퍼를 전달합니다.
HTTP 필터를 사용한 답변입니다.
RequestFilter.java
@Component
public class RequestFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
RequestWrapper wrappedRequest = new RequestWrapper((HttpServletRequest) request);
chain.doFilter(wrappedRequest, response);
}
@Override
public void destroy() {
}
}
RequestWrapper.java
public class RequestWrapper extends HttpServletRequestWrapper {
private final String body;
private ObjectMapper objectMapper = new ObjectMapper();
public RequestWrapper(HttpServletRequest request) throws IOException {
// So that other request method behave just like before
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
// Store request body content in 'requestBody' variable
String requestBody = stringBuilder.toString();
JsonNode jsonNode = objectMapper.readTree(requestBody);
//TODO -- Update your request body here
//Sample
((ObjectNode) jsonNode).remove("key");
// Finally store updated request body content in 'body' variable
body = jsonNode.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
public int read() throws IOException {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
RequestBodyAdvice를 사용하여 이를 실현한 방법은 다음과 같습니다.
- RequestBodyAdvice를 구현하는 클래스를 만들고 @ControllerAdvice로 주석을 추가합니다.
@ControllerAdvice
public class CustomRequestBodyAdvice implements RequestBodyAdvice {
- 다음 4가지 방법을 구현해야 합니다.
a. support: 여기서는 대상 컨트롤러를 제어할 수 있습니다.또, 요구 본문의 타입을 지정함으로써, 어느 쪽의 요구 본문을 보다 효율적으로 관리할 수 있습니다.
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
log.info("In supports() method of {}", getClass().getSimpleName());
return methodParameter.getContainingClass() == AuthorController.class && type.getTypeName() == AuthorDTO.class.getTypeName();
}
b. Body Ready 이전
<!-- language: lang-js -->
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
log.info("In beforeBodyRead() method of {}", getClass().getSimpleName());
return httpInputMessage;
}
c. after BodyRead: 요청 본문을 수정할 수 있는 위치입니다.
<!-- language: lang-js -->
@Override
public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
log.info("In afterBodyRead() method of {}", getClass().getSimpleName());
if (body instanceof AuthorDTO) {
AuthorDTO authorDTO = (AuthorDTO) body;
authorDTO.setName("Test");
return authorDTO;
}
return body;
}
d. 핸들 Empty Body
<!-- language: lang-js -->
@Override
public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
log.info("In handleEmptyBody() method of {}", getClass().getSimpleName());
return body;
}
출처 : http://www.javabyexamples.com/quick-guide-to-requestbodyadvice-in-spring-mvc
이에 대한 한 가지 방법은 성찰에 의한 것이다.ProceedingJoinPoint에 메서드로 전달된 args 개체가 포함되어 있습니다.
@Aspect
@Component
public class AopInterceptor {
@Around(value = "@annotation(xyz.rpolnx.spring.web.poc.annotation.AopIntercepExample)")
public Object handler(final ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Object[] args = joinPoint.getArgs();
Class<?> someClass = args[0].getClass();
Field field = someClass.getDeclaredField("custom");
field.setAccessible(true);
field.set(args[0], "custom");
field.setAccessible(false);
return joinPoint.proceed();
}
}
@RestController
public class SimpleController {
@PostMapping("/aop")
@AopIntercepExample
public Person handleAopIntercept(@RequestBody Person nodes) {
return nodes;
}
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AopIntercepExample {
}
public class Person {
private String name;
private String id;
private String custom;
}
저도 이 문제가 있었어요.이 스레드가 조금 도움이 되었고 Bijaya Bhaskar Swain보다 더 간단한 솔루션을 올리고 싶었습니다.
package com.thebois.inpassering.adapters.merchant.staffrestrepo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.thebois.inpassering.adapters.merchant.FilterOrders;
import com.thebois.inpassering.adapters.merchant.facilityownerrestrepo.FacilityOwner;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
import javax.servlet.FilterChain;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.core.annotation.Order;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
@Component
@AllArgsConstructor
@Order(value = FilterOrders.STAFF_REQUEST_ORDER)
public class StaffCreationFilter extends OncePerRequestFilter {
ObjectMapper objectMapper;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
RequestWrapper modifiedRequest = new RequestWrapper(request);
filterChain.doFilter(modifiedRequest, response);
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
return !(request.getServletPath().contains("/staff") && request.getMethod().equals("POST"));
}
private class RequestWrapper extends HttpServletRequestWrapper {
String body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
String body = new ContentCachingRequestWrapper(request).getReader().lines().collect(Collectors.joining(System.lineSeparator()));
//get your dto
Staff staff = objectMapper.readValue(body, Staff.class);
//edit your dto
long facilityOwnerId = ((Number) request.getAttribute("facilityOwnerId")).longValue();
FacilityOwner facilityOwner = FacilityOwner.builder()
.facilityOwnerId(facilityOwnerId)
.build();
Staff modifiedStaff = Staff.builder()
.facilityOwner(facilityOwner)
.username(staff.getUsername())
.password(new BCryptPasswordEncoder().encode(staff.getPassword()))
.build();
//save your changes to body
this.body = objectMapper.writeValueAsString(modifiedStaff);
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
ServletInputStream servletInputStream = new ServletInputStream() {
public int read() {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
}
언급URL : https://stackoverflow.com/questions/50932518/how-to-modify-request-body-before-reaching-controller-in-spring-boot
'programing' 카테고리의 다른 글
| AJAX 요청과 일반 브라우저 요청의 차이점 (0) | 2023.03.16 |
|---|---|
| null의 'getHostNode' 속성을 읽을 수 없습니다. (0) | 2023.03.16 |
| Angular에서 똑딱거리는 시계(시간) 만드는 방법JS 및 HTML (0) | 2023.03.11 |
| jQuery 및 AJAX 응답 헤더 (0) | 2023.03.11 |
| AngularJS를 사용하여 느린 스크립트에 대한 애니메이션을 로드하시겠습니까? (0) | 2023.03.11 |