OKJSP( http://www.okjsp.pe.kr/seq/72792 )
1. 모든 문서는 UTF-8 인코딩으로 저장되어야 합니다.
에디트 플러스의 경우 도구 -> 기본설정 -> 파일 부분에서 새 파일 형식을
UTF-8 로 해놓음으로써 새파일 작성시 UTF-8을 기본으로 작성할수 있고,
이미 다른 인코딩 타입에서 작성된 문서인 경우 내용을 모조리 Ctrl+C로 복사후
문서 -> 인코딩 변경 로드에서 UTF-8로 변경후 다시 붙여넣기 하면 됩니다.
이클립스의 경우 Package Explorer 에서 프로젝트에서 우측 버튼을 누른 후
Properties->Info->Text file encoding->Other 을 UTF-8 로 잡아주면 됩니다.
( 기존 다른 인코딩 타입에서 작성된 문서 내부 한글은 모조리 깨지게 됨 )
2. jsp 파일 상단에는 다음과 같은 방식으로 UTF-8 설정합니다.
<%@ page contentType = "text/html;charset=utf-8" %>
3. 서블릿은 다음과 같은 방식으로 UTF-8을 설정합니다.
request.setCharacterEncoding("utf-8")
4. 자바스크립트에서 encodeURIComponent 처리 및 톰캣 server.xml 의 설정 변경
위 1,2,3번의 방식으로 하면 post 방식의 데이터는 잘 받지만
get 방식의 데이터는 한글이 깨집니다.
이와 같은 경우 자바스크립트의 encodeURIComponent 함수와
server.xml 을 이용하여 처리하면 됩니다.
4.1 server.xml
톰캣 폴더의 conf 폴더에는 server.xml 파일이 존재합니다.
에디터로 열어보면
예)
<Connector port="8080" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" />
값이 약간 틀릴수 있지만 초기 셋팅 값이 보통 저러하고,
Connector 은 초기에 2개가 있는데 8080 포트 부분을 수정하면 됩니다.
수정하는 방법은
URIEncoding="UTF-8" 을 추가하면 됩니다.
예)
<Connector port="8080" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="utf-8" />
위와 같이 했다고 해결되는 것은 아닙니다. get 방식으로 데이터를 전송하면
자바 파일에서 확인 했을 경우 물음표 값만 넘어옵니다.
get 방식으로 보낼 경우 자바스크립트로 변환을 해줍니다.
예를 들어 "한글"을 자바스크립트에서
<SCRIPT>alert( encodeURIComponent("한글") )</SCRIPT>
처럼 encodeURIComponent 함수로 변환하게 되면 %ED%95%9C%EA%B8%80 으로
변환됩니다. 이 값을 주소에 "한글" 대신에 넣게 되면 자바에서 알아서 잘~ 받습니다 ^^
utf-8 인코딩을 이용한 한글 url 처리 [ 조회수: 393 ] |
| |
개요
- utf-8 은 유니코드를 위한 가변길이 문자 인코딩 방식중 하나로 켄 톰프슨과 롭 파이크가 만들었다.
- 유니코드 한문자를 표시하기 위해 1byte~4byte 까지 가변적으로 표현한다.
- U+0000부터 U+007F 범위에 있는 아스키 문자들은 UTF-8에서 1바이트만으로 표시된다. 4바이트로 표현되는 문자는 모두 기본 다중언어 평면(BMP) 바깥의 유니코드 문자이며, 거의 사용되지 않는다.
구조
- U+007F(0~127) 까지의 문자는 7비트 아스키 문자와 동일하게 표시된다.
- U+007F 이후의 문자는 4byte 까지의 비트 패턴으로 표시되며 7비트 아스키 문자와 혼동되지 않게 하기 위해 모든 바이트의 최상위 비트는 1 이다.
| 코드 범위 |
UTF-16BE 표현 |
UTF-8 표현 |
설명 |
| 000000 ~00007F |
00000000 0xxxxxxx |
0xxxxxxx |
아스키와 동일한 범위 |
| 000080 ~0007FF |
00000xxx xxxxxxxx |
110xxxxx 10xxxxxx |
첫바이트는 110 으로 시작하고, 나머지 바이트는 10으로 시작함 |
| 000800 ~00FFFF |
xxxxxxxx xxxxxxxx |
1110xxxx 10xxxxxx 10xxxxxx |
첫바이트는 1110으로 시작하고 , 나머지는 10으로 시작함 |
| 010000 ~10FFFF |
110110yy yyxxxxxx 110111xx xxxxxxxx |
11110zzz 10zzxxxx 10xxxxxx 10xxxxxx |
UTF-16 "surrogate pair" 영역(yyyy=zzzzz -1) |
clear=all>
utf-8 인코딩 예제
'위'(한글) --> U+C7404(유니코드) U+0800부터 U+FFFF 사이의 영역에 있으므로, 표에 따라 1110xxxx 10xxxxxx 10xxxxxx 형식으로 인코딩 C704(16진수) --> 1100-0111-0000-0100(2진수) --> 11101100 10011100 10000100(utf-8 인코딩) 결과적으로 이 문자는 3바이트로 인코딩 되면 16진수로 표기하면 EC 9C 84가 된다.
(첫 128 문자는 1바이트로 표시되고, 그 다음 1920 문자 (판독 기호가 붙은 라틴 문자, 그리스 문자, 키릴 문자, 콥트 문자, 아르메니아 문자, 히브리 문자, 아랍 문자)는 2바이트로 표시되며, 나머지 문자들 중 BMP 안에 들어 있는 것은 3바이트, 아닌 것은 4바이트로 표시된다.) |
관련자료
utf-8 체크
-
- 입력된 문자열이 utf-8로 인코딩 되었는지 하기 위해서는 utf-8 의 인코딩 패턴을 조사한다. 즉 바이트 배열의 패턴이 utf-8 인코딩 패턴(1110xxxx 10xxxxxx 10xxxxxx)과 맞는지를 비교한다.
- 000080 ~0007FF 범위의 110xxxxx 10xxxxxx 패턴 일 경우엔 중복되는 코드값으로 인해 utf-8 인코딩인지 아닌지 체크하는것은 사실상 불가능하다.
110xxxxx 10xxxxxx 패턴의 utf-8 판독
110xxxxx 10xxxxxx 패턴의 코드일 경우 utf-8로 인코딩 되었는지 아닌지를 확인하는것은 사실상 불가능하다. 하지만 utf-8로 인코딩 되면 아스키 영역은 1byte 한글은 3byte 내지는 4byte를 사용하므로 단순하게 생각하여 2 바이트 110xxxxx 10xxxxxx 패턴의 경우는 utf-8 인코딩이 아님을 유추할수 있다. 판독 기호가 붙은 라틴 문자, 그리스 문자, 키릴 문자, 콥트 문자, 아르메니아 문자, 히브리 문자, 아랍 문자 등이 입력되면 판독 오류가 발생하겠지만 이는 무시해도 좋을듯 하다. |
- Null 값의 경우 자바에서는 변형된 utf-8 인코딩 방식에 따라 1byte가 아닌 2byte(11000000 10000000)로 표기하므로 110xxxxx 10xxxxxx 의 경우 null 인지 비교해야 정확한 판독이 가능하지만 입력된 값의 인코딩여부를 판독하므로 상황에 따라서는 무시해도 괜찮을듯 하다.
- CJK 2바이트+한글 2바이트 가 '1110xxxx 10xxxxxx 10xxxxxx 0xxxxxxx' 와 같은 패턴으로 utf-8 3바이트 와 아스키1바이트 조합과 유사할 경우 앞자리 3바이트를 유니코드 형태로 역치환 해서 000800 ~00FFFF 범위가 맞는지 체크한다.
utf-8 인코딩 체크 예제
utf-8 인코딩 판독 예제
1. '위'.getBytes("ISO-8859-1") : -20 , -100, -124 2. unsigned byte = 236, 156, 132 3. 16진수 : EC , 9C, 84 4. 2진수 : 11101100 10011100 10000100 5. urf-8 패턴제거: 00001100 00011100 00000100 6. 유니코드 타입으로 치환 : 00001100<<12 + 0011100<<6 + 00000100 = 11000000 00000100 7. 16진수 : 000800 <= 00E704 =< 00FFFF |
package util;
import java.io.UnsupportedEncodingException;
/**
* <pre>
* 작성자 : 이종희 (qola@naver.com)
* JAlbum.com (http: * <b>특정 문자열이 utf-8 인코딩인지 아닌지 체크한다.</b>
*
* utf-8 인코딩 패턴인 110xxxxx 10xxxxxx , 1110xxxx 10xxxxxx 10xxxxxx 인지 비교한다.
* 2바이트 (110xxxxx 10xxxxxx) 패턴의 유니 코드 중복으로 인해 100% 검증할수 없지만
* 한글의 경우 3byte 로 표기 되므로 2바이트 패턴일 경우 utf-8 인코딩이 아닌것으로 간주한다.
*
* 따라서 000080 ~0007FF 영역의 라틴 문자, 그리스 문자, 키릴 문자, 콥트 문자,
* 아르메니아 문자, 히브리 문자, 아랍 문자 등은 utf-8 인코딩을 비교할수 없다.
*
* 수정된 utf-8의 의한 null값 \u0000 은 11000000 10000000 로 표기되지만 무시하기로 한다.
*
* </pre>
*/
public class UTFUtil {
public static boolean isUTF8(String str) throws Exception{
byte[] bytes=str.getBytes("ISO-8859-1");
return isUTF8(bytes,0,bytes.length);
}
public static boolean isUTF8(byte[] buf, int offset, int length) {
boolean yesItIs = false;
for (int i=offset; i<offset+length; i++) {
if ((buf[i] & 0xC0) == 0xC0) { int nBytes;
for (nBytes=2; nBytes<8; nBytes++) {
int mask = 1 << (7-nBytes);
if ((buf[i] & mask) == 0) break;
}
if(nBytes==2) return false;
for (int j=1; j<nBytes; j++) {
if (i+j >= length || (buf[i+j] & 0xC0) != 0x80) return false;
}
if(nBytes==3){
char c = (char) (((buf[i] & 0x0f) << 12) + ((buf[i+1] & 0x3F) << 6) + (buf[i+2] & 0x3F));
if(!(c >= 0x0800 && c <= 0xFFFF)){
return false;
}
}
yesItIs = true;
}
}
return yesItIs;
}
}
clear=all>
한글 URL 사용시 문제 발생 케이스
- IE에는 유니코드 지원을 위해 기본적으로 URL을 UTF-8 로 전송해 주지만 옵션 사항이므로 사용자 마다 환경이 다를수 있다.
- utf-8로 다시 보내는 기능을 제공하지 않는 브라우저도 존재한다.
- RSS 리더와 같은 별도의 클라이언트를 사용할경우 서버인코딩, 클라이언트, 브라우저 인코딩 이 모두 일치하여야만 한다.
해결책
- REQUEST 요청시 URL이 UTF-8 인코딩 방식인지 아닌지를 체크하여 UTF-8 방식이면 "ISO-8859-1 --> UTF-8" 형태로 인코딩 변환을 해주고 그렇지 않으면 "ISO-8859-1 --> MS949" 로 인코딩 변환을 시켜준다.
구현 예제
- APACHE MOD_REWRITE
- 아래 예와 같이 MOD_REWRITE를 이용해 특정 패턴의 URL을 REWRITE 시킨다.
RewriteEngine on
# RewriteRule ^/tag2/(.+)$ /tag/index.jsp?tag=$1 [PT]
- JSP 샘플
- isUTF8() 체크 메소드를 이용해 파라메터의 인코딩을 각각 처리해준다.
<%@page language="java" contentType="text/html;charset=utf-8"%>
<%@page import="java.net.URLEncoder, util.*" %>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
</head>
<body>
index.jsp... <br>
<%
String uri=request.getRequestURL().toString();
String tag=request.getParameter("tag");
byte[] tagBytes=tag.getBytes("ISO-8859-1");
out.println("byte[]===");
for(int i=0;i<tagBytes.length;i++){
out.println(tagBytes[i]+",");
}
out.println("<br>");
boolean isUTF8=UTFUtil.isUTF8(tag);
if(isUTF8) {
out.println(util.Enco.toUtf(tag));
out.println("<br>");
out.println(isUTF8);
}else{
out.println(new String(tag.getBytes("ISO-8859-1"),"ms949"));
out.println("<br>");
out.println(isUTF8);
}
%>
<a href="http:>http://tag_test.com/tag2/한글</a><br>
<a href="http:>http://tag_test.com/tag2/코리아</a><br>
<a href="http:>http://tag_test.com/tag2/위</a>
</body>
</html> |