차근차근/이것저것

자바 웹프로젝트를 진행하여 겪는 한글인코딩 문제들 모음.

예쁜꽃이피었으면 2014. 12. 23. 13:33

http://slipp.net/questions/254



현재 Spring + Mybatis 프레임워크와 Tomcat, MySql을 이용한 프로젝트를 진행하고 있습니다.
프로젝트 초창기부터 한글데이터를 기준으로 설계하였습니다.
때문에 디렉토리나 파일구조도 한글에 맞추는 방향으로 프로그래밍을 진행하였구요. 
하지만 프로젝트를 진행하는 내내 한글문제가 발생합니다. 그것에 대한 리서치에도 굉장한 시간을 투자하게 되고요.

혹자는 글로벌사회에 '굳이 한글을 써야하나'..라고 할 수도 있지만
반대로 '굳이 쓰지 말아야할 이유가 있을까..?'라는 생각이 들었습니다. 
만약 사용자가 모두 한국인이라고 가정한다면 한글을 사용하는편이 오히려 restful하지 않을까??라는 생각에서였지요. 
그리고 지금 (첫프로젝트입니다) '한글문제를 피하게 되면 평생 프로그래밍할때마다 피하지 않을까?'라는 생각을 하니까
오기가 더욱 생긴거 같구요..

이 글을 통해서 짧은 시간동안에 제가 겪은 한글문제들을 공유해보고자 하며,
더불어 현재 맞닥트린 문제를 여쭙고자 이렇게 글을 씁니다.
저와 비슷한 문제를 겪을 사람들이 조금이나마 수고을 덜었으면 하는 바람입니다.

추가, 혹은 지적해주시는 내용들은 본문에 추가,수정하도록 하겠습니다.
제 미약한 지식에 적극적인 보탬을 부탁드립니다..

  • 아래내용 (본 프로젝트)에서는 URLEncoding을 전혀 사용하지 않았습니다.
  • 아래에 언급되지는 않지만 소스코드파일의 인코딩은 원하는 설정의 인코딩방식과 동일하게 작성되어야 합니다.

1) GET 요청시 한글 URL 오류.

예를들어 다음과같이 (localhost:8080/2013/자바지기) 요청이 있다고 가정합니다.
spring controller메소드에서 @Pathvariable 로 사용하는 url value를 한글로 사용할 경우,
controller메소드에서 전달받은 데이터 인코딩값이 깨지게 됩니다.


@RequestMapping("/{class1}/{professor}")
public String lecture_detail(@PathVariable String professor) {
//professor 데이터 인코딩 깨짐
}

이 문제는 tomcat 요청시 별다른 파라미터 전달이 없을경우 (header의 encoding setting 요청이 없을경우)
톰캣의 기본인코딩 설정인 8859_1형태로 인코딩되어 발생합니다.
저같은 경우에는 Spring 프로젝트의 web.xml에 encodingFilter를 UTF-8로 설정하였기 때문에
위 메소드의 파라미터로 전달받는 데이터는 8859_1인코딩 + Spring에 설정된 UTF-8인코딩 된 데이터가 전달되게 됩니다.
그러므로 정상적인 데이터를 확인하기 위해서는 아래와 같이 디코딩을 2번해야지만 정상적인 한글이 출력되게 됩니다.


URLDecoder.decode((URLDecoder.decode(param, "8859_1")), "UTF-8"); //방법1
new String(param.getBytes("8859_1"), "utf-8"); //방법2

2) 특정한글이 포함된 URL요청에서 404 not found 에러발생

1)을 통해서 한글데이터를 정상적으로 주고받을 수 있게 되었지만, 특정글자에서 URL인식이 무시되는 현상이 생깁니다.
예를들어 (localhost:8080/2013/한글) 요청에서 '한글'부분에 '종', '눅', '년' 과 같은 글자가 포함될 경우 
404에러가 발생했습니다. 이 부분은 스프링이 아닌 톰캣의 URL요청상의 문제이며 요청 URL의 인코딩과정에서 일어나는 현상입니다.
Tomcat의 server.xml에 설정값을 추가합니다. (리눅스의 경우 /var/lib/tomcat/conf/server.xml)

<Connector port="8080" URIEncoding="UTF-8" connectionTimeout="20000" protocol="HTTP/1.1" redirectPort="8443"/>

여기서 설정하는 URIEncoding의 설정은 1)에서 기본인코딩설정을 8859_1에서 지정하는 Charset으로 변경해줍니다.
이외에 설정할 수 있는 Tomcat옵션은 URL(http://tomcat.apache.org/tomcat-5.5-doc/config/http.html)을 
통해서 확인할 수 있습니다.

여기서 주목할 만한 옵션을 한가지 보자면, useBodyEncodingForURI="true"로 사용하는 항목을 확인할 수 있습니다. 
Tomcat Encoding으로 검색할 경우 많은 포스트에서 보이는 옵션으로,
HTTP Header 영역의 ContentType안에 특별히 정의된 charset이 있을경우 Tomcat에 정의된 URIEncoding 값보다 우선적용됩니다.
JSP에서 자주등장하는 setCharacterEncoding을 사용하지 않더라도, 
헤더에 Content-type=application/x-form-urlencoded;charset=UTF-8"으로 전송하게되면 실제로 UTF-8로 인코딩이 됩니다.

이렇게 server.xml에 설정을 추가하게되면, 이전에 사용했던 1)번의 디코딩방식을 사용하면 안됩니다.
오히려 사용하면 에러가 발생하지요.

