79일차 Servlet Listener나머지에 Filter까지

쿠우·2022년 7월 18일
0

JDBC 생명주기 관리하는 Listener예제

-예제에서 알아볼 점
(1) contextInitialized , contextDestroyed 를 통해 자원의 생명주기를 이용한다는 점
보통 공유속성을 가진 해당 생명주기를 가진 자원객체의 생성과 해제를 리스너에다가 올림


@Log4j2

//@WebListener
public class ServletContextListenerImpl implements ServletContextListener {

	private static String key= "__SHARED__";


	public ServletContextListenerImpl() {
		log.trace("default constructor invoked.");
	}//default constructor

	@Override
    public void contextInitialized(ServletContextEvent e)  {  // 웹어플리케이션에 필요한 자원객체 생성
		log.trace("contextInitialized invoked.");
		// ServletContextEvent  이벤트 객체는 왜 전달 되었을까? 
		// getServletContext()를 통해  ServletContext 객체를 얻기 위해 
		
		ServletContext  sc =e.getServletContext();
		String driver =sc.getInitParameter("driver");
		String jdbcUrl = sc.getInitParameter("jdbcUrl");
		String user = sc.getInitParameter("user");
		String pass = sc.getInitParameter("pass");
		
		
		log.info("\t+ driver :{}"+ driver);
		log.info("\t+ jdbcUrl :{}"+jdbcUrl);
		log.info("\t+ user :{}"+user);
		log.info("\t+ pass :{}"+pass);
		
		
		Object source = e.getSource();
		log.info( "source: "+ source);
		
		// ServletContext 객체에 정보를 올려놓는다.
		sc.setAttribute(ServletContextListenerImpl.key, 1000);
		sc.setAttribute("driver", driver);
		sc.setAttribute("jdbcUrl", jdbcUrl);
		sc.setAttribute("user", user);
		sc.setAttribute("pass", pass);
		
    }// contextInitialized
	
	
	// 보통 공유속성을 가진 해당 생명주기를 가진 자원객체의 생성과 해제를 리스너에다가 올림 
	
	
	
	@Override
    public void contextDestroyed(ServletContextEvent e)  { // 사용했던 자원객체 해제
		log.trace("contextDestroyed invoked.");
		
		ServletContext  sc =e.getServletContext();
		
		sc.removeAttribute(ServletContextListenerImpl.key);
		sc.removeAttribute("driver");
		sc.removeAttribute("jdbcUrl");
		sc.removeAttribute("user");
		sc.removeAttribute("pass");
		
    }// contextDestroyed
}// end class

2. web.xml 에 어노테이션 안쓰고 등록하기

-공유 영역에다가 저장할 값들 넣어주고 Listener등록해주기

3. 공유 데이터 영역에 올라간 JDBC정보를 이용해 쿼리문 가공 후 출력

-알아본 점
(1)init 부분에서 연결정보를 받고 연결
(2)service 부분에서 출력 수행
(3)destroy 부분에서 파괴

@Log4j2
@NoArgsConstructor

@WebServlet("/TTT")
public class TTTServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	private Connection conn;
       
	//1. App.Scope에 공유되어있는 JDBC 연결정보를 이용해서,
	// JDBC Connection 1개를 생성하여, 필드로 저장
	@Override
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		log.trace("init({}) invoked", config);
		
		try {  //  To get a JDBC Connection 
			ServletContext sc = config.getServletContext();
			
			String driver  =(String) sc.getAttribute("driver");
			String jdbcUrl  =(String) sc.getAttribute("jdbcUrl");
			String user  =(String) sc.getAttribute("user");
			String pass  =(String) sc.getAttribute("pass");
			
			// JDBC programing
			Class.forName(driver);
			log.info(Class.forName(driver));
			
			this.conn = DriverManager.getConnection(jdbcUrl, user, pass);
			
		} catch(Exception e) {
			 throw new ServletException(e); 
		}// try- catch
		
		
	}// init
	
	//2. 필드로 저장되어있는 JDBC Connection을 이용하여, 현재 날짜와 시간을 응답 문서로 출력
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		log.trace("service invoked");
			
		try {  // 현재날짜와 시간정보를 얻는 SQL을 수행하고 응답문서로 출력 

			String sql= "SELECT current_date FROM dual ";
				
			PreparedStatement pstmt = conn.prepareStatement(sql);
			
			@Cleanup ResultSet rs =pstmt.executeQuery();
			
			String DATE ="";
			
	    	while(rs.next()) {
	    		
	    		Timestamp CURRENT_DATE = rs.getTimestamp("CURRENT_DATE");
	    		
	    		DATE = String.format("%s",CURRENT_DATE);
		    		
		    		
		    	log.info("Employee: {}" , DATE);
		    	
		    	
		    	resp.setContentType("text/html; charset = UTF-8");
		    	
	    	}// while
	    	PrintWriter out = resp.getWriter();
	    	
	    	out.print("<html><head></head><body>");
	    	out.print("<h1>"+DATE+"</h1>");
	    	out.print("</body></html>");
			
		} catch(Exception e) {
			 throw new IOException(e); 
		}// try- catch
		
		
	}// service

	
	//3. 필드에 저장되어있는 JDBC Connection 자원을 해제
	@Override
	public void destroy() {
		log.trace("destroy invoked");
		
		try { // 필드에 있는 JDBC Connection 해제 
			if(this.conn != null && !this.conn.isClosed()) {
				this.conn.close();
			} //if
		} catch (Exception e) {;;}
		
	}// destroy();

}// end class

