JAVA & Open Framework2014. 5. 23. 15:55

오랜만에 뻘글

이번에 오라클 데이타베이스에 다국어메시지 입력에 대한 테스트를 진행할 일이 있었다.
테스트 대상인 오라클 데이타베이스의 캐릭터셋은 KO16KSC5601 
http://blog.naver.com/kkhigh5/30023536431
위 링크의 블로그에서 너무 잘 정리해주셨는데, 이 캐릭터셋은 한글 완성형 코드와 일치하는 캐릭터셋이라 생각하면 된다.
즉 한글 완성형 코드의 범주에서 벗어난 아랍어나 중국어(간체) 등은 물론이거니와 햏 뷁 등과 같은 몇몇 한글문자의 입력도 불가능 하다는 이야기.
실제로 sqlplus나 Toad, Orange 등의 툴을 통해서 위와 같은 데이터를 밀어넣어 보았더니 "?" 로 입력이 되더라.

자 여기까지는 오라클 데이타베이스의 캐릭터셋에 따른 다국어메시지 입력에 대한 문제점에 대해서 이야기했고, 이제 해결방법을 알아보도록 하자



해결방법 1
너무 단순한 이야긴데, 캐릭터셋을 변경하면 된다.
UTF8이나 AL32UTF8 정도면 충분하다. ㅎㅎ
물론 말은 단순하지, 이미 데이타가 충분히 쌓여있다면 결코 쉬운일은 아니다.
거기에다가 다국어메시지를 그렇게 많이 쓰지 않는다면, 일부러 1.5배 이상의 공간을 더 소비하면서 이렇게 변경할 이유도 없고... (문자당 UTF8은 3바이트, AL32UTF8은 6바이트를 쓴다)
결국 이건 마땅한 해결책은 아니다.
장점 : 단순하다. 코드단에서 수정이 적어질 수 있다.
단점 : 데이타가 많다면? 변경도중 데이타가 깨질수도 있을듯
DB 용량이 커진다. (최소 1.5배)


해결방법 2
그냥 무시할 수 있는 방법인데, euc-kr환경의 웹페이지를 쓰면 된다.
어짜피 문제가 되는 다국어메시지의 경우 대부분은 사용자가 웹페이지에서 입력한 값이 될텐데...
euc-kr환경의 웹페이지에서는 post나 get으로 문자데이터를 전달할 때 한글 범주에서 벗어난 문자데이터들은 알아서 HTML escape 된 문자로 변경하여 전달한다.
만약 utf-8 웹페이지를 쓴다면 어떻게 하냐고? 뭐 WAS단에서 escape 하는 방법밖에는...
그런데 한가지 문제점이 있는데, 바로 파이어폭스를 사용할때이다.
뷁이나 햏같은 완성형 한글에 포함되지 않는 문자의 경우 파이어폭스는 HTML escape 문자로 날리는게 아니라 ㅂㅞㄺ 와 같이 분해해서-_- 날려버린다.
이렇게 분해된 문자는 파이어폭스에서는 잘 보이지만, 익스플로러에서는 분해된 상태로 보인다는 큰 문제점이 있다. 
이런 문제를 해결하기 위하여 직접 스크립트 등으로 HTML escape 문자로 변경해서 날리는 방법이 있다.
 
하지만 이 방법은 추천하지 않는다.
일단 저장공간이 훨씬 낭비된다는 점, 그리고 데이터가 escape된 문자로 들어가서 추출하기가 어렵다는점이 있겠다.
장점 : DB설정을 변경한다거나, 코드에 큰 변화없이 웹서비스를 운영할 수 있다.
단점 : DB에서 원하는 데이터를 추출하기 위한 방법에 대한 연구가 필요


해결방법 3
사실 이번 뻘글은 이 방법에 대해 설명하려고 쓴 글
오라클은 현재 캐릭터셋 범주에서 벗어난 문자를 입력받기 위한 방법으로 네셔널 캐릭터셋을 지정하여 사용할 수 있다.
NCHAR, NVARCHAR, NCLOB 등이 네셔널 캐릭터셋으로 데이터가 입력되는 컬럼의 타입이다.
따라서 위 타입의 컬럼에는 다국어 데이터를 입력해도 깨지지 않는다는 것
단 데이터 입력방식이 조금 다른데, unicode escape 형식으로 입력을 해야 한다.
(참고 : http://cmj8333.tistory.com/entry/nvarchar2-nchar-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9E%85%EB%A0%A5)

예)
INSERT INTO... ('일반데이터',unistr('\5361\6F2B'));


위와 같이 사용하면 된다.
데이터를 조회할때는 특별히 바뀌는 건 없다. 다만 euc-kr등 다국어메시지를 지원하지 않는 웹페이지에 바로 표시하게 된다면 글자가 깨져버리니 주의!

오라클 JDBC의 경우 OraclePreparedStatement의 setFomOfUse 를 사용하여 좀 더 편하게 데이터를 입력할 수 있다.
예를들면 요래요래~

예)
pstmt.setString(1, “뷁”);
((OraclePreparedStatement)pstmt).setFormOfUse(1, OraclePreparedStatement.FORM_NCHAR);


DB Pool 을 이용할땐 위와같은 방법은 이용이 불가능하니, 알아서 코드단에서 문자를 escape 시킨후에 입력하도록 하자.
이 부분에 있어서 아직 마땅한 라이브러리는 찾지 못했는데, 여기저기 뒤져보다 아래와 같은 코드를 찾기는 했다. (참고 : http://www.java2s.com/Tutorial/Java/0400__Servlet/ServletUnicodeEscapeString.htm)

    private static char toHex(int nibble) {
        return hexDigit[(nibble & 0xF)];
    }

    private static char[] hexDigit = { '0', '1', '2', '3', '4', '5', '6', '7',
            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

    private static String escape(String str) {
        // Modeled after the code in java.util.Properties.save()
        StringBuffer buf = new StringBuffer();
        int len = str.length();
        char ch;
        for (int i = 0; i < len; i++) {
            ch = str.charAt(i);
            switch (ch) {
            case '\\':
                buf.append("\\\\");
                break;
            case '\t':
                buf.append("\\t");
                break;
            case '\n':
                buf.append("\\n");
                break;
            case '\r':
                buf.append("\\r");
                break;
            default:
                if (ch >= ' ' && ch <= 127) {
                    buf.append(ch);
                } else {
                    buf.append('\\');
                    buf.append(toHex((ch >> 12) & 0xF));
                    buf.append(toHex((ch >> 8) & 0xF));
                    buf.append(toHex((ch >> 4) & 0xF));
                    buf.append(toHex((ch >> 0) & 0xF));
                }
            }
        }
        return buf.toString();
    }






사실 이자료 저자료 뿔뿔히 흩어져있는 것들 모아서 정리하자고 쓴 글이었는데, 그래도 이정도면 다국어 처리문제로 고민하고 있는 개발자들에게 조금은 도움이 되지 않았을까 싶다.

부디 그랬기를.... ㅎㅎㅎ


발전하는 개발자가 되자! 아자 아자!


출처 : http://glass.tistory.com/45

Posted by 아로나