본문 바로가기
백엔드/웹 개발

필터, 정규표현식

by study_yeon 2023. 8. 3.

2023.07.26 수업


● 필터

- HTTP 요청과 응답을 변경할 수 있는 재사용 가능한 코드
- 어플리케이션의 모든 HTTP Request에 대해서 감지를 할 수 있는 기능
- 이름 그대로 필터의 역할

 

참고용

2023.06.29 - [백엔드/웹 개발] - 로그인, 로그아웃 구현하기(필터)

 

로그인, 로그아웃 구현하기(필터)

2023.06.28수업 - 교재 : 자바 웹 개발 워크북 ※ 브라우저 개발자도구(f12) Network : 현재 접속된 주소의 진행사항 Application : 쿠키, 브라우저에 저장된 내용 Element : 홈페이지 요소(html, css 등을 보여줌)

dustj0824.tistory.com


▷ 다이나믹웹프로젝트 만들기
프로젝트명 : FilterEncodingExam

▷ 폼 작성용 jsp 파일 만들기

- 화면 구현 파일

- 약식 모델2 방식

경로 : FilterEncodingExam/src/main/webapp
파일명 : index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="${ pageContext.request.contextPath }/css/styles.css" rel="stylesheet" type="text/css">
</head>
<body>
	<%-- 약식 모델2 방식 (서블릿, jsp) --%>
	<div class="encoding">
		<form action="encoding" method="post">
			이름<input type="text" name="name" value="홍길동"> <br />
			나이<input type="text" name="age" value="35"> <br />
			장소<input type="text" name="place" value="한양"> <br />
			<input type="submit" />
		</form>
	</div>
	<script src="${ pageContext.request.contextPath }/js/index.js"></script>
</body>
</html>

* pageContext.request.contextPath
- 상대경로, 현재 위치를 기준으로 목표로하는 위치, 현재 위치의 문서를 기준으로 경로 인식
- contextPath가 변경되어도 소스 수정없이 적용 가능
- EL표현식을 통해 간편하게 사용 
* pageContext : 웹 컨테이너가 JSP실행시 자동으로 생성하여 제공하는 내장객체

[다른 방법1]
컨텍스트 이름(test or /(root))을 직접 입력하는 방법

<a href="/test/test01/memberForm.jsp">

[다른 방법2]
getContext() 메서드를 이용해 컨텍스트 이름을 가져오는 방법

<a href="<%=reqeust.getContextPath() %>/test01/memberForm.jsp>

▷ CSS
경로 : FilterEncodingExam/src/main/webapp
파일명 : css/styles.css (폴더까지 만들기)

- form(jsp파일)의 디자인

- 클래스이름을 활용하여 css 하기

@charset "UTF-8";

/* 한글 테스트용 */

.encoding {
	text-align: center;
	font-size: 20px;
	color: red;
	border: 5px solid blue;
}

▷ 자바스크립트
경로 : FilterEncodingExam/src/main/webapp
파일명 : js/index.js (폴더까지 만들기)

- 한글이 잘 나오는지 검사용

/* 한글 테스트 */

for(let i = 0; i < 10; i++) {
	document.write(`${i} <= ${ (i + 1) }입니다. <br />`)
}

▷ 서블릿
경로 : /FilterEncodingExam/src/main/java
패키지명 : apple.orange.servlet
클래스명 : EncodingServlet
- doPost만 사용

- JSP의 form을 통해 입력받은 자료를 읽어옴

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;

/**
 * Servlet implementation class EncodingServlet
 */
@WebServlet("/encoding")
public class EncodingServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		PrintWriter out = res.getWriter();
		
		String name = req.getParameter("name");
		String age = req.getParameter("age");
		String place = req.getParameter("place");
		
		// echo 출력
		out.print("이름은 " + name + "<br />");
		out.print("나이는 " + age + "<br />");
		out.print("장소는 " + place + "<br />");
		out.print("<hr>");
	}

}

▷ 실행 : run on server 


-> 한글이 깨져보임


* Filter Life Cycle(생명주기)
init(최초 한번 실행) -> doFilter -> destory(WAS 종료 전 처리)

 

▷한글 깨짐현상을 해결하기 위한 필터 만들기

경로 : /FilterEncodingExam/src/main/java
패키지 : apple.orange.filter
클래스 : EncodingFilter

- 모든 url에 대하여 적용 ( /* )

- EncodingFilter extends HttpFilter(클래스 상속) implements Filter (인터페이스 상속)
- doFilter활용

 

* request.setCharacterEncoding("utf-8");
- 들어오는 파라미터를 UTF-8로 해석한다
- 폼 태그에서 입력한 값을 전송할 때는 GET방식과 POST방식으로 나뉘는데 POST방식으로 보내는 값이 '한글'일 경우 깨지지 않게 전달하기 위해 사용하는 것이다. 

* response.setCharacterEncoding("utf-8");
- 서블릿이 HTML 파일을 만들 때 UTF-8 로 쓰기
- 웹 브라우저에게 한글이 포함되어 있으니 잘 표시하라고 알려주는 역할

* response.setContentType("text/html;charset=utf-8");
- HTML이 UTF-8 형식이라는 것을 브라우저에게 알리는 것

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.FilterConfig;
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;

// 요청이 들어오면 그 요청을 서블릿이 처리하기 전 또는 후에 마지막 추가처리를 하는 기능
// 웹브라우저 요청 > 필터 > 서블릿 > JSP뷰 > (정리)필터
@WebFilter("/*")
public class EncodingFilter extends HttpFilter implements Filter {   

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		// 공통필터 적용 시작
		// 요청객체로부터 읽어오는 데이터를 무조건 UTF-8(유니코드)로 해석해라
		request.setCharacterEncoding("UTF-8");
		// 브라우저로 응답할때 기본 데이터 쓰기 절정을 UTF-8로 설정해라
		// 이후 출력은 모두 UTF-8로 해석이 됨
		response.setCharacterEncoding("UTF-8");
		// 이후부터 모든 HTML관련 파일들을 UTF-8로 변환
		// CSS, JS는 마임파일 타입이 text/css text/javascript이므로 문제 발생
		// 그래서 한글설정을 하면 css, js파일들이 일부 실행안되는 문제 발생
		// 아래의 방식으로 변경하여 해결
		response.setContentType("text/html; charset: UTF-8");
		
		// 위의 3가지 설정으로 필터 적용하기
		// pass the request along the filter chain
		chain.doFilter(request, response);
		System.out.println("필터적용 완료");
	}

}

▷ 필터 적용 후 실행


* 필터를 적용하여 실행 후 css를 수정하면 반영이 안됨 

기존에 설정한 css로 보여짐


res.setContentType("text/html; charset: UTF-8"); 때문
그렇다고 작성하지 않으면 한글이 깨짐

 

▷ css 반영 안됨 문제 해결을 위해 필터에 내용 추가

- 정규표현식 활용하기

- pattern객체에 검색할 원본문자열에서 제거하고 싶은 또는 포함하고 있는지를 검사하고 있는 비교할 문자패턴을 등록

- 필터처리를 위한 요청객체와 응답객체를 웹프로토콜로 다운캐스팅

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.FilterConfig;
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;

/**
 * Servlet Filter implementation class EncodingFilter
 */
// 요청이 들어오면 그 요청을 서블릿이 처리하기 전 또는 후에 마지막 추가처리를 하는 기능
// 웹브라우저 요청 > 필터 > 서블릿 > JSP뷰 > (정리)필터
@WebFilter("/*")
public class EncodingFilter extends HttpFilter implements Filter {   
 
	/* css 반영 안됨 문제 해결 */
	// Pattern : 자바에서 정규표현식 객체
	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 {
		/* css 반영 안됨 문제 해결 */
		// 필터처리를 위한 요청객체와 응답객체를 웹프로토콜로 다운캐스팅
		// 현재 우리가 다루는 프로토콜은 웹관련 프로토콜이므로 굳이 객체의 타입을 조사하여
		// 자식클래스 타입으로 변환할 필요는 없다
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;
		
		// req(웹 요청객체), res(웹 응답객체)
		// getRequestURI() : 웹 브라우저에서 요청한 요청주소 중에서 
		// 프로토콜, 서버주소, 포트번호를 뺀 요청처리에 관련한 나머지 주소
		// http://localhost:8080/api/index.jsp라면 
		// 프로토콜 http:// 제거
		// localhost:8080 서버주소 제거
		// /api/index.jsp 요청 uri가 된다(getRequestURI)
		// index.jsp : 실제 실행하는 앱이름 = 요청 애플리케이션 컨텍스트(request.getContextPath)
		// 컨텍스트만 남기기 위해서
		String path = req.getRequestURI().substring(req.getContextPath()
				.length()).replaceAll("[/]+$", "");
		
		// 공통필터 적용 시작
		// 요청객체로부터 읽어오는 데이터를 무조건 UTF-8(유니코드)로 해석해라
		request.setCharacterEncoding("UTF-8");
		// 브라우저로 응답할때 기본 데이터 쓰기 절정을 UTF-8로 설정해라
		// 이후 출력은 모두 UTF-8로 해석이 됨
		response.setCharacterEncoding("UTF-8");
		// 이후부터 모든 HTML관련 파일들을 UTF-8로 변환
		// CSS, JS는 마임파일 타입이 text/css text/javascript이므로 문제 발생
		// 그래서 한글설정을 하면 css, js파일들이 일부 실행안되는 문제 발생
		// 아래의 방식으로 변경하여 해결
		// response.setContentType("text/html; charset: UTF-8");
		// 공통필터 적용 끝
		
		// 허용불가경로 포함여부 판별
		Matcher matcher = excludeUrls.matcher(path);
		boolean isPathExcluded = matcher.find();
		
		// 허용불가 경로가 아니면
		if(!isPathExcluded) {
			response.setContentType("text/html; charset: UTF-8");
			System.out.println("허용불가 경로 아님" + path);
			
		} else {
			
		}
		
		// 위의 3가지 설정으로 필터 적용하기
		// pass the request along the filter chain
		chain.doFilter(request, response);
		System.out.println("필터적용 완료");
	}

}

※ Pattern 활용: 자바에서 정규표현식 객체
(css|js|images|ckeditor)
Pattern.compile() : 비교할 목록리스트를 만들어라
"^.* : '\n' 개행문자를 제외한 모든 문자들

[정규표현식]
^ : 문자열 시작
: '\n' 개행문자를 뺀 모든 문자들
* : 앞의 문자패턴을 여러번 반복해라
(...) : ()안의 내용을 그룹으로 묶음 분리, list의 효과
: or, ()안의 내용들 중에 하나
$ : 앞의 그룹 문자들로 끝나는지
CASE_INSENSITIVE 대소문자 구분하지 않음
시작/.../끝 : 시작패턴(^.*), 끝의 패턴(.*$)을 포함하는가? 

※ 다운캐스팅
req(웹 요청객체), res(웹 응답객체)
getRequestURI() : 웹 브라우저에서 요청한 요청주소 중에서 
프로토콜, 서버주소, 포트번호를 뺀 요청처리에 관련한 나머지 주소
http://localhost:8080/api/index.jsp라면 
프로토콜 http:// 제거,
localhost:8080 서버주소 제거,
/api/index.jsp 요청 uri가 된다(getRequestURI)
index.jsp : 실제 실행하는 앱이름 = 요청 애플리케이션 컨텍스트(request.getContextPath)

* replaceAll("[/]+$", "")
-> "[/]+$"패턴을 "" 공백으로 변경해라

[정규표현식]
...$ : ...단어로 끝나는가(문장의 끝)
^... : ...단어로 시작하는가(문장의 시작)
[...] : []안의 ...문자가 어떤 것이든 OK
* : 0부터 많음, 문자 또는 숫자 등의 수가 제한 없음
+ : 1부터 많음, 문자 또는 숫자 등의 수가 제한 없음 
[/]+$ : 문자열의 끝에 '/'인 문자를 포함하면 

▷ css 변경 후 실행

- 실행중인 서버를 종료하고 변경 내용 저장하여 재실행하기

- 재실행 후 css 변경하고 저장하면 바로 적용이 됨

@charset "UTF-8";

.encoding {
	text-align: center;
	font-size: 20px;
	color:  pink;
	border: 1px solid grey;
}

 

 

 


추후 스프링 프로젝트를 진행하며 한글깨짐 현상을 해결하기 위해 필터를 만들었을때

css 파일적용이 안되는 경우가 있어 그것을 해결하기 위한 코드를 배운 것인데  

Window > Preferences 설정 을 활용해도 되고, 

해당 filter를 매핑할 때 모든 URL에 대해 인코딩될 수 있도록 /*와 같이 url-pattern을 설정 해주는 방법도 있는 것 같다

수업의 내용은 지금으로서는 이해하기 너무 어려우니 정규 표현식만 얻어가자.