코딩마을방범대
HttpRequest에서 body값 가져오기 본문
728x90
Form Data를 어느 method에 넣느냐에 따라 쿼리파라미터의 위치가 다르다
- get: url
- post: body
컨트롤러에서 HttpRequestServlet을 이용하여 body를 출력하려 하면 null값이 출력됨
요청 -> 필터 -> 디스패처 서블릿 -> 인터셉터 -> 컨트롤러로 값을 바인딩 하는 과정에서
Interceptor에서 getInputStream() 을 호출하여 Http Body를 읽으면서 소비하였기 때문에
Controller의 Http Body가 비어있는 것
public void test(HttpServletRequest request) throws IOException {
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
위의 코드와 같이 데이터를 추출할 경우 아래와 같이 길이만 출력됨
Http Body =
Http Body Length = 38
해결 방법
1. HttpServletRequestWrapper 를 상속받는 클래스 생성
- 한번 읽고 사라지는 HttpBody가 아닌 여러번 계속해서 읽을 수 있도록 구현
- getInputStream()에서 요청 Http Body를 복사하여 값을 저장하고 반환하는 기능을 재정의
public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
private ByteArrayOutputStream cachedBytes;
public MultiReadHttpServletRequest(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (cachedBytes == null)
cacheInputStream();
return new CachedServletInputStream(cachedBytes.toByteArray());
}
@Override
public BufferedReader getReader() throws IOException{
return new BufferedReader(new InputStreamReader(getInputStream()));
}
private void cacheInputStream() throws IOException {
/* Cache the inputstream in order to read it multiple times. For
* convenience, I use apache.commons IOUtils
*/
cachedBytes = new ByteArrayOutputStream();
IOUtils.copy(super.getInputStream(), cachedBytes);
}
/* An input stream which reads the cached request body */
private static class CachedServletInputStream extends ServletInputStream {
private final ByteArrayInputStream buffer;
public CachedServletInputStream(byte[] contents) {
this.buffer = new ByteArrayInputStream(contents);
}
@Override
public int read() {
return buffer.read();
}
@Override
public boolean isFinished() {
return buffer.available() == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener listener) {
throw new RuntimeException("Not implemented");
}
}
}
2. Filter 를 구현하는 클래스 생성
- 인터셉터에서 Http Body가 소모 되기 전에 필터 단계에서 Http Body를 옮겨 담는 기능을 수행
@Component
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request);
chain.doFilter(multiReadRequest, response);
}
}
3. 사용
ServletInputStream inputStream = request.getInputStream();
String messageBody = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
💡 TIPS
자바에서 개행 문자 지우는 법 (replace)
1. System.getProperty("line.separator") 를 이용하기
- 모든 개행이 지워지진 않음
// java 6 버전 이하
str.replaceAll(System.getProperty("line.separator"))
// java 7 버전 이상
str.replaceAll(System.lineSeparator())
2. "(\r\n|\r|\n|\n\r)" 이용
str.replaceAll("(\r\n|\r|\n|\n\r)", "")
JAVA HTTP Request, Response 메소드 내에서 생성하는 방법
첫번째
ServletWebRequest servletContainer = (ServletWebRequest)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletContainer.getRequest();
HttpServletResponse response = servletContainer.getResponse();
두번째
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getResponse();
참고사이트
728x90
'💡 백엔드 > Java' 카테고리의 다른 글
Log - (3) Log4jdbc+Logback을 이용한 SQL 로그 남기기 (0) | 2023.05.29 |
---|---|
Spring Profile 설정하기 (0) | 2023.05.29 |
JAVA의 @ExceptionHandler (0) | 2023.05.28 |
Java의 Interceptor (0) | 2023.05.28 |
Log - (2) Logback (0) | 2023.05.28 |