Web Programming & Servlet

servlet이라는 web program의 실행순서

  1. public void init(){}
    // 초기화 메소드. 서버 기동 및 최초 접근에 한해 한 번 실행
  2. public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {}
    // 사용자 요청이 발생할 때마다 실행
  3. public void destroy(){}
    // 서비스 종료시점을 기준으로 한 번 실행

실행영역

  • 사용자 컴퓨터의 resource를 사용하는 client program - html, javascript, css, applet 등
  • 서버 컴퓨터의 resource를 사용하는 server program - servlet, jsp 등

client/server 3-tier architecture

  • client pc
  • application server
  • database server

Http 통신의 요청과 응답

HTTP의 요청 형식

HTTP의 응답 형식

HTTP 응답 코드

Java Web program 파일 구조

eclipse web project 파일구조


ㄴ이것도 war로 압축시키면 위에 자바 웹 프로그램 파일구조로 나온다

Servlet

개념

  • java의 class 구조를 기반으로 web page를 동적으로 생성하여 web 상에서 실행되는 program을 작성하는 기술
  • applet과 다르게 server의 resource를 사용하는 server쪽 프로그램이다

web server의 구동

이 순서대로 읽어서 구동한다.

Servlet Life Cycle

public void init() (또는 init(ServletConfig sc)) 

init 메소드에 의한 초기화.
web.xml파일이 실행되면서 실행되거나 or 최초 접속하는 client에 의해 실행됨

public void service(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException{}

client의 요청에 의해 실행되는 메소드이다.
콘솔 프로그램의 main() 메소드와 같은 역할을 한다.

  • service 메소드 대신에 doGet, doPost 메소드 두 개로 나눠서 작성할 수도 있음
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException{}

public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException{}

이렇게 나눠서
get 방식일 때는 doGet으로,
post 방식일 때는 doPost로 나눠서 하능고
public void destory(){}

메소드에 의한 memory 해제.
web server가 종료될 때 실행된다.

web.xml 설정 파일

<display-name> : 
보통 project명을 넣어서 어떤 project에 대한 설정 파일이다 라는 걸 명시

filter 부분 : 
어떤 페이지가 실행되기 직전이나 실행된 직후 그 사이사이에 끼워서 실행해야 하는 class가 있다면 그걸 filter로 설정할 수 있다.

<filter> : 
사이사이 실행할 class를 선언. filter 실행할 때 전달할 초기화 매개변수(<init-param>)도 담을 수 있음.

<filter-mapping> : 
이 filter가 어느 위치에서 실행될지를 잡아줌. 
예를 들어 <url-pattern>에 *.do 라고 하면 .do가 실행할 때 이 filter가 먼저 실행되고 나서 해당 serlvet으로 넘어가게 되는 것.
혹은 main.jsp 라고 설정하면 main.jsp가 실행될 때 이 filter 먼저 실행하고 넘어간다는 것.

<servlet> :
servlet 선언. <init-param>에 초기화 매개변수.
<load-on-startup> : 실행 순서 값. 0은 서버임의실행.

<servlet-mapping> :
servlet이 언제 실행할 건지.
<url-pattern>에 써줌.

<welcome-file-list> :
<welcome-file> :
기본 연결 파일.
여러 개 쓴 경우, 위에서부터 순서대로 파일을 찾는다.
하나씩 찾아봤는데 모두 없을 경우 그 떄 404 not found 오류가 남.


* 참고
여러 개를 쓸 때는

filter 여러 개
filter-mapping 여러 개
servlet 여러 개
servlet-mapping 여러 개

이 순서를 지켜줘야 한다.
web server가 인식할 수 있도록.

HttpServletRequest 클래스

  • getCookies()
    반환형 : Cookie[ ]
    요청을 하는 client에 있는 cookie를 모두 획득하여 배열형으로 반환한다.

GET 방식 & POST 방식

Get 방식의 요청

  • 주소표시줄에서 접속하려는 url을 직접 입력하는 경우
  • 링크 클릭한 경우
  • javascript의 location.href에 의해 요청 발생 경우
  • javascript의 window.open() 함수가 실행되는 경우
  • form 태그에서 get 방식일 때
  • redirect방식에 의해 웹페이지가 이동하는 경우

Post 방식의 요청

  • form 태그의 method="post" 지정
  • javascript를 통한 form method 지정
<script>
   function check_form(){
      myform.method="post";
      return true;
   }
</script>
<form name="myform" action="..." onSubmit="return check_form()">
  • servlet에서 RequestDispatcher 객체를 활용하여 다른 페이지에서 post로 넘어온 요청을 forward하는 경우
  • jsp의 forward 태그 라이브러리를 사용하여 다른 페이지에서 post로 넘어온 요청을 forward하는 경우

참고

  • forward 방식과 include 방식은 get이냐 post냐에 따라 달라짐

한글처리

Get 방식 요청의 한글처리

  1. String 클래스 이용한 문자 셋 변환
    ex)
