본문 바로가기
교재 실습/자바 웹 개발 워크북

26. 요청 매개변수의 한글 깨짐 처리

by Jint 2022. 1. 22.

웹 브라우저에서 보낸 한글 데이터를 서블릿에서 꺼낼 때 한글이 깨지는 경우가 있다. 그 이유와 해결책을 알아본다.

 

회원등록 입력폼의 이름 입력단에 한글 이름을 입력 후 추가버튼을 클릭한다(그림 1).

그림 1 (입력폼에 한글 입력)

회원 목록 조회 결과를 확인한다(그림 2).

그림 2 (회원 목록 조회 결과)

한글로 '가각간'이라고 입력한 이름부분이 깨진 것을 확인할 수 있다.

그림 3 (DB의 데이터 출력)

DB의 MEMBERS 테이블 조회문을 실행하니 한글이 깨져서 데이터가 저장된 것 또한 확인할 수 있다(그림 3).

한글이 깨진 이유를 살펴보기 위해 웹 브라우저의 기본 문자집합을 확인한다(그림 4).

 

그림 4 (크롬의 기본 문자집합 확인)

현재 사용하는 크롬의 기본 문자집합이 유니코드(UTF-8)로 설정되어 있는 것을 확인할 수 있다.

(크롬은 따로 기본 문자집합을 확인할 수 있는 방법이 없어서 Set Character Encoding 이라는 크롬 확장 프로그램을 설치하여 확인하였다)

웹 브라우저가 웹 서버로 데이터를 보낼 때 웹 페이지의 기본 문자집합으로 인코딩하여 보내기 때문에 사용자가 입력한 값은 UTF-8로 인코딩되어 서버에 전달된다. 즉, 웹 브라우저에선 한글이 깨지지 않게 보내짐을 확인할 수 있다.

 

그럼 서블릿에서 데이터를 꺼낼 때 문자 형식을 살펴본다. MemberAddServlet 클래스의 doPost()에서 입력 매개변수에 값을 지정할 때 HttpServletRequest 클래스의 메소드 getParameter()를 호출하는 모습을 볼 수 있다.

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ...
    stmt.setString(1, request.getParameter("email"));
    stmt.setString(2, request.getParameter("password"));
    stmt.setString(3, request.getParameter("name"));
    ...
}

서블릿에서 getParameter()를 호출하면 기본적으로 매개변수의 값이 ISO-8859-1(ISO-Latin-1)로 인코딩되었다고 가정하고 각 바이트를 유니코드로 바꾸고 나서 반환한다. 즉 클라이언트가 보낸 문자를 영어로 간주하고 유니코드로 바꾼다. 바로 여기서 문제가 발생한 것이다. 서블릿이 웹 브라우저로 받은 한글 데이터는 UTF-8로 인코딩된 값이다. UTF-8은 한글 한 자를 3바이트로 표현한다. 서블릿은 이 3바이트를 하나의 문자로 인식하지 않고 각각의 바이트를 개별 문자로 취급하여 유니코드를 변환하기 때문에 각각으론 의미 없는 바이트들이 유니코드로 바뀌어져 한글이 깨진 것이다(그림 5).

그림 5 (입력 데이터의 유니코드 문자 변환)

 

한글이 깨지는 것을 해결하려면 getParameter()를 호출하기 전에 클라이언트가 보낸 매개변수의 값이 어떤 인코딩으로 되어 있는지 지정해야 한다.

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    //setCharacterEncoding() : 매개변수 값의 인코딩 형식 지정하는 메소드(이 메소드가 호출되기 전 getParameter()가 호출되면 아무 소용 없다.)
    request.setCharacterEncoding("UTF-8");
    
    ...
    stmt.setString(1, request.getParameter("email"));
    stmt.setString(2, request.getParameter("password"));
    stmt.setString(3, request.getParameter("name"));
    ...
}

HttpServletRequest 클래스의 메소드 setCharacterEncoding()는 매개변수 값의 인코딩 형식을 지정한다. 단, 이 메소드가 호출되기 전에 getParameter()를 호출하면 이 메소드의 기능이 아무 소용없어 진다.

 

톰캣 서버를 재시작한 뒤 회원 정보를 다시 등록하고 회원 목록 조회 결과를 확인한다.

그림 6 (회원 목록 조회 결과)

마지막 행을 보면 한글이 깨지지 않고 제대로 출력된 것을 확인할 수 있다.

그림 7 (DB의 데이터 출력)

DB의 MEMBERS 테이블 조회문을 실행하니 한글이 깨지지 않고 올바르게 저장된 것을 확인할 수 있다.

 

톰캣(5.X 이상)의 경우 클라이언트에서 GET 요청으로 데이터를 보내면 여전히 한글이 깨진다. GET 요청에서는 매개변수의 값을 URL에 포함하여 보내는데 setCharacterEncoding()은 이런 쿼리스트링에 대해서는 적용되지 않기 때문에 톰캣 서버의 server.xml에서 다음 코드를 찾아 URIEncoding="UTF-8"을 추가하여 해결해야 한다.

그림 8 (URL 구성 요소의 명칭)
그림 9 (Servers 프로젝트의 톰캣이 설치된 폴더의 server.xml)

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

이렇게 편집한다. 이클립스는 톰캣 실행 환경을 별도의 프로젝트로 관리한다. Servers 프로젝트를 살펴보면 각 톰캣 실행 환경마다 서버 설정 파일이 있음을 확인할 수 있다. 서블릿 컨테이너마다 설정 방법이 다르니 반드시 제품 매뉴얼을 확인해야 한다.

 

만약 톰캣 서버를 설치 폴더에서 독립적으로 실행하는 경우 톰캣이 설치된 폴더에서 conf/server.xml파일을 편집한다.

그림 10 (server.xml파일 위치)

server.xml파일 위치 : C:\javaide\server\apache-tomcat-8.5.73\conf\server.xml

 

참고도서 : https://freelec.co.kr/book/1674/

 

[열혈강의] 자바 웹 개발 워크북

[열혈강의] 자바 웹 개발 워크북

freelec.co.kr

댓글