kh day 078
이번주 공지사항
- 금주 목요일 능력단위평가 시행예정! 빠지지 마세요~
이번주 훈련방향
가. Servlet/JSP에서 Servlet 완료
-Servlet 핵심클래스, JDBC연동, DataSource 연동, Servlet 고급 (MVC패턴)
나. JSP 초급 완료
- JSP 스크립팅 요소 (선언태그, Scriptlet, Expression 태그)
- 웹 어플레케이션 예외처리
다. 진도가 빠르면 스프링을 위한 선행요소기술로 MyBatis SQL Mapper Framework 나간다
---
ServletContextListener 이어서 나가자!
@Log4j2
@NoArgsConstructor
//@WebListener // web.xml에서 해보자
public class ServletContextListenerImpl implements ServletContextListener {
// public ServletContextListenerImpl() {
// log.trace("Default Constructor invoked.");
//
// } // default constructor
@Override
public void contextInitialized(ServletContextEvent e) {
log.trace("contextInitialized({}) invoked.", e);
ServletContext sc = e.getServletContext();
// web.xml에 등록된 컨텍스트 파라미터 획득
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);
// Application scope에 올리자!
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.", e);
ServletContext sc = e.getServletContext();
// 파괴될 때 내리자!
sc.removeAttribute("driver");
sc.removeAttribute("jdbcUrl");
sc.removeAttribute("user");
sc.removeAttribute("pass");
} // contextDestroyed
} // end class
ServletContextListenerImpl.java
WAS 실행시키고 로그 확인
Q) 생성자가 언제 호출되나?
-> WAS가 완전히 올라오기 전에 호출된다 (웹 어플리케이션이 디플로이 되기 전에 호출)
-> 결론 : 리스너 객체는 WAS 안의 웹 어플리케이션들이 올라오기 전에 먼저 생성된다.
WAS를 내리고 로그확인
Q) contextDestroyed가 언제 호출되나?
-> WAS가 완전히 내려가기 전에 호출된다
-> 따라서 자원객체 해제를 여기에다가 해준다.
* 어노테이션 말고 web.xml 파일에 리스너를 등록해보자
web.xml에 <listener> 태그를 사용하여 등록한다.
주의할 점은 <context-param> 태그 다음에 지정해야 된다.

* 서블릿을 위한 파라미터는 이닛파람
컨텍스트를 위한 파라미터는 컨텍스트파람
컨텍스트 나오면 웹 어플리케이션을 떠올리세요

- 서버 올렸을때 콘솔창

- 서버 내렷을때 콘솔창
--
@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 {
log.trace("init({}) invoked.", config);
super.init(config); // 지우면 큰일! 앞에다 넣어주자
try { // JDBC Connection을 얻으라
ServletContext sc = config.getServletContext();
// 리스너에서 올린 JDBC 연결정보 값을 얻어서 필드에 저장하자
String driver = (String) sc.getAttribute("driver");
String jdbcUrl = (String) sc.getAttribute("jdbcUrl");
String user = (String) sc.getAttribute("user");
String pass = (String) sc.getAttribute("pass");
// 잘 받아서 저장했는지 찍어서 확인해보자
log.info("\t+ dirver : {}", driver);
log.info("\t+ jdbcUrl : {}", jdbcUrl);
log.info("\t+ user : {}", user);
log.info("\t+ pass : {}", pass);
// JDBC programming
Class.forName(driver);
this.conn = DriverManager.getConnection(jdbcUrl, user, pass);
log.info("\t+ this.conn : {}", this.conn);
// 연결객체가 null인지 여부 검증 (2가지 방법)
Objects.requireNonNull(this.conn);
// assert this.conn != null;
} catch (Exception e) {
throw new ServletException(e);
} // try-catch
} // init
// 2. 필드에 저장되어 있는 JDBC Connection을 이용하여 현재 날짜와 시간을 응답문서로 출력
@Override
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
log.trace("revice(req, res) invoked.");
String now = null;
try { // 현재날짜와 시간정보를 얻는 SQL을 수행하고 응답문서로 출력
String sql = "Select to_char(current_date, 'yyyy/mm/dd - hh24:mi:ss') AS now From dual";
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
now = rs.getString("now");
} // if
// 응답문서생성
res.setContentType("text/html; charset=utf8");
@Cleanup
PrintWriter out = res.getWriter();
out.println("<h1>" + now + "</h1>");
out.flush();
} catch (Exception e) {
throw new IOException(e);
} // try-catch
} // service
// 3. 필드에 저장되어있는 JDBC Connection 자원을 해제
@Override
public void destroy() {
log.trace("destroy() invoked.");
try { // 필드에 있는 JDBC Connection 해제
// 롬복 @Cleanup은 메소드 블록 안에서만 쓸 수 있으므로 사용불가
// try-with-resources는 final이어야 쓸 수 있으므로 사용불가
if(this.conn != null && !this.conn.isClosed()) {
this.conn.close();
} // if
} catch(Exception e) {;;}
// super.destroy(); // 얘는 지워도 됨
} // destroy
} // end class
TTTServlet.java - 강사님의 예제다
* studyproject의 JDBCExample 1~7 다시 한번 확인해봐야한다

