SpringBoot 한글 출력.. 도저히 안될때

Sorbet·2021년 7월 20일
3

상황

  • SpringBoot + intelij + H2 + Junit5 + MockMvc 환경에서 Controller 통합 테스트를 진행하던 때 한글이 깨지는 현상을 해결한 경험입니다.

  • ##Test.java파일

    mockMvc.perform(get("/member/all")
                    .andDo(print())
                    .andExpect(status().isOk());
                    
    @Test
      public void 상품검색() throws Exception {
          String keyword = "스포츠";  // 한글 사용
    
          MvcResult result = this.mockMvc
                  .perform(get("/api/search/" + keyword))
                  .andExpect(status().isOk())
                  .andExpect(어쩌구 Matcher...)
                  .andReturn();                
  • 위와 비슷한 방식으로 모든 데이터를 조회하는 요청을 날리는데, print할때 계속 한글이 깨지는 문제가 있었어요

도전1

  • 처음에는 이게 인텔리제이탓인가 해서 "인텔리제이 한글깨짐" 키워드로 검색하면 나오는 몇가지 해결법을 적용해봤습니다.
    • Intellij VM 설정 : Edit Custom VM Options > -Dfile.encoding=UTF-8
    • Intellij Editor File Encoding 설정 : Editor >> File Encodings >> Global, Project Encoding, Properties Files
    • 톰캣 인코딩 설정 : Run >> Edit Configurations >> VM options에 옵션을 추가"-Dfile.encoding=UTF-8"
  • 위 3가지 방법을 적용해도 제 상황에서는 동일하게 한글이 출력되지 않는 문제가 있었어요 ㅠ_ㅠ;;
  • 참고로 JVM의 인코딩 확인 방법은 아래 코드를 참고해주세요
System.out.println(Charset.defaultCharset().displayName());

도전2

  • 몇일 대충 그냥저냥 워킹 어라운드라고 쓰고 외면이라고 읽는,한글이 깨져도 제가 테스트하고자 하는 핵심기능에는 지장이 없어서 그냥저냥 핵심기능 개발에만 집중했습니다.
  • 그러던 어느날 몇주간의 api작업을 완료하고 test커버리지도 꽤 높이 올라와있지만 한글깨짐 문제는 여전히 남아있었고, 이 문제를 해결하고 싶어서 조금 생각을 해보니
    • 테스트할때는 빠른 테스트를 위해서 in-memory-db로 H2를 사용하니까, 여기에다가 UTF8 인코딩을 적용해보면 되지 않을까? 하는 생각에 RDB에 적용할수 있는 UTF8 옵션을 다 때려박아줬습니다.
  • application.properties 파일
spring.datasource.hikari.jdbc-url=jdbc:h2:mem:testdb?useUnicode=true&characterEncoding=utf8&charSet=UTF-8
  • 하늘도 감복해서 한글이 정상적으로 출력되...기는 개뿔 여전히 깨지는 증상은 계속되었습니다.

도전3

  • 진심으로 이 한글이 깨지는 증상을 해결하고 싶었습니다. 그 누구도 고치라고 강요하지는 않았지만, 제가 만든 테스트 데이터셋을 JSON 형식으로 깨지지 않은 온전한 한글과 함께 받아보고 싶었거든요. 절대 절대로 노가다하기 싫어서 이러는거 아닙니다!
  • 찾다보니 최근에 Spring-Heateoas 업데이트가 있어서 Controller단에서의 MediaType 에 UTF-8이 기본포함된 문자열은 없다는군요? 강제로 UTF-8 형식을 적용해줍니다
  • 요런느낌 코드는 아래
@RequestMapping(value = "/myapi/sidedish", produces = MediaTypes.HAL_JSON_VALUE+";charset=UTF-8")
public class DishController {
  • 위 사항을 적용하고 나서야
  • 비로소 세종대왕님께서 만드신 아름다운 한글이 깨지지 않고 잘 전달되네요
  • 결론 : 제 상황에서는 스프링 부트에서 JSON API 컨트롤러가 UTF-8 인코딩으로 리턴하도록 명시해야 정상적으로 동작했습니다

추가 : special thanks to Dae-Hwa

  • 조금더 우아한 방법 : 프로퍼티 파일에 설정 추가하기

  • 프로퍼티의 경우

    #MockMvc Encodings
    server.servlet.encoding.force-response=true
  • 야믈의 경우

    # test/resources/application.yml
    server:
      servlet:
        encoding:
          force-response: true
  • 위처럼 추가해주면, UTF-8 인코딩 포맷으로 출력됨을 알 수 있다

부작용의 가능성 : 테스트코드에서 http헤더의 컨텐츠 타입을 검사하는 경우 테스트 실패의 가능성이 있음

Response header 'Content-Type' expected:<application/hal+json> but was:<application/hal+json;charset=UTF-8>
Expected :application/hal+json
Actual   :application/hal+json;charset=UTF-8
<Click to see difference>
  • 스프링 헤이티오스가 버전이 올라가면서 완전히 동일한 타입의 기본으로 제공되는 문자열이 없다
  • 왜나하면 test의 application.yml 에서 저렇게 response만 따로 true로 설정해줘야 하는 이유는 Response 에 대해서는 기본값이 false 이기 때문
package org.springframework.hateoas;

public class MediaTypes {
	public static final String HAL_JSON_VALUE = "application/hal+json";
(중략...)

profile
Sorbet is good...!

0개의 댓글