자바 인코딩이 이상할 때

Jaychy·2020년 11월 26일
0

프로젝트 PICK

목록 보기
2/8
post-thumbnail

본 글은 글쓴이의 개인적인 생각이 담겨있을 수 있습니다.

😡 사건의 발단

PICK 프로젝트를 진행하던 도중 선생님(유저)의 비밀번호를
우리가 직접 데이터베이스에 넣는 형식은 매우 귀찮고 번거럽고
실수도 많이 나온다는 것을 알았다.

이를 깨달은 나는 일종의 노가다(DML 생성)를 하고 싶지 않았기에
선생님 정보를 자동으로 데이터베이스에 저장 및 수정해주는 프로그램을 만들기로 결심했다.

😆 프로그램 제작

선생님 계정 등록기 레포지터리
https://github.com/Lee-Jin-Hyeok/UserAccountRegistrationMachine

일명 '선생님 계정 등록기'를 제작하게 되었는데,
유저 계정 등록기는 선생님의 아이디, 비밀번호, 이름, 위치가 담긴 Excel(xlsx 파일)을 읽어서
이미 존재하는 선생님이라면 정보 업데이트를 하고,
존재하지 않는다면 새로 선생님 정보를 생성한다.

xlsx 확장자 파일을 읽어들이기 위한 용도로 Apache POI 라이브러리를 사용하였는데,
이 라이브러리는 XSSF와 HSSF 라이브러리를 이용하여 xlsx 파일과 xls 파일을 읽을 수 있다.

처음 사용해보는 라이브러리였기에 여러 시행착오를 겪고 난 뒤 프로그램을 완성할 수 있었다.


🦄 XSSF vs HSSF

XSSF와 HSSF가 무엇이 다른지에 대해서 궁금할까봐 준비했다.
사실 내가 궁금해서 찾아봤었다..

HSSF는 2007년 이전에 사용되던 xls 파일을 제어하기 위해서 사용되는 라이브러리이고,
XSSF는 2007년 이후에 사용되는 xlsx 파일을 제어하기 위해서 사용되는 라이브러리이다.
또한 XSSF 라이브러리를 사용하면 HSSF 라이브러리도 같이 사용할 수 있으므로,
XSSF로 시작하는 클래스들을 사용하는 것이 좋다.


😐 인코딩이 이상해요

위에서 말했듯이 선생님 계정 등록기를 만들던 중 자바 인코딩이 이상한 문제를 겪게 된다.
POI 라이브러리를 통해 엑셀에서 값을 가져오고 가져온 선생님의 정보가
데이터베이스에 존재하지 않으면 삽입 연산을 진행하고,
만약 데이터베이스에 존재한다면 갱신 연산을 진행한다.

그런데 프로그램을 실행해보니 여러 오류와 함께 데이터베이스에
선생님들의 이름이 이상하게 저장되어 있는 것이었다.
왜 이런지를 알기 위해서 엑셀에서 값을 가져온 뒤 그 값을 출력해보았다.
예상과 마찬가지로 인코딩이 이상하게 되어서 한글만 깨진다는 것을 알 수 있었다.

😏 구글링 하기

당연히 구글링하면 해결되겠지라는 생각에 구글링을 통해 문제를 찾으려고 했다

1. 첫 번째 방법

처음으로 얻은 해결 방법은 다음과 같았다.

public String(byte[], String);

위와 같은 String 클래스의 생성자를 이용하여 인코딩을 새로이 하는 것이었다.
이를 위해서는 가져온 값을 getBytes() 메소드를 이용하여 디코딩을 하고
이를 String 생성자에 넣어서 새로운 Charset으로 인코딩을 하는 것이었다.
이것 때문에 UTF-8, EUC-KR, UTF-16, UNICODE, MS..머시기 등등
여러 가지 Charset을 사용해봤지만 제대로 해결되는 것은 없었다.

2. 두 번째 방법

두 번째 방법은 JVM Argument를 이용하여 -Dfile.encoding 옵션을 주는 것이었다.
위 옵션은 자바에서 파일 입출력을 할 때 어떤 인코딩 방식을 사용할 것인지를 결정하는 옵션이다.
따라서 -Dfile.encoding=UTF-8 이라고 옵션을 주면 UTF-8 형식으로 인코딩하여
파일 입출력을 실시한다.

엑셀에서 값을 가져오는 것도 파일 입출력이므로 해결 될 것이라고 생각했지만
이도 문제 해결에 도움을 주지는 못했다.

System.setProperty() 메소드를 이용하여 JVM Argument를 설정할 수도 있고
System.getProperty() 메소드를 이용하여 값을 가져올 수도 있다.
물론 이도 문제 해결에 도움을 주지는 않았다.

2. 세 번째 방법

세 번째 방법은 인터넷에 떠도는 다음과 같은 코드를 사용하는 방법이었다.

System.out.println("UTF-8 -> EUC-KR        : " + new String(msgName.getBytes("UTF-8"), "EUC-KR"));
System.out.println("UTF-8 -> KSC5601       : " + new String(msgName.getBytes("UTF-8"), "KSC5601"));
System.out.println("UTF-8 -> X-WINDOWS-949 : " + new String(msgName.getBytes("UTF-8"), "X-WINDOWS-949"));
System.out.println("UTF-8 -> ISO-8859-1    : " + new String(msgName.getBytes("UTF-8"), "ISO-8859-1"));
System.out.println("UTF-8 -> MS949         : " + new String(msgName.getBytes("UTF-8"), "MS949"));
 
