서블릿의 한글 코드 처리 과정.


[ 다음 글들 ] [ 이어서 글올리기(답하기) ] [ 자바 묻고 답하기 ]

글쓴이 :김덕태 1998년 1월 20일 03:47:09

In Reply to: 여기를 가 보세요... posted by 김필호 on 1998년 1월 18일 14:54:42:

우선 코드 변환의 용어에 대해서 약간 혼란스럽게 사용되고 있으나,


자바 표준에 의한 코드 변환은, 바이트 배열 혹은 바이트 스트림과
char 자료형 혹은 문자 스트림 사이에 자료가 전달되면
자바 언어의 정의에 의해서 무조건 코드변환이 일어나는 것으로 보고 있습니다.


관점에 따라 코드 변환을 약간 달리 볼 수는 있지만,
제가 보는 관점은 다음 3가지로 요약됩니다.


1. 자바는 char 자료형은 문자를 그 문자를 나타내는 16 비트 유니코드값으로 표현되도록 정의되어 있으며,
2. 자바 1.1의 많은 클래스들에서 문자가 char 자료형에서는 그렇게 표현되었을 때에만 제대로 해당 문자가
처리되도록 지원하고 있고
3. 자바 1.2를 비롯한 차후 버전은 현재 자바가 제대로 제대로 유니코드 표현의 한글을 지원하지
못하는 경우가 있는 부분 (특히, 서블릿과 데이타베이스)에 대한 지원을 확대하고 있습니다.


따라서, char 자료형에서는 유니코드에서의 한글 코드값으로 한글이 표현되는 것이 표준이며,
byte 자료형 및 HTML FORM 데이타, 서브릿 출력, 데이타베이스로의 저장등에서는 모두
자료가 KSC5601, 8859-1, UTF8등 여러가지 외부 인코딩이 사용되는 것으로 보면,
자바의 char 자료형의 자료가 이들 형태로 변환 혹은 입출력될 때는
인코딩이 바뀌므로, 코드 변환이 일어나는 것으로 봅니다.
(코드 변환은 반드시 코드 값이 변해야 함을 의미하는 것이 아니기 때문입니다.)


따라서, convert_to_ascii등등의 메쏘드는 코드 변환을 1번 한것이 아니라 2번 한 것입니다.



그 서블릿에서는 HTTP 프로토콜의 GET mothod를 통하여
getParameter 메쏘드로 그 값을 읽어들이셨더군요. (대부분의 경우 그렇듯이)


HTTP 프로토콜은 웹 문서의 인코딩을 웹 문서와 함께 덧붙여 보낼 수 있는
기능이 있어 다국어 기능을 어느 정도 제공하나,
GET method를 통하여 웹 서버로 입력을 전달할 때는, 인코딩을 첨부해서
넘겨주는 기능이 프로토콜에 없으므로, 자바도 완전하게 지원하지 못하고 있습니다.
즉, getParameter메쏘드는 HTML FORM으로부터 읽어들여 바이트값을 얻은 후에,
앞에 0을 붙여 16 비트 유니코드값을 만듭니다.
(마치 deprecate된 메쏘드인 DataInputStream의 readLine과 똑같이)
따라서, 프로그램내에서 명시적으로 코드 변환이 없다 할지라도,
getParameter가 앞에 0을 붙여 유니코드값을 만듦으로써, 입력 문자를
8859-1 문자로 가정하고 유니코드로 코드변환한 것이며,
역시 사용하고 계신 JDBC 드라이버는 유니코드의 8859-1 문자 영역의 코드값으로
가정하고 코드 변환하여 데이타베이스에 저장한 후, 검색되었으며,
ServletOutputStream의 println 메쏘드 역시 8859-1 의 유니코드 영역으로 가정하고
출력하였기에 한글이 제대로 출력 된 것이며, 이 중에서 8859_1가 아닌 인코딩을 가정하고
코드 변환하는 클래스 ( JDBC 드라이버, 혹은 FileWriter, OutputStreamWriter, ...등등)가
개입된다면 그 부분에서 한글이 깨지게 됩니다.


