-예제에서 알아볼 점
(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
-공유 영역에다가 저장할 값들 넣어주고 Listener등록해주기
-알아본 점
(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
대강 흐름
리스너 생성 >범위 별로 자원객체 정보등록 > 필터 (공통적인 조건설정)> 각 서블릿에서 실행
서블릿에서 처리되기 전에 / 변화하기 전에 사전작업이나 사후작업을 해주는 기능을 한다.
=> 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
-필터를 지정하는 방법
Servlet에 부여된 이름 (잘 안씀)
URL (사용)
-필터의 매핑은/* 와일드 카드를 사용해야한다.
=>모든 요청을 다 확인해야하기 때문에
- 확장자 경로는 이렇게 지정