System.out.println("ISO-8859-1 -> EUC-KR        : " + new String(msgName.getBytes("ISO-8859-1"), "EUC-KR"));
System.out.println("ISO-8859-1 -> KSC5601       : " + new String(msgName.getBytes("ISO-8859-1"), "KSC5601"));
System.out.println("ISO-8859-1 -> X-WINDOWS-949 : " + new String(msgName.getBytes("ISO-8859-1"), "X-WINDOWS-949"));
System.out.println("ISO-8859-1 -> UTF-8         : " + new String(msgName.getBytes("ISO-8859-1"), "UTF-8"));
System.out.println("ISO-8859-1 -> MS949         : " + new String(msgName.getBytes("ISO-8859-1"), "MS949"));
 
System.out.println("EUC-KR -> UTF-8         : " + new String(msgName.getBytes("EUC-KR"), "UTF-8"));
System.out.println("EUC-KR -> KSC5601       : " + new String(msgName.getBytes("EUC-KR"), "KSC5601"));
System.out.println("EUC-KR -> X-WINDOWS-949 : " + new String(msgName.getBytes("EUC-KR"), "X-WINDOWS-949"));
System.out.println("EUC-KR -> ISO-8859-1    : " + new String(msgName.getBytes("EUC-KR"), "ISO-8859-1"));
System.out.println("EUC-KR -> MS949         : " + new String(msgName.getBytes("EUC-KR"), "MS949"));
 
System.out.println("KSC5601 -> EUC-KR        : " + new String(msgName.getBytes("KSC5601"), "EUC-KR"));
System.out.println("KSC5601 -> UTF-8         : " + new String(msgName.getBytes("KSC5601"), "UTF-8"));
System.out.println("KSC5601 -> X-WINDOWS-949 : " + new String(msgName.getBytes("KSC5601"), "X-WINDOWS-949"));
System.out.println("KSC5601 -> ISO-8859-1    : " + new String(msgName.getBytes("KSC5601"), "ISO-8859-1"));
System.out.println("KSC5601 -> MS949         : " + new String(msgName.getBytes("KSC5601"), "MS949"));
 
System.out.println("X-WINDOWS-949 -> EUC-KR     : " + new String(msgName.getBytes("X-WINDOWS-949"), "EUC-KR"));
System.out.println("X-WINDOWS-949 -> UTF-8      : " + new String(msgName.getBytes("X-WINDOWS-949"), "UTF-8"));
System.out.println("X-WINDOWS-949 -> KSC5601    : " + new String(msgName.getBytes("X-WINDOWS-949"), "KSC5601"));
System.out.println("X-WINDOWS-949 -> ISO-8859-1 : " + new String(msgName.getBytes("X-WINDOWS-949"), "ISO-8859-1"));
System.out.println("X-WINDOWS-949 -> MS949      : " + new String(msgName.getBytes("X-WINDOWS-949"), "MS949"));
                
System.out.println("MS949 -> EUC-KR        : " + new String(msgName.getBytes("MS949"), "EUC-KR"));
System.out.println("MS949 -> UTF-8         : " + new String(msgName.getBytes("MS949"), "UTF-8"));
System.out.println("MS949 -> KSC5601       : " + new String(msgName.getBytes("MS949"), "KSC5601"));
System.out.println("MS949 -> ISO-8859-1    : " + new String(msgName.getBytes("MS949"), "ISO-8859-1"));
System.out.println("MS949 -> X-WINDOWS-949 : " + new String(msgName.getBytes("MS949"), "X-WINDOWS-949"));

오우... 역시 브루트 포스는 위대하다...
그리고 이 노가다를 하기 싫어서 다음과 같이 for문으로 바꾸어 놓은 글도 있었다.

String string = "이진혁";
String[] charsets = {"UTF-8", "EUC-KR", "KSC5601", "ISO-8859-1", "X-WINDOWS-949"};

for(int i = 0 ; i < charsets.length ; i++) {
    for(int j = 0 ; j < charsets.length ; j++) {
        System.out.println("[" + charsets[i] + "][" + charsets[j] + "] = " + new String(string.getBytes(charsets[i]), charsets[j])
    }
}

하지만 이 코드들은 내 문제를 해결해 줄 수 없었다.
그리고 결국엔 길고 긴 구글링을 통해 문제를 해결할 수 있었다.

😂 문제 해결

사실 문제는 자바 인코딩의 문제도 있었지만 부가적인 오류로 인해서 착각한 것도 있었다.
문제는 IntelliJ IDEA를 제대로 사용하지 않는 죄였다.

IntelliJ에서는 [File]-[Settings]-[Editor]-[File Encodings] 탭에
Global Encoding과 Project Encoding을 설정하는 부분이 있었다.
이 부분이 UTF-8 설정이 되어 있지 않았기 때문에 인코딩 문제가 생겼던 것이었다.
이 이후부터는 선생님의 이름 즉, 한글이 깨지지 않았다.

코드적인 문제가 아닌 사용중인 IDE에 대한 이해가 부족하지 않았나싶다.

profile
아름다운 코드를 꿈꾸는 백엔드 주니어 개발자입니다.

0개의 댓글