String name = request.getParameter("name");
name = new String(name.getBytes("ISO8859_1"), "euc-kr");
  1. WAS 환경설정 파일을 통한 encoding 설정
    => tomcat의 config -> server.xml의 Connector 태그에 포트 설정 마지막에 URIEncdoing을 설정할 수 있다.
<Connector port="8080" ... URIEncoding="EUC-KR"/>

Post 방식 요청의 한글처리

  • parameter를 넘겨 받기 전 request의 encoding을 변경하여 처리 (setCharacterEncoding)
  • ServletRequest의 문자 셋 변환 메소드 사용
    ex)
request.setCharacterEncoding("EUC-KR");
String name = request.getParameter("name");

Servlet API

servlet에서 초기화 매개 변수 등록 및 사용

  1. 등록
  • web.xml에서 servlet 등록 시 init-param 태그로 초기화 매개변수 등록
  1. 사용
    방법 1) Servlet Class (HttpServlet)에서 getInitParameter(매개변수명) method를 통해 획득 후 사용

    방법 2) ServletConfig를 상속받은 다른 class나 ServletConfig 객체 생성 후 매개변수를 획득

    ㄴ getInitParameter(매개변수명) method는 ServletConfig 객체에 소속되어 있는 method임. 그리고 HttpServlet은 ServletConfig 인터페이스를 구현한 클래스이기 때문에 바로 저 method 쓸 수 있는 것.

    ㄴ 어떤 parameters가 있는지 확인하고 싶다면 아래와 같이 확인 가능

    Enumeration enu = this.getInitParameterNames();
    while(enu.hasMoreElements()){
       System.out.println((String)enu.nextElement());
    }

Response를 통한 error 출력 및 page 이동 방법

  1. sendError
  • HttpServletResponse 클래스의 method로, error page를 사용자에게 응답
  • sendError(응답코드) 혹은 sendError(응답코드, 응답메시지)
  • 일반적으로 500번대의 server error 출력
  1. sendRedirect
  • HttpServletResponse 클래스의 method로, 특정 url이나 page로 이동
  • 이동 시 현재 page까지 전달된 request의 parameter는 reset되고 web browser의 url도 이동하는 경로로 변경된다
예를 들어

String su1 = request.getParameter("su1");
String su2 = request.getParameter("su2");
int tot = 0;
try{
   int su1_int = Integer.parseInt(su1);
   int su2_int = Integer.parseInt(su2);
   tot = su1_int + su2_int;
} catch(NumberFormatException e){
   response.sendError(599, "숫자로 변환할 수 없는 데이터가 들어왔습니다.");
}
response.sendRedirect("successPage.htm");

RequestDispatcher 객체 생성, include 및 forward 방법

  1. Request Dispatcher
  • 웹 컨테이너로부터 RequestDispatcher 인터페이스 객체를 획득하여 현재 페이지 내에 다른 url이나 페이지를 포함시킬 수 있고, 또한 특정 페이지로 현재 request 정보를 유지하며 이동할 수 있다.
ServletContext context = ServletConfig객체.getServletContext();
RequestDispatcher dispatcher = context.getRequestDispatcher(포함할 페이지 or 이동할 페이지 상대경로);

