8.1 서블릿 포워드 기능 사용하기
웹 애플리케이션은 여러 기능을 담당하는 서블릿끼리 또는 서블릿과 JSP를 연동해서 작업하는 경우가 많음
포워드 : 하나의 서블릿에서 다른 서블릿이나 JSP와 연동하는 방법
<포워드 기능이 사용되는 용도>
- 요청에 대한 추가 작업을 다른 서블릿에게 수행하게 함
- 요청에 포함된 정보를 다른 서블릿이나 JSP와 공유
- 요청에 정보를 포함시켜 다른 서블릿에 전달
- 모델2 개발 시 서블릿에서 JSP로 데이터를 전달
8.2 서블릿의 여러 가지 포워드 방법
1. redirect 방법
ㄴ HttpServletResponse 객체의 sendRedirect("포워드할 서블릿/JSP") 메서드 이용
ㄴ 웹 브라우저에 재요청하는 방식
2. Refresh 방법
ㄴ HttpServletResponse 객체의 addHeader()메서드 이용
>> response.addHeader("Refresh", 경과시간(초); url="요청할 서블릿/JSP");
ㄴ 웹 브라우저에 재요청하는 방식
3. location 방법
ㄴ 자바스크립트 location 객체의 href 속성 이용 >> location.href='요청할 서블릿/JSP"
ㄴ 자바스크립트에서 재요청하는 방식
4. dispatch 방법
ㄴ 일반적으로 포워딩 기능을 지칭
ㄴ 서블릿이 직접 요청하는 방식
ㄴ RequestDispatcher 클래스의 forward() 메서드 이용
>>> RequestDispatcher dis=request.getRequestDispatcher("포워드할 서블릿/JSP");
dis.forward(request,response);
- 1,2,3은 서블릿 > 웹브라우저 > 다른 서블릿/JSP에게 요청
>>> 첫번째 서블릿으로 요청(주소창에 첫번째 서블릿매핑 이름 으로 치면) 자동으로 두번째 서블릿 주소와 함께 화면이 나옴
- 4는 서블릿>다른 서블릿 (직접)
>>> 웹 브라우저의 주소가 변경되지 않음, 즉 클라이언트에서는 포워드가 진행되었는지 알 수 없음
<1. redirect를 이용한 포워딩>
- 요청 > 첫 번째 서블릿은 sendRedirect()를 이용해 두 번째 서블릿을 브라우저를 통해 요청 > 브라우저는 sendRedirect() 메서드가 지정한 두번째 서블릿을 다시 요청
- 다른 서블릿을 호출하면서 원하는 데이터를 GET 방식으로 전달할 수 있음(첫번째에서 서블릿 뒤에 ?로 구분하여 name=value입력하고 두번째에서 getParameter로 받음)
<2. refresh 포워딩>
- 요청 > 첫번째 서블릿이 addHeader()로 두 번째 서블릿을 브라우저를 통해 요청 > 브라우저는 addHeader()가 지정한 두 번째 서블릿을 다시 요청
- ex) response.addHeader("Refresh","1;url=second"); // 웹 브라우저에 1초 후 서블릿 second로 재요청
<3. location 포워딩>
첫번째 서블릿
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
out.print("<script type='text/javascript'>");
out.print("location.href='second'");
out.print("</script>");
}
8.3 dispatch를 이용한 포워드 방법
- 요청 > 첫번째 서블릿은 RequestDispatcher를 이용해 두 번째 서블릿으로 포워드
- 모델2방식, 스트럿츠, 스프링 프레임워크에서 포워딩할 때 사용
ex)
RequestDispatcher dispatch=request.getRequestDispatcher("second");
dispatch.forward(request, response);;
- redirect처럼 ?뒤에 name=value를 추가해서 GET 방식으로 데이터를 전송할 수 있다
8.4 바인딩
- 앞서 GET방식으로 데이터를 전달하는 방법은 대량의 정보를 전송하는 것은 불편 >> 바인딩 이용
- 바인딩 : 두 개를 하나로 묶는 것, 데이터를 서블릿 관련 객체에 저장하는 방법
- HttpServletRequest, HttpSession, ServletContext 객체에서 사용 됨
- 저장된 데이터는 프로그램 실행 시 서블릿이나 JSP에서 공유하여 사용
- 모델2, 스트럿츠, 스프링 프레임워크로 구현하는 웹 프로그램이 사용하는 방법
<서블릿 객체에서 사용되는 바인딩 관련 메서드>
- setAttribute(String name, Object obj) : 데이터를 각 객체에 바인딩(ex. address-서울시 성북구)
- getAttribute(String name) : 객체에 바인딩 된 데이터를 name으로 가져옴
- removeAttribute(String name) : 객체에 바인딩 된 데이터를 name으로 제거
* HttpServletRequest 바인딩을 이용한 redirect 포워딩 ==> X
* 첫번째에 request.setAttribute하고 두번째에 request.getAttribute하면 제대로 데이터가 전송되지 않음,
>> because, 첫번째 서블릿이 받는 요청과 두번째 서블릿이 받는 요청은 서로 다른 요청이기 때문이다.
HttpServletRequest 바인딩을 이용한 dispatch 포워딩 ==> O
첫 번째 서블릿에서 두 번째 서블릿으로 전달되는 요청이 브라우저를 거치지 않고 바로 전달되어 같은 요청임
//first
request.setAttribute("address", "서울시 성북구");
RequestDispatcher dispatch=request.getRequestDispatcher("second");
dispatch.forward(request, response);
/////////////////////
//second
String address=(String)request.getAttribute("address");
~두 서블릿 간 회원 정보 조회 바인딩 실습~
MemberServlet.java
protected void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
List<MemberVO> memberList=dao.listMembers();
request.setAttribute("membersList", memberList);
RequestDispatcher dispatch=request.getRequestDispatcher("viewMembers");
dispatch.forward(request, response);
}
ViewServlet.java
protected void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
List membersList=(List)request.getAttribute("membersList");
out.print("<html><body>");
out.print("<table border=1><tr align='center' bgcolor='lightgreen'>");
out.print("<td>아이디</td><td>비밀번호</td><td>이름</td><td>이메일</td><td>가입일</td><td >삭제</td></tr>");
for(int i=0;i<membersList.size();i++) {
MemberVO memberVO=(MemberVO)membersList.get(i);
String id=memberVO.getId();
String pwd=memberVO.getPwd();
String name=memberVO.getName();
String email=memberVO.getEmail();
Date joinDate=memberVO.getJoinDate();
out.print("<tr><td>"+id+"</td><td>"+
pwd+"</td><td>"+
name+"</td><td>"+
email+"</td><td>"+
joinDate+"</td><td>"
+"<a href='/pro07/member3?command=delMember&id="+id+"'> 삭제 </a></td></tr>");
}
out.print("</table></body></html>");
out.print("<a href='/pro08/memberForm.html'>새 회원 등록하기</a>");
}
* 7장과 다르게 db 데이터 받아오는 서블릿과 화면에 응답하는 서블릿(추후에 분화되어 발전된 것이 JSP)을 분리
8.5 ServletContext와 ServletConfig 사용법
ServletContext 클래스
- getServletContext()로 ServletContext 객체를 가져옴
- 서블릿과 컨테이너 간의 연동을 위해 사용
- 톰캣 컨테이너 실행 시 각 컨텍스트(웹 애플리케이션)마다 한 개의 ServletContext 객체를 생성
- 톰캣 컨테이너가 종료하면 소멸
- 웹 애플리케이션이 실행되면서 애플리케이션 전체의 공통 자원이나 정보를 미리 바인딩해서 서블릿이 공유하여 사용
- 서블릿에서 파일 접근 / 자원 바인딩 / 로그 파일 / 컨텍스트에서 제공하는 설정 정보 제공
<ServletContext 메서드>
메서드 | 기능 |
getAttribute(String name) | - 주어진 name(없으면 null)을 이용해 바인딩된 value를 가져옴 |
getAttributeNames() | - 바인딩된 속성들의 name 반환 |
getContext(String uripath) | - 지정한 uripath에 해당하는 객체를 반환 |
getInitParameter(String name) | - name에 해당되는 매개변수(없으면 null)의 초기값 반환 |
getInitParameterNames() | - 컨텍스트의 초기화 관련 매개변수들의 이름들을 Enumeration 타입으로 반환 - 매개변수가 없으면 null 반환 |
getMajorVersion() | - 서블릿 컨테이너가 지원하는 주요 서블릿 API 버전 반환 |
getRealPath(String path) | - 지정한 path에 해당되는 실제 경로 반환 |
getResource(String path) | - 지정한 path에 해당되는 Resource 반환 |
getResourceAsStream(String path) | - 지정한 path에 해당되는 파일 반환 |
getServerInfo() | - 현재 서블릿이 실행되고 있는 서블릿 컨테이너의 이름과 버전 반환 |
getServletContextName() | - 해당 어플리케이션의 배치 관리자가 지정한 ServletContext에 대한 웹 어플리케이션 이름 반환 |
log(String msg) | - 로그 파일에 로그를 기록 |
removeAttribute(String name) | - 해당 name으로 ServletContext에 바인딩된 객체를 제거함 |
setAttribute(String name, Object object) | - 해당 name으로 객체를 바인딩 |
setInitParameter(String name, String value) | - 주어진 name으로 value를 컨텍스트 초기화 매개변수로 설정 |
~바인딩 실습~
바인딩하는 cset.java
...
ServletContext context=getServletContext();
List member=new ArrayList();
member.add("이순신");
member.add(20);
context.setAttribute("member", member);
바인딩 데이터 가져오는 cget.java
...
ServletContext context=getServletContext();
List member=(ArrayList)context.getAttribute("member");
String name=(String)member.get(0);
int age=(Integer)member.get(1);
>> ServletContext에 바인딩된 데이터는 모든 서블릿이 접근 가능한 것을 알 수 있음
ServletContext의 매개변수 설정 기능(바인딩 미리 선언)
- WebContent>Web-INF>web.xml에서 <web-app>내 <context-param> 태그 안에 <param-name>, <param-value>를 이용해 하위 메뉴 항목을 설정 >>> 서블릿에서 getInitParameter("paramName")으로 가져옴
ex)
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>
서블릿.xml
ServletContext context=getServletContext();
String menu_member=context.getInitParameter("menu_member");
String menu_order=context.getInitParameter("menu_order");
String menu_goods=context.getInitParameter("menu_goods");
out.print("<html><body> <table border=1 cellspacing=0><tr>메뉴 이름</tr>");
out.print("<tr><td>"+menu_member+"</tr></td>");
out.print("<tr><td>"+menu_member+"</tr></td>");
out.print("<tr><td>"+menu_member+"</tr></td>");
out.print("</table></body></html>");
<ServletContext의 파일 입출력 기능>
폴더에 바인딩 이름 작성 > getResourceAsStream으로 파일 읽어드리기 > 버퍼리더 선언 > 토큰분리 후 저장
- /WEB-INF/bin/init.txt
회원등록 회원조회 회원수정, 주문조회 주문등록 주문수정 주문취소, 상품조회 상품등록 상품수정 상품삭제
-servlet
//서블릿 객체를 얻은 후
..
InputStream is=context.getResourceAsStream("/WEB-INF/bin/init.txt"); //파일 읽어드리기
BufferedReader buffer=new BufferedReader(new InputStreamReader(is));
...
while((menu=buffer.readLine())!=null) {
StringTokenizer tokens=new StringTokenizer(menu,","); //콤마로 토큰 분리
menu_member=tokens.nextToken();
menu_order=tokens.nextToken();
menu_goods=tokens.nextToken();
}
ServletConfig
- 각 Servlet 객체에 대해 생성됨, 서블릿끼리 공유 불가
- Servlet과 동일하게 생성&소멸
- ServletConfig 인터페이스를 GenericServlet 클래스가 실제로 구현(5장 참고)
- 기능 : ServletContext 객체를 얻는 기능 / 서블릿에 대한 초기화 작업 기능
서블릿에서 사용할 설정 정보를 읽어 들어와 초기화하기
방법1) @WebServlet 애너테이션 사용
방법2) web.xml에 설정하는 방법
방법1]
@WebServlet 구성 요소들
- urlPatterns : 서블릿 요청 매핑 이름
- name : 서블릿 이름
- loadOnStartup : 컨테이너 실행 시 서블릿이 로드되는 순서 지정
- initParams : @WebInitParam 애너테이션을 이용해서 매개변수를 추가하는 기능
- description : 서블릿에 대한 사용
이클립스에서 @WebServlet 값들 설정하기
서블릿 생성 시 URL mappings 설정하는 창
> 위에 Initialzation parameters 추가하여 이름-값 입력
> 매핑 값들 입력
결과~ urlPatterns를 이용해서 매핑이름 여러개, initParams의 @WebInitParam을 이용해 매개변수 여러개 설정
@WebServlet(
urlPatterns = {
"/sInit",
"/sInit2"
},
initParams = {
@WebInitParam(name = "email", value = "admin@jweb.com"),
@WebInitParam(name = "tel", value = "010-1111-2222")
})
public class InitParamServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
String email=getInitParameter("email"); //컨텍스트의 메서드가 아니라 그냥 바로 가져옴
String tel=getInitParameter("tel");
out.print("<html><body>email: "+email+"<br>휴대전화 : "+tel+"<br>"+"</body></html>");
}
방법2) web.xml를 이용해 매개변수 지정
web.xml에서 <web-app>안에
<servlet>
<servlet-name>sinit</servlet-name>
<servlet-class>sec06.ex01.initParamServlet</servlet-class>
<init-param>
<param-name>email</param-name>
<param-value>admmin@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>
...
8.6 load-on-startup 기능 사용하기
서블릿은 브라우저에서 최초 요청 시 init() 메서드를 실행한 후 메모리에 로드되어 기능을 수행해서 최초 요청에선 실행 시간 길어짐 >> 이 단점을 보완한 기능이 load-on-startup
load-on-startup 특징
- 지정한 숫자가 0보다 크면 톰캣 컨테이너가 실행될 때 미리 서블릿을 실행
- 지정한 숫자는 우선순위를 의미, 작은 숫자부터 먼저 초기화
- 방법 : 1) 애너테이션 이용 2)web.xml에 설정
방법1) @WebServlet에 loadOnStartup로 등록
@WebServlet(name = "loadConfig", urlPatterns = { "/loadConfig" },loadOnStartup=1)
public class LoadAppConfig extends HttpServlet {
private ServletContext context;
public void init(ServletConfig config) throws ServletException {
//톰캣 실행 시 이것만 실행, 요청을해야 doGet실행
System.out.println("init호출");
context=config.getServletContext(); //config이다
String menu_member=context.getInitParameter("menu_member");
String menu_order=context.getInitParameter("menu_order");
String menu_goods=context.getInitParameter("menu_goods"); //web.xml에서 읽어드림
context.setAttribute("menu_member", menu_member);
context.setAttribute("menu_order", menu_order);
context.setAttribute("menu_goods", menu_goods);
//컨텍스트 객체에 바인딩 >> 요청 시 web.xml(파일)보다 객체에서 가져오는게 더 빠름
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("doGet호출");
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
String menu_member=(String)context.getAttribute("menu_member"); //객체에서 가져오기
String menu_order=(String)context.getAttribute("menu_order");
String menu_goods=(String)context.getAttribute("menu_goods");
...
방법2) web.xml에 설정하기
<servlet>
<servlet-name>...</servlet-name>
<servlet-class>...</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
'BackEnd > Servlet' 카테고리의 다른 글
10장. 서블릿의 필터와 리스너 기능 (0) | 2022.02.18 |
---|---|
9장. 쿠키와 세션 알아보기 (0) | 2022.02.17 |
7장. 서블릿 비즈니스 로직 처리 (0) | 2022.02.15 |
6장. 서블릿 기초 (0) | 2022.02.14 |
5장. 서블릿 이해하기 (0) | 2022.02.13 |
Comment