많은 분들이 jsp에서 한글처리때문에 많은 고생을 하고 계신데 한글처리는
동작원리만 알면 쉽게 풀수 있는 문제입니다.
그럼. 동작원리를 잠깐 알아볼까요.... ^^
먼저 자바는 유니코드를 사용한다는 사실을 인지해야합니다.
(자바하시는 분들은 다 알고 있지만 한글처리를 하실때 많이 빼먹는 부분이기도합니다)
다시 말해서 jsp(java) 안에서는 문자열이 유니코드라는 것입니다.
그럼. 브라우저에서 request를 보낼 때 입니다.
HTTP 요청은 8859_1로 보냅니다. 즉 다시 말하면 한글완성형코드 그대로 변환없이
보냅니다. (byte그대로...)
일단 간략하게 그리면
브라우저 한글완성형코드 그대로 전송 --request(*)--> jsp 컨테이너에서 유니코드로 변환 --> 내부처리
--response(*)--> 결과물을 브라우저로 전송
(*)부분에서 유니코드<-->해당문자열코드로 변환이 일어납니다.
request(*)에서 문자셋이 지정되어 있지 않으면 (이 말은 브라우저가 request를 요청할 때 특별히
문자셋을 지정하지 않았을 때, 가장 일반적인 상황입니다) 8859_1로 처리됩니다.
즉. "한"이라는 문자열을 보냈다고 했을 때 완성형코드 2byte가 그대로 전송되죠.
8859_1 문자셋코드를 유니코드로 변환하면 상위바이트와 하위바이트가 각각 1자의
유니코드로 변환되므로 "한"이라는 글자는 유니코드 2자로 변환됩니다.
아시다시피 유니코드에서 한글은 1자입니다. 이 변환이 있더라도 한글byte가 깨지지는 않습니다.
왜냐하면 상위, 하위바이트가 각각 유니코드 안에 그대로 살아있기때문입니다.
이 경우 유니코드문자열.getBytes("8859_1")의 메소드 호출로 원래 byte열로 돌릴 수 있기 때문입니다.
request에서 기본 8859_1 문자셋을 다른 문자셋으로 바꾸는 메소드가 있죠.
request.setCharacterEncoding("euc-kr") 이라고 하면(반드시 파라미터를 읽기 이전에 해야합니다)
한글 1자(2byte)를 유니코드 1자로 변환해줍니다..
response(*) 부분은 브라우저에 보내기전에 유니코드를 해당 문자셋의 byte열로 변환하는 부분입니다.
page 태그나 response.setContentType() 메소드에서 "text/html; charset=euc-kr" 식으로 설정가능합니다.
지정하지 않으면 역시 8859_1로 처리되므로 request에서 8859_1이면 들어온 그대로 다시 보내므로
어떤 문자코드라도 깨지지 않습니다. 그러나 euc-kr로 되어 있으면 유니코드 --> 한글완성형
변환시 유니코드 1자를 한글 1자로 인식하기때문에 한글유니코드는 2byte의 완성형 코드로 변환됩니다.
여기서 한글유니코드를 8859_1으로 변환하면 유니코드의 상위byte가 없어지고 하위byte만 사용됩니다.
그러니 한글이 깨져서 브라우저로 전송됩니다.
이 경우 글자의 상위byte가 없어지므로 되돌릴 수 없습니다.
그래서 한글이 정상적으로 처리될려면
1, 브라우저 -- 8859_1(default) --> jsp 컨테이너(jsp/java) -- 8859_1(default) --> 브라우저
(* 비추전)
2. 브라우저 -- euc-kr(요청시 브라우저에서 지정하던지, 아니면 setCharacterEncoding사용 -->
jsp 컨테이너(jsp/java) -- euc-kr(response에서 contentType으로 지정) --> 브라우저
(* 추전)
3. jsp 내에서 <jsp:include>(실행시간include)로 jsp가 아닌 한글화일(html등) 포함할 때는 jsp컨테이너가 실행될 때
시스템 문자셋에 따라서 변환이 됩니다.
그래서 1의 경우일 경우 시스템은 반드시 8859_1로 문자셋(로케일의 문자코드셋)으로 되어야하고
2의 경우는 한글코드(리눅스, 원도우즈에 따라 명칭이 다르지만 기본적으로 완성형표준코드입니다)로
지정되어 있어야 깨지지 않습니다.
4. 자바빈이나 db에서 한글처리 1의 경우를 비추천으로 하는 이유는 자바빈이나 db에서도
모두 8859_1로 맞추어 주어야한다는 것입니다. 즉 클래스를 컴파일할 때도 컴파일 옵션에 8859_1로
지정해주어야 클래스안의 한글이 깨지지 않습니다. (디폴트로 시스템 문자셋으로 컴파일, 원도는 당근 한글셋)
2의 경우는 euc-kr로 맞추어 주어야합니다. 대부분 개발시스템의 문자셋은 당근 한글이겠죠 ^^
2의 경우에서 mysql의 연결url에 unicode사용 옵션을 주고 문자셋을 주면 그냥 됩니다.
(상세한 옵션: jdbc:mysql://localhost/디비명?useUnicode=true&characterEncoding=euc-kr)
오라클도 시스템 문자셋에 따라 알아서 동작하는데
db가 asc7인가(갑자기 기억안남) 일때 문제가 있는 경우가 있는데 이경우 오라클 클라이언트를
같이 맞추어주고 getString(...)메소드를 읽을 때 new String(XXX.getBytes(8859_1), "euc-kr")로
변환해주어야 합니다. 이건 오라클 jdbc드라이버가 db asc7 --> client euc-kr 변환을 못해주는 것 같습니다.
asc7 --> 8859_1 --> euc-kr 요렇게 두번 해주어야 하는데 asc7 --> euc-kr 요렇게 바로 해버리니까
한글이 깨지는 것 같습니다.(오라클 jdbc 스펙을 확인해보세요..)
동작원리만 알면 쉽게 풀수 있는 문제입니다.
그럼. 동작원리를 잠깐 알아볼까요.... ^^
먼저 자바는 유니코드를 사용한다는 사실을 인지해야합니다.
(자바하시는 분들은 다 알고 있지만 한글처리를 하실때 많이 빼먹는 부분이기도합니다)
다시 말해서 jsp(java) 안에서는 문자열이 유니코드라는 것입니다.
그럼. 브라우저에서 request를 보낼 때 입니다.
HTTP 요청은 8859_1로 보냅니다. 즉 다시 말하면 한글완성형코드 그대로 변환없이
보냅니다. (byte그대로...)
일단 간략하게 그리면
브라우저 한글완성형코드 그대로 전송 --request(*)--> jsp 컨테이너에서 유니코드로 변환 --> 내부처리
--response(*)--> 결과물을 브라우저로 전송
(*)부분에서 유니코드<-->해당문자열코드로 변환이 일어납니다.
request(*)에서 문자셋이 지정되어 있지 않으면 (이 말은 브라우저가 request를 요청할 때 특별히
문자셋을 지정하지 않았을 때, 가장 일반적인 상황입니다) 8859_1로 처리됩니다.
즉. "한"이라는 문자열을 보냈다고 했을 때 완성형코드 2byte가 그대로 전송되죠.
8859_1 문자셋코드를 유니코드로 변환하면 상위바이트와 하위바이트가 각각 1자의
유니코드로 변환되므로 "한"이라는 글자는 유니코드 2자로 변환됩니다.
아시다시피 유니코드에서 한글은 1자입니다. 이 변환이 있더라도 한글byte가 깨지지는 않습니다.
왜냐하면 상위, 하위바이트가 각각 유니코드 안에 그대로 살아있기때문입니다.
이 경우 유니코드문자열.getBytes("8859_1")의 메소드 호출로 원래 byte열로 돌릴 수 있기 때문입니다.
request에서 기본 8859_1 문자셋을 다른 문자셋으로 바꾸는 메소드가 있죠.
request.setCharacterEncoding("euc-kr") 이라고 하면(반드시 파라미터를 읽기 이전에 해야합니다)
한글 1자(2byte)를 유니코드 1자로 변환해줍니다..
response(*) 부분은 브라우저에 보내기전에 유니코드를 해당 문자셋의 byte열로 변환하는 부분입니다.
page 태그나 response.setContentType() 메소드에서 "text/html; charset=euc-kr" 식으로 설정가능합니다.
지정하지 않으면 역시 8859_1로 처리되므로 request에서 8859_1이면 들어온 그대로 다시 보내므로
어떤 문자코드라도 깨지지 않습니다. 그러나 euc-kr로 되어 있으면 유니코드 --> 한글완성형
변환시 유니코드 1자를 한글 1자로 인식하기때문에 한글유니코드는 2byte의 완성형 코드로 변환됩니다.
여기서 한글유니코드를 8859_1으로 변환하면 유니코드의 상위byte가 없어지고 하위byte만 사용됩니다.
그러니 한글이 깨져서 브라우저로 전송됩니다.
이 경우 글자의 상위byte가 없어지므로 되돌릴 수 없습니다.
그래서 한글이 정상적으로 처리될려면
1, 브라우저 -- 8859_1(default) --> jsp 컨테이너(jsp/java) -- 8859_1(default) --> 브라우저
(* 비추전)
2. 브라우저 -- euc-kr(요청시 브라우저에서 지정하던지, 아니면 setCharacterEncoding사용 -->
jsp 컨테이너(jsp/java) -- euc-kr(response에서 contentType으로 지정) --> 브라우저
(* 추전)
3. jsp 내에서 <jsp:include>(실행시간include)로 jsp가 아닌 한글화일(html등) 포함할 때는 jsp컨테이너가 실행될 때
시스템 문자셋에 따라서 변환이 됩니다.
그래서 1의 경우일 경우 시스템은 반드시 8859_1로 문자셋(로케일의 문자코드셋)으로 되어야하고
2의 경우는 한글코드(리눅스, 원도우즈에 따라 명칭이 다르지만 기본적으로 완성형표준코드입니다)로
지정되어 있어야 깨지지 않습니다.
4. 자바빈이나 db에서 한글처리 1의 경우를 비추천으로 하는 이유는 자바빈이나 db에서도
모두 8859_1로 맞추어 주어야한다는 것입니다. 즉 클래스를 컴파일할 때도 컴파일 옵션에 8859_1로
지정해주어야 클래스안의 한글이 깨지지 않습니다. (디폴트로 시스템 문자셋으로 컴파일, 원도는 당근 한글셋)
2의 경우는 euc-kr로 맞추어 주어야합니다. 대부분 개발시스템의 문자셋은 당근 한글이겠죠 ^^
2의 경우에서 mysql의 연결url에 unicode사용 옵션을 주고 문자셋을 주면 그냥 됩니다.
(상세한 옵션: jdbc:mysql://localhost/디비명?useUnicode=true&characterEncoding=euc-kr)
오라클도 시스템 문자셋에 따라 알아서 동작하는데
db가 asc7인가(갑자기 기억안남) 일때 문제가 있는 경우가 있는데 이경우 오라클 클라이언트를
같이 맞추어주고 getString(...)메소드를 읽을 때 new String(XXX.getBytes(8859_1), "euc-kr")로
변환해주어야 합니다. 이건 오라클 jdbc드라이버가 db asc7 --> client euc-kr 변환을 못해주는 것 같습니다.
asc7 --> 8859_1 --> euc-kr 요렇게 두번 해주어야 하는데 asc7 --> euc-kr 요렇게 바로 해버리니까
한글이 깨지는 것 같습니다.(오라클 jdbc 스펙을 확인해보세요..)