포스트

Day65 실습프로젝트(Servlet)

Servlet

ListServlet 만들기

  • init(ServletConfig config)
    • 생성자 역할을 대신하는 메서드로 클래스 구동에 필요한 서버정보를 호출 한다.
    • ServletConfig에는 리스너에서 담았던 Context객체가 담겨있다.
  • service(ServletRequest req, ServletResponse res)
    • 서블릿컨테이너에서 해당 클래스를 호출하면 실행되는 메서드이다.
    • 웹브라우저가 받을 정보는 res에서, 웹브라우저에서 가져올 정보는 req로 받는다.
    • res.setContentType(MIME;CharaterSet)으로 출력 인코딩을 설정한다.
    • PrintWriter out = res.getWriter()으로 출력 스트림을 생성한다.
    • 동적 HTML을 작성해서 Out 스트림에 보낸다.

HTML문서에서 링크 만들기

  • 태그에 링크를 연결하기 위해서는 <a href="url">내용</a>를 작성한다.
  • 내용을 클릭하면 설정한 url로 이동한다.

    image

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    
    @WebServlet("/user/list")
    public class UserListServlet implements Servlet {
      
      private ServletConfig config;
      private UserDao userDao;
      
      @Override
      public void init(ServletConfig config) throws ServletException {
        // 서블릿 객체를 생성한 후 바로 호출됨(물론, 생성자가 먼저 호출된다.)
        // 서블릿이 작업할 사용할 의존 객체를 준비하는 일을 이 메서드에서 수행한다.
        this.config = config;
      
        ServletContext ctx = config.getServletContext();
        userDao = (UserDao) ctx.getAttribute("userDao");
      }
      
      @Override
      public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        // 웹브라우저에서 이 서블릿을 실행해달라고 요청이 들어오면 이 메서드가 호출된다.
        // 누가 호출하는가? 서블릿 컨테이너가 호출한다.
      
        // 출력할 콘텐트의 타입을 먼저 지정한 후 출력 스트림을 얻는다.
        res.setContentType("text/html;charset=UTF-8");
      
        // 출력 콘텐트를 어떤 문자집합으로 인코딩 할 지 지정하지 않고 출력 스트림을 꺼내면
        // 출력 문자열(UTF-16BE)은 ISO-8859-1 문자집합에 맞춰 인코딩된다.
        // 만약 UTF-16BE 에 있는 문자가 ISO-8859-1에 정의되어 있지 않다면,
        // '?' 문자로 변환된다.
        PrintWriter out = res.getWriter();
        out.println("<!DOCTYPE html>");
        out.println("<html>");
        out.println("<head>");
        out.println("    <meta charset='UTF-8'>");
        out.println("    <title>Title</title>");
        out.println("    <link href='/css/common.css' rel='stylesheet'>");
        out.println("</head>");
        out.println("<body>");
      
        try {
          out.println("<header>");
          out.println("  <a href='/'><img src='/images/home.png'></a>");
          out.println("        프로젝트 관리 시스템");
          out.println("</header>");
          out.println("<h1>회원 목록</h1>");
          out.println("<p><a href='/user/form.html'>새 회원</a></p>");
          out.println("<table>");
          out.println("  <thead>");
          out.println("      <tr><th>번호</th><th>이름</th><th>이메일</th></tr>");
          out.println("  </thead>");
          out.println("  <tbody>");
      
          for (User user : userDao.list()) {
            out.printf("      <tr><td>%d</td><td><a href='/user/view?no=%1$d'>%s</a></td><td>%s</td></tr>\n",
                user.getNo(), user.getName(), user.getEmail());
          }
      
          out.println("  </tbody>");
          out.println("</table>");
        } catch (Exception e) {
          out.println("<p>목록 조회 중 오류 발생!</p>");
        }
      
        out.println("</body>");
        out.println("</html>");
      }
      
      @Override
      public void destroy() {
        // 서블릿 컨테이너가 종료되기 전에 해제할 자원이 있다면 이 메서드에서 수행한다.
      }
      
      @Override
      public String getServletInfo() {
        // 서블릿 컨테이너 관리 화면에서 서블릿을 정보를 출력할 때 이 메서드가 호출된다.
        // 서블릿에 대한 간단한 정보를 문자열로 리턴하면 된다.
        return "회원 목록 조회";
      }
      
      @Override
      public ServletConfig getServletConfig() {
        // 서블릿의 정보를 조회할 때 사용할 ServletConfig 객체를 리턴해 준다.
        // 이 메서드가 리턴할 ServletConfig 객체는
        // init() 메서드가 호출될 때 파라미터로 넘어온 객체다.
        // 따라서 init() 메서드가 호출될 때 ServletConfig 객체를 보관해 둬야 한다.
        return this.config;
      }
    }
      
    


