▪︎ Dynamic Web Project 생성 : FilterEncodingExam
▪︎ index.jsp 생성
- 테스트 시, value 속성을 이용해 초기값 자동으로 설정하기 )
- CSS 및 자바스크립트의 주소 : EL 엔진 이용
<link href="${ pageContext.request.contextPath }/css/styles.css" rel="stylesheet" type="text/css" >
• pageContext.request.contextPath : 웹에서 상대적인 경로를 나타냄 ( 현재 위치의 문서를 기준으로 경로 인식 )
• pageContext 객체 : javax.servlet.jsp.PageContext 클래스를 상속해 웹 컨테이너가 JSP 실행 시 자동으로 생성해서 제공하는 내장 객체
• javax.servlet.http.HttpServletRequest 객체가 제공하는 정보를 활용해 정보 얻을 수 있음
▪︎ styles.css 및 index.js 생성
→ 생성 결과 (Package Explorer창)
▪︎ EncodingServlet 생성
package apple.orange.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/encoding")
public class EncodingServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
String name = request.getParameter("name");
String age = request.getParameter("age");
String place = request.getParameter("place");
// echo 출력
out.print("이름은 " + name + "<br />");
out.print("나이는 " + age + "<br />");
out.print("장소는 " + place + "<br />");
out.print("<hr />");
}
}
• 문자열로 입출력할 계획 - 출력 스트림 생성 : PrintWriter ( 응답 객체로부터 얻음 )
• 요청객체로부터 데이터 얻어오기 : getParameter( ) 메서드 이용
• 받은 데이터 그대로 전송 : echo 출력
▪︎ 프로젝트 실행 : Run As - Run On Server
• 제출 클릭 시, 한글이 깨지는 현상 발생
→ 아래의 필터 적용 후 한글이 깨지지 않음 (해결)
다만, css 수정 후 다시 재실행할 경우 수정된 내용이 반영이 되지 않음
( 페이지 소스 보기를 통해서도 수정된 내용이 반영 안됨 )
▪︎ EncodingFilter에서 정규표현식을 이용해 문제 해결
▪︎ EncodingFilter 생성
package apple.orange.filter;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebFilter("/*")
// * 요청이 들어오면, 그 요청을 요청 서블릿이 처리하기 전 또는 서블릿 처리 후에
// 마지막 추가 처리를 하는 기능
// * 웹 브라우저 요청 -> 필터 -> 서블릿 -> JSP 뷰 -> 정리 필터
// * 루트 밑의 모든 경로로 설정 -> 한글 처리
public class EncodingFilter extends HttpFilter implements Filter {
// * Pattern : 자바에서 정규표현식 객체
// pattern 객체에 검색할 원본문자열에서 제거하고 싶은 또는 포함하고 싶은지를 검사하고 있는 비교할
// 문자패턴을 등록함
// * Pattern.compile() : 비교할 목록 리스트를 만드는 역할
// "^.* : '\n' 개행문자를 제외한 모든 문자들
// ^ : 문자열의 시작을 의미
// . : '\n' 개행문자를 뺀 모든 문자
// * : 앞의 문자패턴을 여러 번 반복
// (...) : () 안의 내용을 그룹으로 묶음 분리 (리스트와 같은 역할)
// | : or, () 안의 내용들 중에 하나
// $ : 앞의 그룹문자들로 끝나는지
// CASE_INSENSITIVE : 대소문자 구분하지 않음
private static final Pattern excludeUrls = Pattern.compile(
"^.*/(css|js|images|ckeditor)/.*$",
Pattern.CASE_INSENSITIVE);
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// * 필터처리를 위한 요청객체와 응답객체를 웹 프로토콜로 다운캐스팅
// ServletRequest <- HttpServletRequest
// 현재 우리가 다루는 프로토콜은 웹 관련 프로토콜이므로,
// 굳이 객체의 타입을 조사해서 자식 클래스 타입으로 변환할 필요는 없음
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String path = req.getRequestURI().substring(req.getContextPath().length())
.replaceAll("[/]+$", "");
// req : 웹 요청 객체 | res : 웹 응답 객체
// getRequestURI()
// : 웹 브라우저에서 요청한 요청주소 중에서 프로토콜, 서버주소 및 포트 번호를 뺀 나머지 주소
// → 웹 서버로 요청 시, 요청에 사용된 URL로부터 URI 값을 리턴
// 예 ) 'http://localhost:8080/api/index.jsp'에서
// 프로토콜 'http://' 제거, 서버주소 'localhost:8080' 제거 후
// 나머지 주소인 '/api/index.jsp'가 요청 URI 주소에 해당
// index.jsp : 실제 실행하는 앱 이름 = 요청 애플리케이션 컨텍스트 == request.getContextPath
// ...$ : ... 로 끝나는지, 즉 문장의 끝을 의미
// ^... : ... 로 시작하는지, 즉 문장의 시작을 의미
// [...] : [] 안의 ... 문자 어떤 것이든 가능
// * : 문자가 0번 이상 반복
// + : 문자가 1번 이상 반복
// [/]+$ : 문자열의 끝이 '/'인 문자를 포함하는 경우
// * req.getRequestURI().substring(req.getContextPath().length()).replaceAll("[/]+$", "")
// : URI 주소에서 문장의 끝이 '/'로 끝나는 경우, 요청 애플리케이션 컨텍스트의 길이만큼 대체
// -> 컨텍스트만 남게 됨 (index.jsp)
// * 공통 필터 적용
// 1) 요청객체로부터 읽어오는 데이터를 무조건 UTF-8(유니코드)로 해석해라
// 2) 나중에 브라우저로 응답할 때 기본 데이터 쓰기 설정을 UTF-8(유니코드)로 설정해라
// -> 이후 출력은 모두 UTF-8로 해석이 됨
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
// * 이후부터 모든 HTML 관련 파일들을 UTF-8로 변환하라
// 다만, CSS 및 JS의 경우, 마임 파일 타입이 text/css, text/javascript이므로 문제 발생
// 그래서 한글 설정을 하면 CSS 및 JS 파일들이 일부 실행되지 않는 문제가 생김
//response.setContentType("text/html; charset: UTF-8");
// 현재 CSS 수정 시 반영이 안되는 문제의 원인
// -> 이 부분을 주석처리 시, 한글이 깨지는 현상 다시 발생
// response.setContentType()
// 허용불가 경로 포함여부 판별
Matcher matcher = excludeUrls.matcher( path );
boolean isPathExcluded = matcher.find();
// 허용불가 경로가 아니면
if(!isPathExcluded) {
response.setContentType("text/html; charset: UTF-8");
System.out.println("허용불가 경로 아님 : " + path);
} else {
}
// 위의 설정으로 필터를 적용하라는 의미
chain.doFilter(request, response);
System.out.println("필터 적용 완료!");
}
}