//페이지 포함
dispatcher.include(request, response);
//페이지 이동
dispatcher.forward(request, response);
  • forward 사용 예시 --- 바로 위에 sendRedirect 코드 부분에서 response.sendRedirect("successPage.htm"); 대신에 쓸 코드
ServletContext context = this.getServletContext();
RequestDispatcher dispatcher = 
     context.getRequestDispatcher("/successPage.jsp?tot=" + tot);
dispatcher.forward(request, response);

---- 그리고 여기서 include를 대신 쓰고 싶으면
마지막 줄 forward 대신 include를 쓰면 된다.
summary
  • Servlet에서 해당 페이지를 실행할 때 초기화 매개변수를 전달하여 실행할 수 있음
  • HttpServletResponse의 sendError를 통해 에러 페이지로 이동, sendRedirect를 통해 특정 페이지로 이동 가능. But 값을 담을 순 없고 단순히 이동함
  • RequestDispatcher 객체를 ServletContext를 통해 생성하고 이를 통해 특정 페이지를 include하거나 해당 위치로 forward 할 수 있음

서블릿에서의 데이터 저장

  • Request 객체
  • Session 객체
  • Cookie 데이터 (cookies 라는 폴더가 있다)

데이터 저장 영역

  1. request (SerletRequest or HttpServletRequest)
  2. session (HttpSession)
  3. application (ServletContext)

추가 : .setAttribute(key, value)
획득 : .getAttribute(key)
삭제 : .remmoveAttribute(key, value)

예시
  • html
<form name="myForm" action="~~">
   <input type="text" name="first">
   마찬가지로 second, third까지 input 만듦

여기서 input에 값을 담고 submit 하면
servlet으로 간다.
그러면 servlet에서는 request.getParameter("input name 값")으로 받는다.

  • Servlet