ViewServlet 만들기

  • GenericServlet을 상속받아서 클래스를 작성한다.
  • init() : init(ServletConfig config)을 호출하면 다시 init()을 호출한다.
    • GenericServlet에서는 config외 호출 할 정보를 이 메서드에 작성하면 된다.
    • GenericServlet에서는 ServletContext객체도 서블렛 컨테이너로 부터 받아오기 때문에 getServletContext을 통해 ctx를 만들수 있다.
  • service(ServletRequest req, ServletResponse res)
    • res로 출력 인코딩과 출력 스트림을 생성한다.
    • req를 통해 조회할 no를 받아온다.
    • 웹브라우저에서 /user/view?no=xx를 컨테이너에 request하면 컨테이너는 /user/view url을 가진 클래스를 호출 하고 no를 매개변수로 넘긴다.

    image

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    
    @WebServlet("/user/view")
    public class UserViewServlet extends GenericServlet {
      
      private UserDao userDao;
      
      @Override
      public void init() throws ServletException {
        // 서블릿 컨테이너 ---> init(ServletConfig) ---> init() 호출한다.
        userDao = (UserDao) this.getServletContext().getAttribute("userDao");
      }
      
      @Override
      public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        res.setContentType("text/html;charset=UTF-8");
      
        PrintWriter out = res.getWriter();
        out.println("<!DOCTYPE html>");
        out.println("<html>");
        out.println("<head>");
        out.println("    <meta charset='UTF-8'>");
        out.println("    <title>Title</title>");
        out.println("    <link href='/css/common.css' rel='stylesheet'>");
        out.println("</head>");
        out.println("<body>");
      
        try {
          out.println("<header>");
          out.println("  <a href='/'><img src='/images/home.png'></a>");
          out.println("        프로젝트 관리 시스템");
          out.println("</header>");
          out.println("<h1>회원 조회</h1>");
      
          int userNo = Integer.parseInt(req.getParameter("no"));
      
          User user = userDao.findBy(userNo);
          if (user == null) {
            out.println("<p>없는 회원입니다.</p>");
            out.println("</body>");
            out.println("</html>");
            return;
          }
      
          out.printf("<p>이름: %s</p>\n", user.getName());
          out.printf("<p>이메일: %s</p>\n", user.getEmail());
          out.printf("<p>연락처: %s</p>\n", user.getTel());
      
        } catch (Exception e) {
          out.println("<p>조회 중 오류 발생!</p>");
        }
      
        out.println("</body>");
        out.println("</html>");
      }
    }
      
    


AddServlet 만들기

form.html만들기

  • 정적HTMl을 만들어서 브라우저에 보낼수도 있다.
  • 이는 webserver에서 관리를 하는 페이지이기 때문에 webapp에서 작성을 한다.
  • <form atction="url" method="GET|POST"> : 폼이 완료되면 액션 메서드가 실행된다.
    • method=”GET”: 데이터가 URL의 쿼리 스트링(예: ?name=value)으로 전송된다.
    • method=”POST”: 데이터가 HTTP 요청의 본문에 포함되어 전송된다.
  • <link href="url" rel='stylesheet"> : 해당 url경로에 있는 stylesheet을 찾아서 연결한다.
  • <input name="name" type="type"> : 입력창을 만드는 태그이다.
    • name : 태그가 req로 반환될 때 파라미터 명이다.
    • type : 입력받을 type이며, type에 따라 입력창이 다르게 출력된다. (특히 모바일)
  • <input type="submit" value="등록"> : 입력창을 만드는 태그이고, 클릭하면 폼의 액션이 호출된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link href="/css/common.css" rel="stylesheet">
    </head>
    <body>
        <header>
            <a href="/"><img src="/images/home.png"></a>
            프로젝트 관리 시스템
        </header>
        <h1>회원 등록</h1>
        <form action="/user/add">
            이름: <input name="name" type="text"><br>
            이메일: <input name="email" type="email"><br>
            암호: <input name="password" type="password"><br>
            연락처: <input name="tel" type="tel"><br>
            <input type="submit" value="등록">
        </form>
    </body>
    </html>
    