대강 흐름

리스너 생성 >범위 별로 자원객체 정보등록 > 필터 (공통적인 조건설정)> 각 서블릿에서 실행


-Servlet Filter

서블릿에서 처리되기 전에 / 변화하기 전에 사전작업이나 사후작업을 해주는 기능을 한다.
=> request가 servlet에 가기 전 -요청 필터
or
=> esponse가 servlet에서 나가기 전 -응답 필터

필터를 나눠서 처리하게끔 만들어놨다.
= 필터 체인(그 다음 필터로 넘기는 것을 도와주는 객체)


▼ Filter예제

-핵심!
(1)필터가 생성되고 파괴되는 시점 (리스너보다 늦게 생기고 빨리 죽는다.)

(2)doFilter 메소드
->FilterChain chain에 대해서 그 다음 필터로 넘기는 것을 도와주는 객체
-> chain.doFilter(request, response); 선처리/후처리 제어 메서드
-> 선처리와 후처리가 나눠진다는 점 인식
(3)공통적으로 사전에 처리 해줘야하는 것 사용

(4)잘못된 요청일 때 뒤에 또 처리문을 보내지 않고 끝내기 위한 if문으로 구별 후 리턴처리

@Log4j2
//@NoArgsConstructor

@WebFilter("/Login")
public class MyFilter extends HttpFilter implements Filter {
      
	public MyFilter() {
		super();
		log.trace("default constructor invoked.");
		
		
	} // default constructor
	

	@Override
	public void init(FilterConfig config) throws ServletException {
		log.trace("init() invoked" , config);
		
	}// init
	
	@Override
	// FilterChain은  그 다음 필터로 넘기는 것을 도와주는 객체
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		log.trace("doFilter invoked" ,chain);
		
		log.info("김 선처리");// 요청에 대한 선처리 
		request.setCharacterEncoding("utf8"); //이렇게 공통적으로 사전에 처리 해줘야하는 것 사용
		// 그러나 servers에서 전체적인 설정을 담당하는 web.xml 에서 설정해주는게 좋음
		
		//선처리에서 먼저 응답 보내기
		response.setContentType("text/html; charset=UTF-8");
		
		@Cleanup
		PrintWriter out = response.getWriter();
		
		out.print("나쁜 요청이야");
		out.flush();
		
//		return; // 뒤에 또 처리문을 보내지 않고 끝내기 위한 리턴처리 
		//예제는 보여주기식위함이고 if문으로 보통 구별하여 응답한다.
		
//		=======================================

		//이 부분은 건드리지 않는다. 
		chain.doFilter(request, response); // 요청에 대한 선처리와 응답에 대한 후처리를 제어하는 호출
		
		
		// 그럼 필터 체인의 순서는 어떻게 정할까 ?
//		=======================================
		
		log.info("김 후처리");//응답에 대한 후처리
		
	}// doFilter

	@Override
	public void destroy() {
		log.trace("destroy() invoked");

		
	}// destroy
}//end class

4. 필터의 Web.xml 로 등록

-필터를 지정하는 방법
Servlet에 부여된 이름 (잘 안씀)
URL (사용)

-필터의 매핑은/* 와일드 카드를 사용해야한다.
=>모든 요청을 다 확인해야하기 때문에

  • 확장자 경로는 이렇게 지정
profile
일단 흐자

0개의 댓글