public void doGet(HttpServletRequest ~~~~){
   String first = request.getParameter("first");
   마찬가지로 second, third
   
   그리고 request, session, application 다 이용해보자.
   
   request.setAttribute("first_req", first);
   
   HttpSession session = request.getSession();
   session.setAttribute("second_ses", second);
   
   ServletContext application = this.getServletContext();
   application.setAttribute("third_app", third);
   
   response.sendRedirect("viewData.jsp");
   
   ---
   sendRedirect는 request buffer를 비우는 것.
   그래서 결과값 보면
   first, second, third, first_req는 null이 나온다.
   ---
   
   sendRedirect 대신에 아래와 같이 forward를 사용하면..!
   
   RequestDispatcher dispatcher = 
     application.getRequestDispatcher("/viewData.jsp");
   dispatcher.forward(request, response);
  • jsp
String first = request.getParameter("first");
마찬가지로 second, third

String first_req = (String)request.getAttribute("first_req");

object 이기 때문에 String으로 형변환 해주어야 한다.

String second_ses = (String)session.getAttribute("second_ses");

String third_app = (String)application.getAttribute("third_app");
어디에 데이터를 저장해야 할지 알기

request에 데이터를 저장하면 : 연결이 유지되는 동안 유지됨
session에 데이터를 저장하면 : web browser가 종료되기 전까지 유지됨
application에 데이터를 저장하면 : server가 종료하기 전까지 유지됨. application이 꺼질 때 없어짐.

application에는 웬만하면 데이터를 안 넣음. 서버부하걸림.

쿠키 데이터

쿠키 데이터 저장
  • 쿠키 전송
    Cookie cookie = new Cookie(key, java.net.URLEncoder.encode(값, "UTF-8");
    cookie.setComment(주석);
    cookie.setPath(도메인);
    cookie.setMaxAge(유지시간(초));
    response.addCookie(cookie);

  • 개별 client의 Cookies 폴더에 파일로 저장

  • 쿠키 획득

Cookie[] cookies = request.getCookies();
for(int i = 0; i < cookies.length; i++){
   String key = cookies[i].getName();
   if(key.equals(키)){
      String value = cookies[i].getValue();
   }
}
만들어보자
  • login.jsp
<form name="loginForm" method="post" action="~~">
   <input type="text" name="id">
   <input type="text" name="pw">
   <input type="checkbox" name="idrem">
   <input type="submit" value="로그인">
  • servlet
~~ doPost(~~~){
   request.setCharacterEncoding("UTF-8"); // 한글 설정하고 싶다면. 아이디가 한글이면.
   String id = request.getParameter("id");
   pw, idrem도 마찬가지
   
   확인해보니 idrem에는 on 혹은 null 이 올 수 있다.
   
   // 우선 DBMS에서 id와 pw 확인을 한다. 가입된 사용자가 맞다면
   
   if(idrem != null && idrem.trim().equals("on")){
      Cookie cookie = new Cookie("id", id); //아이디가 영어일 때 그냥 id로 넣으면 댐
      cookie.setMaxAge(60*60*24*365); // 1년동안 유지
      response.addCookie(cookie);
   } else {
      Cookie cookie = new Cookie("id", id);
      cookie.setMaxAge(0);
      
      response.addCookie(cookie);
   }
   response.sendRedirect("main.htm");   

여기까지 하면 cookie 저장은 한 거고
아이디 비번이 세팅되려면 쿠키를 가져와야 한다.

  • 위에 쓴 login.jsp에 추가
맨 위에 <% page ~~~> 아래에 추가
<%
Cookie[] cookies = request.getCookies();
String id = "";
if(cookies != null){
   for(int i = 0; i < cookies.length; i++){
      String key = cookies[i].getName();
      if(key != null && key.trim().equals("id")){
         id = cookies[i].getValue();
         break;
      }
   }
}
%>

그리고 body에 input 태그 안에 추가한다.

id input에 value="<%=id%>" 추가

그리고 체크박스도 자동으로 체크되도록 하려면
input type checkbox에 추가
<% if(id.length() != 0) out.println("checked");%>

파일 입출력

#66

  • 파일 I/O 방법
  • 파일 업로드 방법
  • DBMS 연동

서블릿에서의 파일 I/O

  • 서버에 저장될 파일의 경로
ServletContext context = ServletConfig객체.getServletContext();
String real_path = context.getRealPath("/");
현재 프로젝트의 실제 경로임
  • OutputStream을 통한 1 byte data 전송

  • Writer를 통한 2 byte data 전송

  • ObjectOutputStream을 통한 객체 전송

  • CountServlet.java

private int cnt = 0;
init(){
   String dir = this.getInitParameter("countDirectory"); //web.xml에 설정한 초기화 매개변수
   String fileName = this.getInitParameter("countFile");
   ServletContext context = this.getServletContext();
   String real_path = context.getRealPath("/");
   try {
      File dir_file = new File(real_path, dir);
      if(!dir_file.exists()){
         dir_file.mkdir();
      }
      File dir_file = new File(dir_file, fileName);
      if(file_file.exists()){
         DataInputStream dis = new DataInputStream(
            new BufferedInputStream(new FileInputStream(file_file)));
         cnt = dis.readInt();
         dis.close();
      } else{
         file_file.createNewFile();
      }
   }catch(Exception e) {}
 
 
 
service(){
   cnt++;
   
   response.setCharacterEncoding("euc-kr");
   PrintWriter out = response.getWriter();
   out.println("<html><body><center>");
   out.println("당신은" + cnt + "번째 방문자이십니다.");
   out.println("</center></body></html>");
   
   out.flush();


destroy(){
   String dir = this.getInitParameter("countDirectory"); //web.xml에 설정한 초기화 매개변수
   String fileName = this.getInitParameter("countFile");
   ServletContext context = this.getServletContext();
   String real_path = context.getRealPath("/");
   try {
      File dir_file = new File(real_path, dir);
      if(!dir_file.exists()){
         dir_file.mkdir();
      }
      File dir_file = new File(dir_file, fileName);
      if(file_file.exists()){
         DataOutputStream dos = new DataOutputStream(
            new BufferedOutputStream(new FileOutputStream(file_file)));
         dos.writeInt(cnt);
         dos.close();
      } else{
         file_file.createNewFile();
      }
   }catch(Exception e) {}

파일 업로드

  • client program (html 등)
<form method="post" action="처리서블릿" enctype="multipart/form-data">
<input type="file" name="">

method post와
enctype multipart 가 중요하다!
  • file upload servlet에 쓸 파일업로드 api 다운로드 필요
  • jakarta.apache.org > commons > fileupload > 버전별로 있음 > download > lib > 1.3.jar 복사 > webcontent > lib 폴더에 넣기 > add to buildpath 해서 라이브러리에 등록
  • 그리고 io > commons io 도 다운로드하고 똑같이 하기



DBMS 연계

  • tomcat의 DBCP를 활용한 DBMS Connection 객체 생성

  • ConnectionServlet.java
Context context = new InitialContext();
DataSource ds = (DataSource) context.lookup("java:comp/env/jdbc/myconn");
Connection conn = ds.getConnection();

/*
PreparedStatement pstmt = conn.prepareStatement(query);
pstmt.setString(1, "");
ResultSet rs = pstmt.executeQuery();
*/

이미지, 사운드, 응용프로그램의 데이터

  • MIME을 설정하여 원하는 형식으로 데이터 출력
  • 서블릿 이용하여 각 이미지, 응용프로그램별로 출력
  • 동적인 이미지 생성

MIME

  • Multipurpose Internet Mail Extensions
response.setContentType("application/octet-stream"); //파일 다운로드
response.setHeader("Content-Disposition", "attachment;filename=파일명.확장자");

동적 차트

JPEGImageEncoder
  • 자바에서 자체적으로 지원하는 이미지 변환 클래스

  • 예시

BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();

// g.draw...

response.setContentType("image/jpeg");
ServletOutputStream out = response.getOutputStream();
JPEGImageEncoder encode = JPEGCodec.createJPEGEncoder(out);
encode.encode(img);

g.dispose();
  • 참고 : JFreeChart 처럼 동적 차트를 구성할 때 사용하는 open source API도 있음

서블릿 필터

  • web program에서 filter를 설정하고 filter class 생성
  • servlet의 event class를 작성하고 실행

Filter

  • 개념 : 어떤 클래스나 페이지가 동작하기 전에 데이터 포함해서 가로채서 어떠한 동작을 먼저 해주고 그 다음에 넘어갈 수 있도록 하는 것

  • 웹 상에서 사용자 요청 페이지가 실행하기 전/후 필요에 의해 데이터 가로채 작업

  • ex) 전달받은 데이터를 인코딩하는 경우, session 데이터 인증하는 경우, 이벤트나 공지 등 팝업 추가하는 경우

  • 필터 인터페이스를 구현하는 클래스로 작성 후 필터를 web.xml에 등록

  • filter의 life cycle

class 클래스명 implements Filter{
   public void init(FilterConfig fc)
   public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain){
      // 필터작업
      chain.doFilter(req, res);
   }
   public void destroy
  • web.xml에 등록하는 부분은 => 위에 내가 정리한 내용 중 "web.xml 설정 파일" 참고

  • 예를 들어 로그인 되어있는지 확인하고 넘어가고 싶을 때 사용

ublic void doFilter(ServletRequest req, ServletResponse res, FilterChain chain){
      HttpServletRequest h_req = (HttpServletRequest) req;
      HttpSession h_ses = h_req.getSession();
      
      String uri = h_req.getRequestURI();
      if(uri.indexOf("LoginProcess.do")<0){ //로그인 프로세스가 아닐 때만 필터가 실행하도록
         String id = (String)h_ses.getAttribute("id");
         if(id==null || id.trim().length()==0){
            HttpServletResponse h_res = (HttpServletResponse)res;
            h_res.sendRedirect("/login.htm");
            return;
         // 아이디가 없는 경우 즉 로그인이 안되어있는 경우 로그인 페이지로 가도록 필터가 작업하는 것
         }
      }
      chain.doFilter(req, res);
   }

서블릿 이벤트

  • server가 실행된 이후 특정 이벤트를 감지하여 그 시점에 작업을 하고자 하는 경우 (아주 많진 않음)
  • ex) context가 초기화되는 경우, session이 생기거나 소멸되는 경우, 속성이 바뀌는 경우
  • 서블릿 이벤트 리스너
  • 서블릿 이벤트 등록 : web.xml (필터보다 위에 등록)

Servlet과 Applet 간의 데이터 전송

  • applet내부에서 servlet으로 요청 보냄 -> 결과값 받아서 다시 applet에서 데이터를 띄우는 걸 해보겠습니당

servlet

  • server 측의 program

applet

  • client 측의 program

data 전송

  • 다른 측의 program이기 때문에 각 실행 영역이 달라 직접 실행을 호출할 수 없다.
  • applet은 html페이지 내에 포함되어 실행하도록 구성하고 해당 applet에서 (web url을 통해) servlet을 호출하여 결과를 받아와 출력하도록 구성하여 연동 실행
예시
  • 이름 입력받는 html page 작성
  • 이름 전송받아 그걸 매개변수로 하는 applet을 작성한 후 servlet에 포함
  • applet이 실행되면서 또 다른 servlet으로 이름과 이름의 길이값 전송
  • 해당 servlet에서 이름과 길이를 받아 저장 후 결과를 applet으로 다시 전송
  • applet은 돌아온 결과를 화면에 표시

-html

<form ~
   <input ~ name="name">
   ~
  • view applet serlvet.java
doPost(~~~){
   request.setCharacterEncoding("euc-kr");
   String name = request.getParameter("name");
   
   response.setCharacterEncoding("euc-kr");
   PrintWriter out = response.getWriter();
   out.println("<html><body><center>");
   out.println("<applet code='MyApplet.class' width='300' height='200'");
   out.println("<param name='name' value='" + name + "'/>");
   out.println("</applet>");
   out.println("</center></body></html>");
   
   // 이렇게 하묜 myapplet.class를 html 과 동일한 위치로 파일을 이동시켜야 된당 인식하도록
  • MyApplet.java
private String name;
init(){
   name = this.getParameter("name");
}
start(){}
paint(Graphics g){
   g.drawString(name, 100, 100); //servlet의 param name 이 여기로
}
stop(){}
destroy(){} 

#75
  • servlet이 applet 내부의 동작을 요청하기 위해서는 또 다른 network 통신을 사용해야 한다.

JSP

  • jsp 파일을 실행할 때 생성되는 파일에 대해 이해한다
  • jsp 파일의 life cycle을 이해한다
  • jsp 파일을 구성하는 요소를 안다

jsp 파일 생성

  • jsp 파일을 생성하여 최초 실행 시 해당 파일이 servlet 형태의 java 파일로 변환되어 server의 work 폴더에 생성된다.

jsp 파일의 life cycle

  • 해당 jsp file은 servlet으로 변환 시 HttpJspBase class를 상속하고, 구현 내용으로 jsp 파일의 life cycle인 jspInit() -> _jspService(request, response) -> jspDestroy()를 포함한다.

jsp 파일의 구성요소

  • jsp 파일 영역별 구성 요소들
  • ex)
page 원소를 선언하는 영역
taglib 원소를 선언하는 영역
[
  include 원소 : <%@ include ~ %>
  템플릿 데이터 : html, xml, javascript, css 등
  선언 : <%! ~ %>
  식 : <%= ~ %>
  스크립트 렛 : <% ~ %>
  액션원소 : <jsp:xxx ~ />
  EL / JSTL / 사용자 정의 태그 등
]

jsp 파일에서 사용되는 다양한 주석처리 방법

주석

  • html, xml, style sheet 외부 :
<!-- OOO -->
  • javascript 외부
<!-- OOO // -->
  • javascript 내부, java, 스크립트렛, 선언, 식
한 줄 주석 : // (식에서는 사용 불가)
여러 줄 주석 : /* OOO */
  • jsp
<%-- OOO --%>

jsp default 객체

  • jsp 파일에서 사용할 수 있는 디폴트 객체 학습
  • default 객체 중 data 저장과 관련된 객체들을 servlet과 비교하여 이해

좋은 웹페이지 즐겨찾기