- 서버 올렸을때 콘솔창

- 서버 내렷을때 콘솔창
---
4. Filter API
클라이언트인 웹 브라우저에서 서블릿으로 요청하면, 웹 컴포넌트인 서블릿이 요청을 받아서 작업을 처리하고 결과 HTML 형식으로 작성하여 웹 브라우저에게 응답 처리한다. 이때, 서블릿이 요청 받기 전과 결과를 웹 브라우저에게 응답하기 전에 특정 작업을 수행할 수 있도록 Filter API를 사용할 수 있다.
즉, 웹 컴포넌트가 실행되기 전의 선처리(pre-processing) 작업과 응답되기 전의 후처리(post-processing) 작업을 수행하는 API이다. 다수의 Filter를 체인(Chain)처럼 묶어서 적용시킬 수도 있으며, 선처리 작업의 필터를 요청필터(Request Filter)라고 하고 후처리 작업의 필터를 응답필터(Response Filter)라고 한다. 선처리 작업의 대표적인 적용 예는 한글인코딩 및 보안관련 작업 등이고, 후처리 작업은 압축 및 데이터 변환작업 등이다.
다음은 Filter를 적용한 아키텍처이다.

---
필터를 생성하자!



@Log4j2
@NoArgsConstructor
// @WebFilter("/*") // 이렇게 쓰면 어떤 servlet이던 이 필터를 통과함
// @WebFilter({ "/Lifecycle1", "/Lifecycle2" })
// 이렇게 쓰면 /Lifecycle1, /Lifecycle2만 이 필터를 통과함
// web.xml에서 수동으로 등록해보자!
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
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
log.trace("doFilter(req, res, {}) invoked.", chain);
// 1. 요청에 대한 선처리 (Pre-processing)
log.info("\t+ Pre-processing for request");
// boolean isValid = false;
//
// if(!isValid) {
// res.setContentType("text/html; charset=utf8");
// @Cleanup
// PrintWriter out = res.getWriter();
// out.println("<h1> Bad request. </h1>");
// out.flush();
// return;
// } // if
// 요청(request)에 대한 선처리와, 응답(response)에 대한 후처리를 제어하는 호출
// chain 객체를 이용해 request, response를 넘긴다
chain.doFilter(req, res);
// 2. 요청에 대한 후처리 (Post-processing)
log.info("\t+ Post-processing for response");
} // doFilter
@Override
public void destroy() {
log.trace("destroy() invoked.");
} // destroy
} // end class
MyFilter.java
- 서버를 올리고 호출로그를 확인해보자

선처리 로그가 먼저 나오고
후처리 로그가 나중에 나온다
---
이번엔 어노테이션 말고 직접 web.xml에 등록해보자

---
* 자바 언어 1권은 마치고 나머지는 백앤드에 몰입해보세요
백엔드는 교재랑 예제를 반복해서 보고 해보세요
---
5. url-pattern 개요
서블릿 맵핑과 필터 맵핑은 web.xml 파일 및 어노테이션을 사용하여 설정한다.
이때 공통적으로 사용하는 값이 url-pattern이다.
url-pattern은 웹 브라우저에서 클라이언트가 요청하는 URL 값의 패턴에 따라서,
서버의 어떤 웹 컴포넌트가 실행될지를 결정하는 방법이다
1) 디렉토리 패턴

2) 확장자 패턴

@Log4j2
@NoArgsConstructor
@WebServlet("*.do")
public class ExtensionServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
log.trace("service(req, res) invoked.", req, res);
} // service
} // end class
ExtensionServlet.java
---
* getInitParameter()와 getAttribute() 차이가 뭔가요?
1) request.getInitParameter(전송파라미터이름)
- 지정된 이름의 전송파라미터 값을 획득 (문자열)
2) 공유데이터 영역에 접근할 수 있는 객체.getAttribute(공유속성이름)
- ServletContext.getAttribute("name");
: App.scope의 name 공유 속성값을 획득
- HttpSession.getAttribute("name");
: Sess.scope의 name 공유 속성값을 획득
- HttpServletRequest.getAttribute("name");
: Req.scope의 name 공유 속성값을 획득
- page.getAttribute("name");
: Page.scope의 name 공유 속성값을 획득
'국비학원' 카테고리의 다른 글
| [국비지원] KH 정보교육원 80일차 (0) | 2022.07.21 |
|---|---|
| [국비지원] KH 정보교육원 79일차 (0) | 2022.07.20 |
| [국비지원] KH 정보교육원 77일차 (0) | 2022.07.16 |
| [국비지원] KH 정보교육원 76일차 (0) | 2022.07.15 |
| [국비지원] KH 정보교육원 75일차 (0) | 2022.07.14 |