티스토리 뷰
Spring MVC 에서는 REST API 을 지원하기 위해 Jackson 라이브러리를 이용하여 response 을 Json 형태로 변경하여 제공하는 기능을 포함하고 있습니다. 또한 @RequestBody 을 이용해 @RequestMapping 으로 선언된 method 의 매개변수로 Json 으로 된 body 을 POJO 로 받을 수도 있습니다. 이러한 처리를 위해 Spring 은 Json 혹은 XML 등의 여러 형태의 값을 자동으로 처리하기 위해 MessageConverter 을 등록해두는데, HttpMessageConverter 인터페이스를 구현한 것을 개발자가 상속받아 변경하여 사용할 수 있습니다. Jackson 은 MappingJackson2HttpMessageConverter 을 제공하는데, 이 class 을 상속받아 수정하게 되면 개발자가 원하는 동작을 할 수 있도록 수정할 수 있습니다.
기본적으로는 아래와 같이 @Configuration 으로 class 을 등록하여 사용할 수 있습니다.
@Configuration public class MessageConverterConfig extends MappingJackson2HttpMessageConverter { private final HttpServletRequest request; @Autowired public MessageConvertorConfig(HttpServletRequest request) { this.request = request; } }
이 때, 위의 예제와 같이 request 을 주입받아 필요할 경우 사용할 수 있음을 알 수 있습니다.
제가 가장 많이 사용하는 경우 HTTP 요청 시 body 영역에 form 이 아닌 Json 형태로 전송할 데이터를 보내는 것을 처리하는 것입니다. 이를 위해 read() 을 상속 받아서 수정을 해줘야 합니다. MappingJackson2HttpMessageConverter 소스를 구해서 read() 가 어떻게 구현되어 있는지 확인해서 수정할 수 있겠지만, 간단하게 어떤 식으로 수정할 것인지 확인해보겠습니다.
@Override public Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage) { JavaType javaType = this.getJavaType(type, contextClass); return this.objectMapper.readValue(inputMessage.getBody(), javaType); }
가장 기본적인 형태는 위와 같습니다. JavaType 을 이용해서 Jackson 이 사용자가 요구하는 형태의 POJO 에 body 내용을 변환하도록 구현할 수 있습니다.
여기서, 요청을 보내는 쪽이 웹 브라우져가 아니라 모바일 기기 등일 경우 본문 내용을 암호화해서 보내는 경우를 감안해서 확장해보겠습니다. 모바일 기기가 어떠한 암호화를 한 뒤 본문 내용을 보내고, 암호화 여부를 HTTP header 에 ISCRYPT 라는 key 로 1 이냐 아니냐로 구분해서 보낸다고 한다면 다음과 같이 처리할 수 있습니다.
@Override public Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage) { JavaType javaType = this.getJavaType(type, contextClass); // Request Header 에 ISCRYPT 가 1 일 경우 암호화 전송 String isCrypt = request.getHeader("ISCRYPT"); if (!Strings.isNullOrEmpty(isCrypt) && isCrypt.equals("1")) { // 암호화된 메세지일 경우 별도 처리 String message = CharStreams.toString(new InputStreamReader(inputMessage.getBody())); byte[] result = cipher.doFinal(Base64Utils.decodeFromString(message)); // 여기에 복호화될 부분이 구현되면 됩니다. return this.objectMapper.readValue(result, javaType); } return this.objectMapper.readValue(inputMessage.getBody(), javaType); }
암호화가 되지 않았다면 body 을 그대로 변환하고, 암호화가 된 것이라면 별도의 복호화 처리(여기서는 이해를 돕기 위해 Java 암복화화를 위한 Cipher 로 처리하는 형태를 남겨놨습니다)를 내부에서 구현하면 됩니다. 그리고 그렇게 복호화된 구분을 받아 Jackson 에서 JavaType 에 맞게 다시 변환하는 방식입니다.
response 구현도 마찬가지이지만, 한가지 주의할 점이 있습니다. request 에서는 Json 이 POJO 로 저장되는 동일한 형태로 구현하였지만, response 로 사용자에게 결과를 전송할 때에는 암호화가 되지 않으면 Json 으로 전송되어야 하나, 암호화가 된 경우라면 String 으로 전송이 된다는 것입니다. 그렇기 때문에 역시 HTTP header 에 암호화 여부를 추가해주고 두 경우에 따라 다른 처리가 필요하다는 것입니다.
아래 예제 코드를 통해 차이점을 확인하고 구현하면 됩니다.
@Override protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage) { // Request Header 에 ISCRYPT 가 1 일 경우 암호화 전송 String isCrypt = request.getHeader("ISCRYPT"); if (!Strings.isNullOrEmpty(isCrypt) && isCrypt.equals("1")) { // JSON text 생성 String message = objectMapper.writeValueAsString(object); byte[] result = Base64Utils.encode(cipher.doFinal(message.getBytes())); HttpHeaders header = outputMessage.getHeaders(); header.add("ISCRYPT", "1"); OutputStream output = outputMessage.getBody(); output.write(result); output.flush(); return; } outputMessage.getHeaders().add("ISCRYPT", "0"); super.writeInternal(object, type, outputMessage); }
이 외에도 본인이 추가해야할 것이 있다면 그 코드를 위와 같이 추가함으로써 모든 요청과 응답을 제어할 수 있습니다.
'Programming > Spring Boot 시작하기' 카테고리의 다른 글
외부 resource 을 서비스하기 (3) | 2019.01.24 |
---|---|
RestTemplate 설정 변경하기 (0) | 2019.01.23 |
Spring Boot Java Config 으로 Jackson 설정하기 (0) | 2019.01.22 |
TaskExecutor 로 @Async 의 Thread 을 Pool 로 관리하기 (0) | 2019.01.22 |
MyBatis 와 JOOQ 을 연동해보기 (0) | 2018.09.05 |
- Total
- Today
- Yesterday
- 내장 WAS
- paging
- OracleJDK
- couchbase
- Phabricator
- 워드프레스
- 페이징
- git
- manjaro
- 클라우드플레어
- Nas
- 프로젝트 규모
- RestTemplate
- docker
- Redmine
- Spring Boot
- boot
- SI
- messages.properties
- java config
- Spring
- 엘지
- KDE
- 도입기
- Spring MVC
- proxmox
- 시니어 프로그래머
- NoSQL
- jooq
- 외장 WAS
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |