해당 포스팅의 목차는 다음과 같다
1. 배경지식
1) xml과 @(어노테이션)
2) 초기화 매개변수
2. 리스너
1) When?_언제 사용되는가
2) 크롤링 실습
3. 필터
1) When?_언제 사용되는가
2) 필터의 동작과정
3) 인코딩 실습
1. 배경지식
servlet과 filter는 특정한 상황에서 사용되는 특수한 형태의 servlet이라고 알려져있다. 자세히 알아가기 전에 xml파일과 @에 대한 내용을 파악할 필요가 있다.
1) xml과 @(어노테이션)
① XML
상황에 대한 설정정보, 환경설정정보 등을 저장하여 사용하는 파일이다. 어노테이션 개념이 생겨나기 전, 서블릿 컨테이너의 설정정보를 XML파일로 관리하였다.
톰캣의 경우 서블릿컨테이너에 대한 설정정보를 아래의 경로에 있는 XML파일을 수정, 관리하여 작성한다.
apache-tomcat-9.0.58-windows-x64\apache-tomcat-9.0.58\webapps\ROOT\WEB-INF
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<display-name>Welcome to Tomcat</display-name>
<description>
Welcome to Tomcat
</description>
</web-app>
② @(어노테이션)
이 개념을 통해 설정정보를 자동으로 생성 및 관리되도록 하여, 개발자들이 .xml파일(환경설정정보파일)을 직접 관리해야하는 부담을 줄여준다. 자바코드로 확인할 수 있어 로직과 설정정보를 한 눈에 볼 수 있으며, 응집도 또한 높다.
XML 방식과 어노테이션 방식의 가장 큰 차이라면, 전자가 프로젝트 전체의 컴포넌트와 의존 관계를 한 눈에 볼 수 있다는 장점이 있고, 후자는 보다 간편한 설정이 가능하다고 한다.
package test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//url패턴이 *.a로 끝나는 경우, 혹은 *.b로 끝나는 경우에 해당 서블릿파일을 수행하도록 하는 어노테이션
@WebServlet(urlPatterns= {"*.a", "*.b"})
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public TestServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
?
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
2) 초기화 매개변수
웹 어플리케이션을 구동시키는 서블릿 컨테이너가 최초로 로딩될때 적재되는 정보이다. 이 정보들은 웹 어플리케이션 전반에 활용되는 값들을 설정할때 사용된다. 해당 개념을 사용하면, 하드코딩을 방지하여 유지보수에 용이해진다.
사용예시) DB관련 환경설정정보, 파일 입출력시의 해당 파일 위치정보,...등
아래의 코드를 통해 초기화 매개변수를 설정하고 해당 변수를 화면에 조회해보았다.
package test;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class TestServlet
*/
@WebServlet(urlPatterns= {"*.a", "*.b"}, initParams= {@WebInitParam(name="uname1", value="timo"),@WebInitParam(name="uname2", value="ari")})//여러개를 받아올 수도 있다.
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public TestServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out=response.getWriter();
response.setCharacterEncoding("text/html; charset=UTF-8");
out.println("<html><body>");
out.println("uname1: "+getInitParameter("uname1")+"<br>");
out.println("uname2: "+getInitParameter("uname2")+"<br>");
out.println("</body></html>");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
2. 리스너
1) When?_언제 사용되는가
① 샘플데이터(초기 데이터) 확보
리스너는 컨테이너의 생명주기를 모니터링(감지)할 수 있으므로, 이 점을 활용하여 컨테이너 최초 동작시 초기데이터를 확보할 수 있도록 한다.
② 특정 이벤트에 대해 반응하는 기능을 구현
객체들에 대해 각종 다양한 상황 또한 모니터링이 가능하다. 이 점을 활용하여 특정 이벤트에 대해 반응하는 기능을 구현할 수 있다.
2) 샘플데이터 확보
리스너를 활용하여 크롤링으로 샘플데이터를 확보하는 코드를 작성해보았다.
① 크롤링 로직
package controller;
import java.io.IOException;
import java.util.Iterator;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class Crawling {
public static String admin; //크롤링 데이터를 담을 변수
public static void start() { //
final String url="https://comic.naver.com/index";
Document doc=null;
try {
doc=Jsoup.connect(url).get();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Elements eles=doc.select("div.genreRecomBox > h3.titleMain > a > span.Ntxt_genre_webtoon");
Iterator<Element> itr=eles.iterator();
while(itr.hasNext()) {
admin=itr.next().text();
/////System.out.println("로그: Crawling: "+itr.next().text()); "장르별 추천웹툰"
}
}
}
Crawling객체를 통해 start( )메서드를 수행하게 되면 웹 크롤링한 데이터를 adim이라는 변수에 저장하는 작업을 진행하게 된다. 이때 각 변수와 메서드는 재사용 목적이 없기에 static(객체와 무관하게)을 선언하여 활용한다.
② 리스너 파일
파일 생성시 파일명 입력 후 NEXT를 통해 다음 설정페이지로 이동하게 되면 아래와 같은 창을 마주할 수 있다.
자세히 확인해보면 단락별로 ServletContext, session, request의 상황에 관하여 특정한 상황에 대해 감지 및 설정할 수 있도록 설정창을 통해 지정할 수 있게 된다. 크롤링같은 경우는 서블릿컨테이너 최초 동작시 1번만 수행할것이기 때문에 형광펜으로 칠한 부분, 서블릿컨테이너의 생명주기(시작과 끝)만을 선택하여 진행하게 되고, 물론 상황에 대해서는 다중선택이 가능하다.
package controller;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* Application Lifecycle Listener implementation class CrawlingListener
*
*/
@WebListener
public class CrawlingListener implements ServletContextListener {
/**
* Default constructor.
*/
public CrawlingListener() {
// TODO Auto-generated constructor stub
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
}
//서블릿컨테이너 최초 동작시 작동할 메서드
public void contextInitialized(ServletContextEvent sce) {
Crawling.start();
System.out.println("로그: 리스너 클래스: 크롤링 완료");
ServletContext sc=sce.getServletContext();
sc.setAttribute("admin", Crawling.admin);
}
}
서블릿컨테이너 최초 동작시 start( )메서드를 수행하고, 이를 통해 생성된 admin변수의 값을 ServletContext에 setAttribute한다.
서블릿컨텍스트란 무엇인지 더 자세하게 알고싶다면 아래의 포스팅을 통해 확인할 수 있다.
https://java117.tistory.com/18
③ view에 내용 출력
EL식을 활용하여 html혹은 jsp파일에서 ${admin}을 선언한다면 쉽게 크롤링한 데이터를 view에 출력할 수 있게 된다.
3. 필터
1) When?_언제 사용되는가
① 인증, 허가, 인가
② 로깅처리
③ 국제화(다국어처리, UTF-8) 언어처리
등과 같은 경우에 보편적으로 사용된다.
2) 필터의 동작과정
사용자의 요청정보를 "탈취"해서 작업하므로 request, response객체가 초기화되지 않고 데이터가 유지된 채 가공된다. 이때 필터를 부분별로 적용할 수 있으며, 그렇기 때문에 필터간의 우선순위를 잘 생각해서 적용해야한다.
컨테이너가 구동되면 가장 먼저 @WebFilter()을 확인하고, init( )메서드를 수행함에 따라 filter 객체가 생성된다. 이후 사용자 요청에 따라 필터가 doFilter( )를 수행하게 되는데 doFilter메서드가 사실상 필터의 실질적 기능이라고 할 수 있다.
3) 인코딩 실습
① filter파일 생성
파일 생성시 파일명 작성 후 NEXT버튼을 통해 상세 설정을 진행할 수 있다. 표시된 부분을 보면 자동으로 디폴트되어있는 url패턴을 삭제하고, 본인 프로젝트에서 사용되는 url패턴을 작성한다. 이때 사용되는 패턴이 여러개인 경우 모두 작성하여 프로그램 수행시 모든 경로에 인코딩이 진행되도록 한다.
아래 코드의 주석을 통해 내용을 파악할 수 있다.
package test;
import java.io.IOException;
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;
//url패턴 배열로 지정하였음, 프로젝트에서 사용되는 모든 url의 패턴을 저장하는게 용이
@WebFilter(urlPatterns={"*.jsp","*.do"})
public class TestFilter extends HttpFilter implements Filter {
// 인코딩 설정을 위한 필터 클래스!!!
//인코딩 변수 선언
private String encoding;
public TestFilter() {
super();
// TODO Auto-generated constructor stub
}
//서블릿 컨테이너 종료시
public void destroy() {
// TODO Auto-generated method stub
}
//필터의 본체! 실질적 기능을 수행
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
System.out.println("필터수행됨");
chain.doFilter(request, response);//다음필터로 이동하도록하는 명령어
}
//서블릿 컨테이너 동작시 수행 메서드
public void init(FilterConfig fConfig) throws ServletException {
this.encoding=fConfig.getServletContext().getInitParameter("encoding");
System.out.println("필터생성됨");
}
}
② XML파일 생성
xml파일을 통해 초기화 매개변수를 사용할 예정이다.
물론 위의 코드에서 this.encoding=fCongig.getInitParameter("UTF-8");로 바로 진행할 수 있지만, 이런 코드가 바로 하드코딩이기 때문에 응집도를 높히기 위해 초기화 매개변수를 사용한다.
서블릿컨테이너의 종류와 버전에 따라 다르겠지만, 본인이 사용중인 톰캣 9버전의 경우는 WEB-INF폴더의 하위에 본래 있어야할 XML파일이 표시되지 않기 때문에 새로 생성하였으며, 혹여 xml파일이 있는 경우에는 그 파일을 수정하여 사용하면 된다.
필터에서 사용하려는 encoding이라는 이름의 변수에 UTF-8이라는 값을 입력하는 코드이다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<context-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
</web-app>
③ 결과
NewFile.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>
</head>
<body>
<form action="NewFile1.jsp" method="post">
<input type="text" name="username">
<input type="submit" value="필터">
</form>
</body>
</html>
form을 통해 글을 입력하면 해당 입력이 다른 jsp파일로 넘어가게 되고, 한글 입력일 경우 인코딩을 위해 페이지지시어 하단에 <% request.setCharacterEncoding("UTF-8"); %>코드를 작성하여 인코딩 설정을 진행했어야하지만, 필터파일을 통해 서블릿컨테이너가 동작할때마다 인코딩이 진행될 것이기 때문에 생략할 수 있다.
NewFile1.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>
</head>
<body>
<h1>${param.username}</h1>
</body>
</html>
'JSP' 카테고리의 다른 글
[게시판 Ver.2] 게시글과 댓글의 화면 출력 (0) | 2022.03.14 |
---|---|
[JDBC] MVC나누기 3_게시판+FC,필터,리스너 (0) | 2022.03.11 |
[controller업그레이드] 서블릿 활용 (0) | 2022.03.08 |
[View업그레이드] 커스텀 태그 (0) | 2022.03.07 |
[JDBC] MVC나누기_2 : 게시판+로그인 (0) | 2022.03.06 |