따라서, 정상적으로 유니코드의 한글 코드값으로 반환되지 않습니다.
유니코드의 한글 코드값으로 반환된 스트링은
자바 1.1의 System.out.println()을 사용해서 출력하면 한글이 출력되나,
getParamter()로 반환된 스트링을 그대로 화면에 출력하거나,
new PrintWriter(new FileInputStream(..))에 println 메쏘드를 사용해서
화일에 그 스트링을 출력하면 한글이 깨지게 될 것이며,
그 코드값을 Integer.toHexString()을 사용해서 16진수로 찍어보면
보다 확실하게 알 수 있습니다.



이때, getParamter()로부터 반환된 잘못 표현된 유니코드 문자열을
교정하는 방법이 convert_to_ascii의 역 메쏘드를 사용하는 것이고,
또 다른 방법은 잘못 표현된 유니코드를 사용하는 메쏘드만을
프로그램내에서 일관되게 사용하는 것입니다.


2가지 방법중에서 저는 일관되게 1번째 방법을 사용하나,
김필호님은 일관되게 2번째 방법을 사용하시더군요.
비록 잘못표현된 유니코드를 사용한다고 해도 상황에 따라 필요하다면
그리고 올바른 결과를 만들어낸다면 물론 의미가 있으며,
특히, 자바 1.1의 서블릿과 데이타베이스에서는 한글을 비롯한 다국어 지원이
미비한 부분이 있기 때문에 더욱 그러합니다.


그러나, 잘못 표현된 것이라는 사실은 명확히 해 두는 것이
최소한 개념상 혼란을 덜 초래합니다.
밑에 예제 프로그램을 첨부합니다.


사용하고 계신 방법은 DB에 유니코드로 저장되었다고 볼 수 없습니다.
UTF8을 비롯한 유니코드류의 인코딩으로 저장된다면,
이름이 한글 뿐아니라 프랑스어등 다양한 언어의 이름이
충돌없이 한글과 섞여서 저장될 수 있으며,
그것이 유니코드의 가장 중요한 목적이기 때문입니다.
그러나, 사용하신 방법으로는 그것이 불가능합니다.
(KSC5601 한글만을 다루는 것이 명백한 상황에서는 중요하지 않기는 하지만)



import java.io.*;


class StringBytesConvTest
{ public static void main(String[] args)
throws IOException
{ byte[] ksc = new byte[10000];
int count = 0;
for(int b; (b = System.in.read()) != -1; count++)
ksc[count] = (byte) b;


System.out.print( "KSC5601 (EUC-KR) 코드값 (16진수): " );
for(int i = 0; i < count; i++)
System.out.print( " " + Integer.toHexString(ksc[i] & 0xff) );
System.out.println();


System.out.print( "유니코드 2.0 코드값 (16진수): " );
String str = new String(ksc, 0, count, "KSC5601");
for(int i = 0; i < str.length(); i++)
System.out.print( " " + Integer.toHexString(str.charAt(i)) );
System.out.println();


System.out.print( "역변환된 KSC5601 (EUC-KR) 코드값 (16진수): " );
displayEncoding( str, "KSC5601" );
System.out.print( "역변환된 8859_1 코드값 (16진수): " );
displayEncoding( str, "8859_1" );
System.out.print( "역변환된 UTF8 코드값 (16진수): " );
displayEncoding( str, "UTF8" );


System.out.write( ksc, 0, count );
System.out.print( str );
System.out.flush();
}


static void displayEncoding( String str, String encoding )
throws UnsupportedEncodingException
{
byte[] bytes = str.getBytes(encoding);
for(int i = 0; i < bytes.length; i++)
System.out.print( " " + Integer.toHexString(bytes[i] & 0xff) );
System.out.println();
}
}


C:\example\i18n> java StringBytesConvTest
ab가나 (리턴키를 친후, Control-Z 입력)
KSC5601 (EUC-KR) 코드값 (16진수): 61 62 b0 a1 b3 aa d a
유니코드 2.0 코드값 (16진수): 61 62 ac00 b098 d a
역변환된 KSC5601 (EUC-KR) 코드값 (16진수): 61 62 b0 a1 b3 aa d a
역변환된 8859_1 코드값 (16진수): 61 62 3f 3f d a
역변환된 UTF8 코드값 (16진수): 61 62 ea b0 80 eb 82 98 d a
ab가나
ab가나




다음 글들:



이어서 글올리기(답하기)

이름:
E-Mail:
제목:
내용:
관련 URL(선택):
URL 제목(선택):
관련 이미지 URL:


[ 다음 글들 ] [ 이어서 글올리기(답하기) ] [ 자바 묻고 답하기 ]