Tech Note

Spring 4.x 에서 HttpServletRequest 의 params 를 변경하고 싶을 때

Samgim 2017. 8. 3. 00:11


Spring을 참 싫어하는 나로서는, Spring 으로 개발한다는 것이 좀 싫고 그렇다.


어떻게 보면 가장 익숙하게 쓸 수 있는데도, 한창 배울 시기에... 그 때의 트라우마가 남아서 꺼림칙할 때가 있다.


뭐, 개인적인 감상이고.


지금은 밥벌어 먹고 살려고 하는 중.





간단한 Tip 이지만, 위와 같은 Spring Controller가 있다고 하자.


아마 평범하게(?) 이렇게 쓸 것 같다. paging 이 없거나 하면 더 간단하겠지.


그런데 이 코드에 보면 저 request 에서 JPA 의 specification 을 사용하기 위해 getSpecificationFromRequest() 안에 request를 집어 넣는 것을 볼 수 있다.



getSpecificationFromRequest() 는 다음과 같이 생겼다.



받아온 request 안의 값을 사용해서 specification 을 만든다.


이렇게 만든 specification 을 사용해서 DB 에서 Comments 를 꺼내온다.




그런데 이제 여기서 갑자기 변경을 막 가하고 싶어진다.


저렇게 like 검색을 했다간 DB가 많이 힘들어 할 것 같아서 다른 Service 에서 contents를 따로 검색해 와서 검색한 ID를 가져오고 싶다.


그래서 이렇게 변경했다고 해보자. (예시가 적절한지 모르겠다...)



Controller 는 이렇게 바뀌었다.



이제 ids 를 request에 parameter로 넣어줘야 하는데 어떻게 넣어줄 수 있을까? 




기본적으로 Spring 에서 HttpServletRequest 는 Immutable 이다.


생각해보면 외부에서 들어온 값을 Immutable 로 받는 것은 당연한데, 어른의 사정이란 건 항상 존재하기 마련이다.


구조적으로 잘못되었거나 

(이 경우는 DB에서 SELECT하는 걸 포기하고 통째로 외부에서 검색하는 편이 낫다. 지금은 이렇게 계속 하겠지만, 페이징 등에서 어려움을 또 겪는다.) 


이미 레거시가 되어버려서 슬픈 경우...아니면 잘못된 것이 아니라 정말로 특이한 경우일 수도 있다.


이 때는 Immutable 인 request를 억지로 변경하는 것보다 Wrapping을 하는 것이 안전하다.


Spring 에는 HttpServletRequestWrapper 라는 클래스가 있는데, 이것을 확장하면 request를 wrapping 해서 사용할 수 있다.



(참고로 나도 구글링해서 만든 코드라... 출처가 어딘지 기억이 나지 않음;;)


이렇게 HttpServletRequestWrapper 를 확장해서 사용하면 request 값을 변경하지 않고 wrapping 된 request를 다음과 같이 사용할 수 있다.



(일단 보여주기 위해서 변수 정리를 좀 덜했다. search 해서 가져오고 wrapping 된 request 리턴해주는 함수를 하나 더 만들면 깔끔하겠지?)


이렇게 Request 내부의 값을 변경하기 위해 삽질하는 대신, 좀 더 안전하게 수정된 request를 사용할 수 있게 되었다.


wrapping 이라는 아이디어 자체가 꼭 request 처리 뿐만 아니라 다른 곳에서도 유용하게 쓰일 수 있을 것 같아서 굳이 포스팅을 해보았다. (은근 귀찮고 힘드네..ㅠㅜ)






그래도 가장 좋은 건 request 를 wrapping 할 필요 없이 만드는 것 같다.


일단 wrapping할 상황이라는 것 자체가 모델링이 망한 경우일 수도 있고... 여러 모로 반가운 상황은 아닌 듯.