AddServlet만들기

  • form action이 실행되면 action에 설정된 url의 servlet이 실행된다.
  • AddServlet을 동적으로 HTML을 생성하여 req의 파라미터를 받아온다.
  • query string에서 값을 받아오는 방법은 다음과 같다.

    image

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        res.setContentType("text/html;charset=UTF-8");
        PrintWriter out = res.getWriter();
      
        req.getRequestDispatcher("/header").include(req, res);
      
        try {
          out.println("<h1>회원 등록 결과</h1>");
      
          User user = new User();
          user.setName(req.getParameter("name"));
          user.setEmail(req.getParameter("email"));
          user.setPassword(req.getParameter("password"));
          user.setTel(req.getParameter("tel"));
      
          userDao.insert(user);
          sqlSessionFactory.openSession(false).commit();
          out.println("<p>등록 성공입니다.</p>");
      
        } catch (Exception e) {
          sqlSessionFactory.openSession(false).rollback();
          out.println("<p>등록 중 오류 발생!</p>");
        }
      
        out.println("</body>");
        out.println("</html>");
      
        ((HttpServletResponse) res).setHeader("Refresh", "1;url=/user/list");
      }
    


URL

  • URI (Uniform Resource Identifier) : URI는 인터넷에 있는 자원의 식별자이다. 웹 상의 자원(문서, 이미지, 파일 등)을 식별하고 위치를 나타내는 데 사용된다. URI는 일반적으로 URL과 URN을 포함하는 상위 개념이다.
  • URN (Uniform Resource Name) : URN은 자원의 이름을 식별하는 URI의 일종이다. URN은 자원의 위치에 의존하지 않고, 그 자원의 고유한 이름을 나타낸다.
  • URL (Uniform Resource Locator) : URL은 자원의 위치를 식별하는 URI의 일종이다. URL은 자원의 접근 방법(프로토콜)과 그 자원이 위치한 장소를 나타낸다.

    image

URL인코딩

image

project member 받아오기

  • project member를 받아오기 위해서는 form이 동적으로 생성되어야한다.
  • <input name='member' value='%d' type='checkbox'>를 통해 AddServlet에 user_id를 파라미터로 전달한다.

    1
    2
    3
    4
    5
    6
    7
    
    out.println("        <ul>");
    List<User> users = userDao.list();
    for (User user : users) {
      out.printf("          <li><input name='member' value='%d' type='checkbox'> %s</li>\n",
              user.getNo(), user.getName());
    }
    out.println("        </ul>");
    
  • AddServlet에서는 req.getParameterValuse("memeber")을 통해서 user_id의 배열 받아온다.

    1
    2
    3
    4
    5
    6
    7
    8
    
    String[] memberNos = req.getParameterValues("member");
    if (memberNos != null) {
      ArrayList<User> members = new ArrayList<>();
      for (String memberNo : memberNos) {
        members.add(new User(Integer.parseInt(memberNo)));
      }
      project.setMembers(members);
    }
    


loginServlet 만들기

  • BoardAddServlet에 작성자를 저장하기 위해서는 LoginServlet이 필요하다.
  • 로그인을 하는 Form을 만들어 LoginServlet에게 값을 전달한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link href="/css/common.css" rel="stylesheet">
    </head>
    <body>
        <header>
            <a href="/"><img src="/images/home.png"></a> 프로젝트 관리 시스템
        </header>
        <h1>로그인</h1>
        <form action="/auth/login">
            이메일:<input name="email" type="email"><br>
            암호:<input name="password" type="password"><br>
            <input type="submit" value="로그인">
        </form>
    </body>
    </html>
    
  • LoginServlet에서 로그인정보를 Session에 저장한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    String email = req.getParameter("email");
    String password = req.getParameter("password");
    
    User user = userDao.findByEmailAndPassword(email, password);
    if (user == null) {
      out.println("<p>이메일 또는 암호가 맞지 않습니다.</p>");
      out.println("</body>");
      out.println("</html>");
      ((HttpServletResponse) res).setHeader("Refresh", "1;url=/auth/form");
      return;
    }
    
    // HTTP 프로토콜 관련 기능을 사용하려면
    // 파라미터로 받은 ServletRequest 객체를 원래 타입으로 형변환 해야 한다.
    // 즉 req 레퍼런스는 실제 HttpServletRequest 객체를 가리키고 있다.
    HttpServletRequest httpReq = (HttpServletRequest) req;
    
    // 클라이언트 전용 보관소를 알아낸다.
    HttpSession session = httpReq.getSession();
    
    // 클라이언트 전용 보관소에 로그인 사용자 정보를 보관한다.
    session.setAttribute("loginUser", user);
    
    out.println("<p>로그인 성공입니다!</p>");
    
  • BoardAddServlet에서는 Session의 로그인 유저를 꺼내온다.

    1
    2
    
    User loginUser = (User) ((HttpServletRequest) req).getSession().getAttribute("loginUser");
    board.setWriter(loginUser);
    


이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.