딸기말차
[Java web] 9. Servlet Context, Servlet Config 본문
엔코아 플레이데이터(Encore Playdata) Backend 2기 백엔드 개발 부트캠프 (playdata.io)
백엔드 개발 부트캠프
백엔드 기초부터 배포까지! 매력있는 백엔드 개발자 포트폴리오를 완성하여 취업하세요.
playdata.io
1. Forward 복습
1. forward 란?
기본적으로 forward란, RequestDistpatcher 객체에 데이터를 담아 다른 servlet이나 view template으로 넘겨주는 것을 의미한다.
1. request에 대한 추가 작업을 다른 서블릿에게 수행하게 한다.
2. request에 포함된 정보를 다른 서블릿이나 jsp와 공유할 수 있다.
3. request에 정보를 포함시켜 다른 서블릿에 전달할 수 있다.
4. 모델2 개발 시 서블릿에서 jsp로 데이터를 전달하는데 사용한다.
* 모델2?
1. 모델1 방식 : 혼자 모든걸 처리하는 방식
2. 모델2 방식 : 일을 나눠서 처리하는 방식 (mvc 패턴)
현재 우리가 자주 사용하는 방식으로,
1. servlet <-> serlvet 이동
2. servlet <-> jsp 이동
이렇게 두 종류가 존재한다.
2. Servlet의 forward 방법
1. redirect
1) 웹 브라우저에 재요청하는 방식이다.
2) HttpServletResponse 의 sendRedirect("서블릿명 or JSP")
2. refresh
1) 웹 브라우저에 재요청하는 방식이다.
2) HttpServletResponse 의 addHeader("Refresh", 경과시간(초); url="서블릿명 or JSP")
3. location
1) 자바스크립트 location 객체의 href 속성을 이용한다.
2) 자바스크립트에 재요청하는 방식으로, 서블릿에서 웹 브라우저를 거쳐 다른 서블릿 혹은 JSP에 전달한다.
3) location.href = '서블릿명 or JSP'
4. dispatch
1) 일반적인 forward를 말한다. 서블릿이 웹 브라우저를 거치지않고 다른 서블릿이나 JSP에 직접 전달한다.
2) RequestDispatcher 객체는 생성을하는게 아니라 HttpRequest 객체 내에서 얻어와야한다.
3) requestDistpatcher.forward(request, response);
3. forward 실습
위에 서술한 4가지 방식을 사용해 FirstServlet에서 SecondServlet으로 forward하는 실습을 진행하였다.
1) FirstServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
// 1. 단순 화면 이동
response.sendRedirect("second");
// 2. 파라미터와 화면 이동
response.sendRedirect("second?name=lee");
// 3. Refresh 화면 이동
response.addHeader("Refresh", "2; url=second");
// 4. javascript 화면 이동
out.print("<script type='text/javascript'>");
out.print("location.href='second';");
out.print("</script>");
// 5. RequestDispatcher 화면 이동
RequestDispatcher requestDispatcher = request.getRequestDispatcher("second?name=lee");
requestDispatcher.forward(request, response);
// 6. RequestDispatcher 이용 객체 전달 (바인딩)
request.setAttribute("key", "value");
RequestDispatcher requestDispatcher = request.getRequestDispatcher("second");
requestDispatcher.forward(request, response);
}
2) SecondServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=utf-8");
// 1. 단순 화면 이동 결과
PrintWriter out = response.getWriter();
out.print("<html><body>");
out.print("1. sendRedirect를 이용한 redirect 실습입니다.");
out.print("</html></body>");
out.print("<br/><br/>");
// 2. 파라미터와 화면 이동 결과
out.print("<html><body>");
out.print("2. name : " + request.getParameter("name"));
out.print("</html></body>");
out.print("<br/><br/>");
// 3. Refresh 화면 이동 결과
out.print("<html><body>");
out.print("3. Refresh를 이용한 redirect 실습입니다.");
out.print("</html></body>");
out.print("<br/><br/>");
// 4. javascript 화면 이동 결과
out.print("<html><body>");
out.print("4. javascript를 이용한 redirect 실습입니다.");
out.print("</html></body>");
out.print("<br/><br/>");
// 5. RequestDispatcher 화면 이동 결과
out.print("<html><body>");
out.print("5. name : " + request.getParameter("name"));
out.print("</html></body>");
out.print("<br/><br/>");
// 6. RequestDispatcher 객체 전달 결과
out.print("<html><body>");
out.print("6. dispatcher를 통해 전달 받은 객체의 값 : " + request.getAttribute("key"));
out.print("</html></body>");
out.print("<br/><br/>");
request.removeAttribute("key"); // 전달받은 객체 제거
}
2. Servlet Context
javax.servlet.ServletContext에 정의되어 있는, Servlet 단위로 생성되는 Context이다.
즉, tomcat 같은 컨테이너에 어떤 Servlet을 등록할 때, 해당 Servlet이 갖는 하나의 작은 컨테이너 역할을 하는 객체이다.
Servlet Context는 new로 새롭게 객체를 생성하는 것이 아니라, Application에서 가져오는 것이다.
때문에 Application 내에 있는 모든 Servlet을 관리하며, 정보를 공유할 수 있게 도와준다.
Servlet Context가 제공하는 기능
1. servlet에서 파일 접근 가능
2. 자원 바인딩 (공유)
3. 로그 파일 (DB에서 쿼리를 사용하면 해당 실행의 로그)
4. context에서 등록하는 설정 정보를 제공
5. tomcat 같은 컨테이너가 실행 시 생성되고 종료 시 소멸한다.
1. Servlet Context에 데이터 저장 후 다른 Servlet에서 가져오기
1) SetServletContext
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
/*
* ServletContext는 Application에서 얻어오는 것이기 때문에 new로 생성하는게 아니라 가져오는 것이다.
* 1. getServletContext() 를 이용해 ServletContext 객체에 접근
* 2. ArrayList에 이름과 나이를 저장
* 3. 다시 ServletContext 객체에 setAttribute() 를 이용해 바인딩
*/
ServletContext context = getServletContext();
/*
* ArrayList는 타입을 지정해주지 않아도 넣으면 다 들어간다.
* 다만, add 시 값이 그대로 들어가는게 아니라 Object로 감싸져서 들어간다.
*/
List members = new ArrayList<>();
members.add("이순신");
members.add(30);
context.setAttribute("members", members);
out.print("<html><body>");
out.print("이순신과 30 설정");
out.print("</html></body>");
out.close();
}
2) GetServletContext
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
ServletContext context = getServletContext();
List members = (ArrayList) context.getAttribute("members");
out.print("<html><body>");
out.print("이름 : " + (String) members.get(0));
out.print(" 나이 : " + (Integer) members.get(1));
out.print("</html></body>");
out.close();
}
2. web.xml에 저장한 context 정보 가져오기
1) web.xml
<context-param>
<param-name>menu_member</param-name>
<param-value>회원등록 회원조회 회원수정</param-value>
</context-param>
<context-param>
<param-name>menu_order</param-name>
<param-value>주문등록 주문조회 주문수정 주문취소</param-value>
</context-param>
<context-param>
<param-name>menu_goods</param-name>
<param-value>상품등록 상품조회 상품수정 상품삭제</param-value>
</context-param>
2) ContextParamServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
/*
* 1. getServletContext() 로 ServletContext 객체 접근
* 2. getInitParamenter() 의 인자로 각각의 메뉴 이름을 전달 한 후
* 3. 메뉴 항목들을 가져와 이를 브라우저로 출력
*/
// web.xml 내의 <context-param></context-param> 를 가져오기 위해
ServletContext context = getServletContext();
out.print("<html><body>");
out.print("<table border = 1 cellspacing = 0>");
out.print("<tr>메뉴이름</tr>");
out.print("<tr><td>" + context.getInitParameter("menu_member") + "</td></tr>");
out.print("<tr><td>" + context.getInitParameter("menu_order") + "</td></tr>");
out.print("<tr><td>" + context.getInitParameter("menu_goods") + "</td></tr>");
out.print("</table>");
out.print("<html><body>");
out.close();
}
3. ServletContext를 통해 외부파일 읽어오기
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
/*
* ServletContext의 파일에서 데이터를 읽어오는 기능
* 1. getServletContext() 로 ServletContext 접근
* 2. getResourceAsStream() 에서 읽어들일 파일 위치를 지정
* 3. 파일에서 데이터를 줄단위로 읽기
* 4. , 를 기준으로 분리
*/
ServletContext context = getServletContext();
InputStream is = context.getResourceAsStream("/WEB-INF/bin/init.txt"); // 외부 파일을 읽어오기 위한 통로 설정
BufferedReader br = new BufferedReader(new InputStreamReader(is)); // 통로를 통해 넘어온 데이터 읽기
String menu = null;
String menu_member = null;
String menu_order = null;
String menu_goods = null;
while ((menu = br.readLine()) != null) {
StringTokenizer tokens = new StringTokenizer(menu, ",");
menu_member = tokens.nextToken();
menu_order = tokens.nextToken();
menu_goods = tokens.nextToken();
}
out.print("<html><body>");
out.print("menu_member : " + menu_member + "<br/>");
out.print("menu_order : " + menu_order + "<br/>");
out.print("menu_goods : " + menu_goods + "<br/>");
out.print("<html><body>");
out.close();
}
3. Servlet Config
servlet을 실행할 때 필요로하는 설정 정보를 제공하는 기능으로, servlet 객체 당 하나씩 생성된다.
대표적인 기능으로 초기 파라미터(initParams)를 설정하거나, servlet의 이름, urlPatterns 등이 존재한다.
즉, servlet을 초기화 하기위해 존재한다 볼 수 있다.
해당 기능을 사용하는 이유는, 기능을 위한 코드 (servlet 내) 와 설정을 위한 코드 (xml) 을 분리 개발 후 ServletConfig로 연결해, 유지보수성을 향상 시킬 수 있기 때문이다.
과거에는 해당 기능을 xml에 구현해 사용했지만, 현재는 @WebServlet 으로 대체해 설정이 가능하다
@WebServlet 구성요소
1. urlPatterns
2. name
3. loadOnStartUp (컨테이너 실행 시 서블릿이 실행되는 우선순위 지정)
4. initParams (@WebInitParam 어노테이션을 통해 매개변수를 추가)
5. description (서블릿에 대한 설정)
load-on-startup 기능
1. 서블릿은 브라우저에서 최초 요청 시 init() 메서드를 실행한 후 메모리에 로드되어 기능을 수행한다.
2. 따라서 최초 요청에 대해서는 실행시간이 길어질 수 밖에 없다. 이 단점을 보완하기 위해 loadOnStartup을 사용한다.
3. 보통 서블릿을 호출할 때 메모리에 로드하지만, 해당 옵션을 설정해두면 톰캣을 실행할 때 서블릿을 메모리에 로드한다.
4. loadOnStartup의 속성값을 설정하지 않으면 0으로 설정 되어있다. 0은 해당 기능을 사용하지 않겠다는 것을 의미한다.
5. 숫자는 우선순위를 의미한다. 낮을수록 우선순위가 높다.
1. web.xml에 config 정보 저장 후 가져오기
1) web.xml
<servlet>
<servlet-name>loadConfig</servlet-name>
<servlet-class>com.lhs.LoadAppConfigWeb</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>loadConfig</servlet-name>
<url-pattern>/loadConfig2</url-pattern>
</servlet-mapping>
2) LoadAppConfigWeb
private ServletContext context;
public void init(ServletConfig config) throws ServletException {
System.out.println("LoadAppConfigWeb의 init 메서드 호출");
context = config.getServletContext();
context.setAttribute("menu_member", context.getInitParameter("menu_member"));
context.setAttribute("menu_order", context.getInitParameter("menu_order"));
context.setAttribute("menu_goods", context.getInitParameter("menu_goods"));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
PrintWriter out = response.getWriter();
out.print("<html><body>");
out.print("<table border = 1 cellspacing = 0>");
out.print("<tr>메뉴이름</tr>");
out.print("<tr><td>" + (String)context.getAttribute("menu_member") + "</td></tr>");
out.print("<tr><td>" + (String)context.getAttribute("menu_order") + "</td></tr>");
out.print("<tr><td>" + (String)context.getAttribute("menu_goods") + "</td></tr>");
out.print("</table>");
out.print("</html></body>");
out.close();
}
2. web.xml과 @WebServlet 비교
1) web.xml
<servlet>
<servlet-name>initParamWebServlet</servlet-name>
<servlet-class>com.lhs.InitParamServlet</servlet-class>
<init-param>
<param-name>email</param-name>
<param-value>admin@jweb.com</param-value>
</init-param>
<init-param>
<param-name>tel</param-name>
<param-value>010-111-2222</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>initParamWebServlet</servlet-name>
<url-pattern>/sinit</url-pattern>
</servlet-mapping>
2) @WebServlet
@WebServlet(
name = "initParamServlet",
urlPatterns = {
"/sInit",
"/sInit2"
},
initParams = {
@WebInitParam(name = "email", value = "admin@free.com"),
@WebInitParam(name = "tel", value = "010-1111-2222")
})
두 설정정보는 동일한 기능을 제공한다. 때문에 오타가 나기 쉬운 xml파일을 건드는 것보단, 최신 트렌드에 맞춰 어노테이션을 사용하는 방식을 추천한다.
4. 21일차 후기
우리가 만드는 웹 어플리케이션은 다음과 같은 실행과정을 거친다.
1. Aplication 실행
2. Aplication으로 부터 가져온 servlet context 생성
3. servlet config (@WebServlet or xml) 을 통해 servlet 초기화
4. servlet 객체 생성
5. 요청에 따른 servlet method (doGet, doPost ... ) 실행
기존에는 Servlet을 생성 후 forward를 통해 다른 Servlet으로 데이터를 운반했다. 하지만 이때 Servlet Context를 사용한다면, forward를 하지 않아도 정보를 공유할 수 있다는 점을 알게 되었다.
또한, Servlet Config 기능을 통해 생성 전 초기 값을 미리 줄 수 있고, loadOnStartup 옵션을 통해 최초 요청 시 실행시간을 줄일 수 있는 점 또한 알게되었다.
'Bootcamp > Java web' 카테고리의 다른 글
[Java web] 11. File Up/Download, JQuery, Ajax, Json (0) | 2023.08.01 |
---|---|
[Java web] 10. Cookie, Session, Filter, Listener (0) | 2023.07.28 |
[Java web] 8. Oracle JDBC, DispatcherServlet (0) | 2023.07.25 |
[Java web] 7. Web 복습, Oracle (0) | 2023.07.24 |
[Java web] 6. Mini Project_2 (0) | 2023.07.22 |