열심히 끝까지
디바이스 융합 자바(Java) day48 - 리스너(Listener)(초기화 매개변수),필터(Filter) 본문
디바이스 융합 자바(Java) day48 - 리스너(Listener)(초기화 매개변수),필터(Filter)
노유림 2022. 8. 18. 17:31[오늘 수업]
V : 커스텀태그, JSTL, EL식
M : JDBC, MYSQL, ORACLE, TRANJECTION, 리스너
C : 필터
>> 오늘의 수업 : 리스너, 필터
- 서블릿 상위 클래스 아래에 리스너, 필터 존재
- 각자 모델과 컨트롤러에서 사용(주로 활용되는 공간)
[리스너] : 초기화 매개변수(키워드)
- JSTL에서 사용한 경험 존재
- 현업, 포폴에서 많이 등장하는 개념은 아니라서 설명을 안했지만
다른 사람의 소스코드에도 나오기 때문에 익혀 놓을 것
>> 질문도 나왔고해서 포함 시켜서 설명
- 조심해야 하는 단어 : "초기화 매개변수"
>> 초기화 매개변수
: 프로그램을 동작을 시키거나 수행을 시킬 때, 꼭 필요한 정보가 존재(ex ) url, id, pw, db...(경로))
일반적으로는 소스코드에 "하드코딩"을 해왔음
그런데 이런 정보들을 프로젝트 중간에 쉽게 변경될 수 있음
이런 "정보"들을 별도로 "환경설정 파일(.xml)"에 보관하는 것이 일반적
"환경설정 파일에 담긴 정보 == 초기화 매개변수"
: 하드코딩
ex )
int N=5; // 이 자리에 데이터의 개수를 입력
int[] data=new int[N];
for(int i=0; i<data.length; i++){
syso(data[i]);
}
: 보관은 다음과 같이 진행
<init-param></init-param> -> ServletConfig
: 해당 서블릿에서 사용 가능
<context-param></context-param> -> ServletContext
: 동일한 웹 어플리케이션 내에서 모든 서블릿에서 사용 가능
: 내부에
<param-name>(이름)</param-name>
<param-value>(값)</param-value>
존재
( 블로그나 교재에 잘 안나오는 내용, 꼭 기억할 것 )
★ .xml -> @ (어노테이션,애너테이션)
: .xml파일을 어노테이션으로 바꾸는 일이 잦아짐
: 대부분이 .xml의 상위버전인 어노테이션으로 바꾸려는 것
>> 과거에 설정파일은 xml에 들어잇엇는데 스프링이라는 웹 프레임워크 등장
여기에서 채택하는 것이 어노테이션
그래서 xml을 어노테이션으로 바꾸는 작업을 자주 함
그걸 신입한테 시킨다고..ㅋㅋㅋ(작대기)
: 컴파일을 시도할 때,
> 어떤 어노테이션(오버라이딩)이 있었는지 별도로 기억
> 특정 기능을 수행할 때,
그에 해당하는 어노테이션이 있는지 가장 먼저 확인(=동적바인딩)
or
특정 순간에 반응(모니터링, 감지)하는 어노테이션 존재,
해당 순간에 기능을 수행
>> WEB-INF 하위에 web.xml 파일 생성(꼭 그렇게 해야 함)
: web.xml 은 WEB-INF 폴더 하위에 존재
: 서버(tomcat : 톰캣)가 시작될 때 참조하는 환경설정 파일
: 최상위 태그로 "<web-app></web-app>" 사용
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<!-- 기본적인 값 명시 -->
<context-param>
<param-name>name</param-name>
<param-value>timo</param-value>
</context-param>
<context-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
<!-- 인코딩을 UTF-8이라고 명시 / 인코딩 정보 입력 가능 -->
</context-param>
<!-- errorPage="error/error(이 부분 이름 바뀌면서 명시).jsp"라고 명시 했었음 -->
<!-- 초기화 매개변수에서는 이렇게 명시 -->
<error-page> <!-- 고쳐야하는 에러가 발생 시, 출력하는 방법 -->
<exception-type>java.lang.Throwable</exception-type>
<location>/error/error.jsp</location>
</error-page>
<error-page> <!-- 없는 페이지, 삭제된 게시글 등... -->
<exception-type>404</exception-type>
<location>/error/error404.jsp</location>
</error-page>
</web-app>
>> 초기설정------------------------------------------------
package test;
import java.io.IOException;
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 TestServlet2
*/
@WebServlet("/apple")
public class TestServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public TestServlet2() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("apple");
}
/**
* @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);
}
}
>> 따로 설정--------------------------------------------------
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={"/TestServlet"}, initParams={@WebInitParam(name="msg1",value="HELLO"),@WebInitParam(name="msg2",value=":D")})
// URL DEFAULT 설정 제거하고 직접 설정
// (urlPatterns={"/TestServlet"}, initParams={})
// initParam에 대한 이야기 > 이름, 변수를 저장 가능, 여러 개 가능
// ("/TestServlet") 단축되어 있음(Default 값)
// URL 매핑 설정이란?
// 브라우저에서 어떤 URL 요청에 대해 해당 서블릿을 서비스할지를 결정
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 {
// TODO Auto-generated method stub
// response.getWriter().append("test");
doPost(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 글자 깨짐을 방지하기 위한 용도
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<HTML>");
out.println("<BODY>");
// 서블릿 초기화 매개변수 -> @(어노테이션)
out.println("<H1>초기화 매개변수 - @(어노테이션 사용)</H1>");
out.println("msg1 : " + getInitParameter("msg1")+"<BR>");
out.println("msg2 : " + getInitParameter("msg2"));
out.println("<HR>");
// 웹 어플리케이션 초기화 매개변수 -> web.xml
out.println("name : " + getServletContext().getInitParameter("name") + "<BR>");
out.println("encoding : " + getServletContext().getInitParameter("encoding"));
out.println("</BODY>");
out.println("</HTML>");
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>초기화 매개변수 설정</title>
</head>
<body>
<!-- Servlet에서 꺼내보기 -->
name : <%=getServletContext().getInitParameter("name") %><br>
<!-- 어플리케이션에서 꺼내보기 -->
encoding : <%=application.getInitParameter("encoding") %>
</body>
</html>
>> 본격적인 [리스너]
>> 리스너
: 특수한 형태의 서블릿
: 특정 동작을 모니터링(감지)해서 기능을 자동 호출
: 어떤 동작을 감지할 지 선택할 수 있음
>> 초기화 매개변수와 엮겨서 사용
※ 전체 흐름
1. 톰캣 서버 시작
2. web.xml 참조
+ 프로젝트에 작성되어 있는 @(어노테이션) 스캔
3. @WebListener(리스너 클래스)가 발견되면
어떤 동작에 대해 해당 리스너 클래스를 자동호출해야하는지 별도로 기억
1. xxx.jsp를 요청
2. 톰캣 시작됨
3. 리스너가 모니터링 하다가 자동 호출됨 -> xxx.jsp 요청 완료(브라우저에 출력)
1. Servlet context
1-1. Lifecycle : 웹 서버 어플리케이션 컨텍스트가 시작되거나 소멸되는 것을 감지
1-2. Change to attribute : 어플리케이션 스코프에 속성 추가, 변경 설정 가능
2. HTTP session
2-1 Lifecycle : 세션이 생성됬니? 장바구니 새로 만들어!
2-2 Change to attribute : session 스코프에 속성 변경 설정 가능
3. Servlet request
3-1 Lifecycle
3-2 Change to attribute
package test;
public class Member {
private String name;
private int score;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public Member(String name, int score) {
this.name=name;
this.score=score;
}
}
package test;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* Application Lifecycle Listener implementation class TestListener
*
*/
@WebListener
public class TestListener implements ServletContextListener {
/**
* Default constructor.
*/
public TestListener() {
// TODO Auto-generated constructor stub
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
}
/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
public void contextInitialized(ServletContextEvent sce) {
ServletContext sc=sce.getServletContext();
Member member=new Member("홍길동",100);
sc.setAttribute("member", member);
// sc.setAttribute("객체명", 객체);
System.out.println("TestListener : contextInitialized() : 톰캣 시작이 감지됨");
}
}
<%@ 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>
${member.name}학생 : ${member.score} 점
</body>
</html>
★★★우리들의 포트폴리오에서는...★★★
- 샘플 데이터
- 웹 크롤링
>> 크롤링해오기..?
class A{ // 웹 크롤링
public ArrayList<VO> funcA(){
}
}
class Listener{
A a = new A();
ArrayList<VO> datas=a.funcA();
DAO dao = new DAO();
if(dao.funcB(datas)){
syso("성공");
}
else{
syso("실패");
}
}
class DAO{
public boolean funcB(ArrayList<VO> datas){
// DB에 크롤링한 데이터를 INSERT하는 로직
}
}
-> 1) 리스너 클래스의 메서드가 동작
=> 웹 크롤링 수행
=> DB에 저장
class A{ // 웹 크롤링
public ArrayList<VO> funcA(){
}
}
class Listener{
DAO dao=new DAO();
if(dao.funcC()){
// 크롤링 데이터가 이미 존재함
return;
}
A a=new A();
ArrayList<VO> datas=a.funcA();
if(dao.funcB(datas)){
syso("성공");
}
else{
syso("실패");
}
}
class DAO{
public boolean funcB(ArrayList<VO> datas){
// DB에 크롤링한 데이터를 INSERT하는 로직
// +) 혹시, 크롤링 데이터가 이미 있다면, false 반환
}
public boolean funcC(){
// 크롤링 데이터가 존재하는지안하는지 알려주는 메서드
}
}
1. Listener에 집어넣어서 Crawling
2. 애초에 funcB() 자체에 크롤링 데이터 유무를 확인하는 로직 존재
항상 좋은 코드는 없고 본인이 왜 그렇게 썼는지 이유를 설명할 수 있으면 ok!
[필터] : 정수기, 에어컨
- 특정 요청에만 반응하는 특수한 형태의 서블릿
- 기존의 요청정보를 탈취(뺏어옴)해서 자신의 작업을 처리하고(doFilter())
아무 일도 없었던 것 처럼 원래대로 요청정보를 다시 진행시킴
- 사용처
: 인증
인가
로깅
데이터 변환
인코딩
국제화(다국어 처리, 번역)에 사용
★★★우리들의 포트폴리오에서는...★★★
- C
- 인코딩 관려 설정
※ 필터 동작 순서
1. 웹서버(톰캣) 시작
2. 필터 클래스 init() 동작
3. 사용자가 서비스를 자유롭게 이용
4. 그러던 중에, 특정 요청을 수행하면,
5. 필터가 반응 : doFilter()
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;
/**
* Servlet Filter implementation class EncFilter
*/
@WebFilter("*.jsp")
public class EncFilter extends HttpFilter implements Filter {
private String encoding;
/**
* Default constructor.
*/
public EncFilter() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
// request.setCharacterEncoding("UTF-8");
// 하드코딩 : 잘 안바뀌는 부분은 하드코딩으로 해 놓기도 한다.(하지만 교육중이니..)
request.setCharacterEncoding(this.encoding);
// web.xml(환경설정파일)에 저장되어 있던 초기화 매개변수로 교체
System.out.println("doFilter() 동작 완료");
// pass the request along the filter chain
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
System.out.println("필터 클래스 최초 초기화 완료");
this.encoding=fConfig.getServletContext().getInitParameter("encoding");
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="NewFile2.jsp" method="post">
<input type="text" name="msg">
<input type="submit" value="확인">
</form>
</body>
</html>
<%@ 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>msg : ${param.msg}</h1>
<!-- param.msg로 안하고 msg로 하면 에러 안나고 null값으로만 들어감 - 놓치지 말 것! -->
</body>
</html>