3) DB 질의시 한글 Param에 대한 오류.

mybatis를 이용한 데이터베이스 쿼리시, 한글 Param값에 해당하는 항목들이 ??????????와 같이 처리되는것이 확인되었습니다.
데이터베이스의 charset 설정값이 UTF-8임에도 불구하고, 한글 Param값에서는 에러가 발생했습니다.
물론 쿼리가 제대로 이루어지지 않았구요.
이 문제는 Connection Pool에 인코딩설정값을 더해줌으로서 해결할 수 있었습니다.
database url 선언시 하단과 같이 설정하게되면 query에 포함되는 유니코드값이 원하는 형태로 인코딩 됩니다.

String databaseURL ="jdbc:mysql://localhost:3306/dbName?useUnicode=true&characterEncoding=UTF8";

4) 리눅스 원격접속 (SSH) 한글사용하기

ssh환경에서 한글파일에 대한 테스트를 진행하고자 했는데, 기본적으로는 사용할 수 없었습니다.
(타이핑해도 제자리에서 멤도는 그 현상..) 원격서버의 몇가지 설정을 변경해주고 나니 한글사용이 가능했습니다.

/etc/sysconfig/i18n

LANG="ko_KR.UTF-8"
SUPPORTED="ko_KR.UTF-8:ko_KR:ko"

/etc/vimrc
if v:lang =~ "utf8$" || v:lang =~ "UTF-8$" 
set fileencodings=utf-8,euc-kr 
endif

/etc/bashrc

export LANG="ko_KR.UTF-8" 
export LC_ALL="ko_KR.UTF-8"

5) Mac에서 JDK 7.0을 사용할 경우, Unicode로 처리된 파일명을 읽지 못할경우

해당링크를 통해 확인할 수 있습니다 (http://www.slipp.net/questions/210)

6) Tomcat 환경에서 한글파일 생성하기. (질문드립니다.)

일반적인 자바프로젝트를 이클립스에서 작성하고, 실행하거나 Terminal에서 java컴파일 명령을 통해서 실행하거나,
두경우 모두 한글파일을 생성하는 경우에서는 별 이슈없이 원하는 CharacterSet으로 파일이나 디렉토리를 생성할 수 있었습니다.
하지만 tomcat을 이용하는 현재의 Spring 프로젝트는,
한글파일을 생성할 경우 파일제목이 글자수만큼 ?로 표기되는 현상이 일어납니다..
예를들어 자바지기.png를 만들면 ????.png로 보이는 것이지요. 시스템설정쪽은 확인해봤지만 UTF8로 잘 되어있습니다. 
톰캣프로젝트에서 실행할 경우에만 이런현상이 발견되는데... 비슷한 경험있으시다면 공유좀 부탁드리겠습니다!!!

import java.io.File;

public class KoreanTest {
  public static void main(String[] args) {
    File file1 = null;
    File file2 = new File("/Users/YOON-SUNG/Desktop/test/javajigi.png");
    
    try {
      
      file1 = new File( new String("/Users/YOON-SUNG/Desktop/test/자바지기.png".getBytes(), "UTF-8") );;


      System.out.println("file1 exists? : "+file1.exists());
      System.out.println("file2 exists? : "+file2.exists());      
      System.out.println("file1 create sucess? : "+file1.createNewFile());
      System.out.println("file2 create sucess? : "+file2.createNewFile());
      
      
      
      //file1.renameTo(new File( new String("/Users/YOON-SUNG/Desktop/test/정윤성.png".getBytes(), "UTF-8")));
      
    } catch (Exception e) {
      e.printStackTrace();
    }
    
    System.out.println("System File Encoding : "+System.getProperty("file.encoding")); //UTF8로 잘 표기됩니다.
  }
}

위 소스는 Tomcat프로젝트와 일반프로젝트에서 동일하게 테스트되었습니다.

(2014년 2월 4일 추가)

7) Spring에서 사용하는 JSON의 인코딩문제

Spring에서 JSON, 혹은 String 데이터를 View영역으로 전달할때, Ajax통신을 하는 과정에서 @ResponseBody 예약어를 사용했습니다. 
일반적으로 사용하는 MODEL 패턴을 사용할대는 객체안에 한글데이터를 담기 때문에 문제가 생기지 않지만,
브라우저를 통해 직접 데이터를 전달해주는 JSON방식에서는 한글이 깨졌습니다. 
이 문제는 아래의 소스코드와 같이 produces 항목에 charset을 지정해주게 되면, 해당 인코딩방식으로 데이터를 처리해서 전달시키게 됩니다.


@RequestMapping(value="/test/SelectTreeViewData", method=RequestMethod.GET, produces="text/plain;charset=UTF-8")
  public @ResponseBody String selectTreeViewJoinData() {
    
    List<TreeViewJoinData> data = treeViewDao.selectTreeViewData();
    Gson gson = new Gson(); //구글에서 제공되는 JSON Parsing라이브러리
    String result = gson.toJson(data); //JSON형태의 스트링값으로 변환.
    
    return result;
  }


반응형