본문 바로가기
내가 공부하려고 올리는/JSP\Servlet

[JSP 게시판] Model 2 JSP/Servlet 게시판 만들기(1) - 웰컴페이지 구현/filter/encoding

by 결딴력 2022. 1. 14.
반응형

들어가기 앞서

  • JSP/Servlet을 활용한 MVC Model2 게시판에 관한 내용입니다.
  • 구현 기능 : 로그인, 로그아웃, 회원가입, 글쓰기, 글 수정, 글 삭제

 

MVC란?

 

- MVC는 Model/View/Controller의 약자입니다.

- MVC는 위 3가지로 이루어진 '디자인 패턴'을 말합니다.

 

 

Model 1이란?

 

- Model 1은 View와 Controller가 분리되지 않은 형식을 말합니다.

- 모델 1 예시

모델1 구조

- 모델 1은 크게 JSP랑 Java Bean(Model)으로 구성됩니다.

- JSP에서 사용자 요청에 대한 응답을 처리하고 Model에 DB정보를 요청합니다.

- Model이 요청에 따라 데이터베이스에 접근하여 데이터를 처리합니다.

- 처리된 요청을 View 페이지에서 처리해 사용자에게 응답합니다.

 

 

Model 2란?

 

- Model 1에서 View와 Controller를 분리한 것을 의미합니다.

- 모델 2 예시

모델2 구조

- 모델 1과 달리 사용자의 요청에 따른 응답은 Controller(Servlet)가 담당합니다.

- 컨트롤러는 요청 정보를 Model에게 전달합니다.

- Model이 요청에 따라 데이터베이스에 접근하여 데이터를 처리합니다.

- 처리한 요청을 View(JSP)에게 전달하여 사용자에게 응답합니다.

- 본 프로젝트에서는 컨트롤러의 요청을 데이터베이스에 전달하거나,

  처리된 데이터를 View에 전달할 때 Action 클래스를 만들어 Action 클래스가 처리하도록 구현했습니다.

  (Action 클래스에 대한 내용은 후술 하겠습니다.)

 

 

main.jsp

 

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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    
<html>
    <head>
    <title>메인 화면</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="${pageContext.request.contextPath}/css/bootstrap.min.css"> <!-- 부트스트랩  css -->
    <style>
        #wrap {
            width: 800px;
            margin: 0 auto 0 auto;
            background-color: #f5f5f5;
        }
        
        #header {
            text-align: center;
            width: 800px;
            height: 150px;
            padding: 60px 0px;
        }
        
        #main {
            float: left;
            width: 800px;
            height: 500px;
            text-align:center;
            vertical-align: middle;
        }
    </style>
    </head>
    <body>
        <jsp:include page="header.jsp" /> <!-- header page 공통적으로 포함 -->
        
        <c:set var="contentPage" value="${param.contentPage}"/> <!-- 파라미터로 전달된 contentPage 받아오기 -->
            <c:if test="${contentPage==null}">
                <jsp:include page="firstView.jsp" /> <!-- 전달된 contentPage가 없다면  -->
            </c:if>
        
        <jsp:include page="${contentPage}"/> <!-- 전달된 contentPage가 있다면 -->      
    </body>
    
    <script src="${pageContext.request.contextPath}/js/jquery-3.6.0.min.js"></script> <!-- jQuery -->
    <script type="text/javascript" src="${pageContext.request.contextPath}/js/bootstrap.js"></script> <!-- 부트스트랩 js -->
</html>
 
cs

 

- 가장 처음 사용자에게 보일 main 페이지입니다.

- 모든 페이지 구현은 부트스트랩과 jQuery 라이브러리를 사용해 만들었습니다.

- CDN 방식이 아닌 다운로드 방식을 이용했습니다.

- 사용한 부트스트랩 버전은 5.1.3, jQuery 버전은 3.6.0입니다.

- 각 파일의 절대 경로를 이용하기 위해

  ${pageContext.request.contextPath}를 앞에 붙여줍니다.

 

부트스트랩 5.1.3

 

- 다운로드한 부트스트랩은 WebContent 폴더 아래에 추가해줍니다.

- js 폴더 안에 다운로드한 jQuery 파일을 추가합니다.

 

jQuery 3.6.0

 

- 기본적으로 페이지를 [Header]와 [Content]로 구성합니다.

- 따라서 [Header] 페이지는 기본적으로 화면에 추가해줍니다.(34번째 줄)

- 전달받은 Content가 있으면 헤더 아래에 Content를

  전달받은 Content 페이지가 없다면 헤더 아래에 firstView.jsp를 추가해줍니다.(36~41번째 줄)

- 위 기능을 구현하기 위해 JSTL을 사용합니다.

- JSTL을 사용하기 위해 라이브러리를 다운로드하여 'WEB-INF\lib' 에 추가해줍니다.

JSTL 라이브러리

 

- ojdbc8과 cos는 다음에 후술 하겠습니다.

- 해당 페이지에 대한 응답 화면은 다음과 같습니다.

 

 

header.jsp

 

- 공통적으로 화면에 출력될 header 페이지를 구현해보겠습니다.

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
89
90
91
92
93
94
95
96
97
98
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!doctype html>
<html lang="en">
  <head>
    <style>
      .bd-placeholder-img {
        font-size: 1.125rem;
        text-anchor: middle;
        -webkit-user-select: none;
        -moz-user-select: none;
        user-select: none;
      }
 
      @media (min-width: 768px) {
        .bd-placeholder-img-lg {
          font-size: 3.5rem;
        }
      }
      a {
          cursor: pointer;
      }
    </style>
    
    <script type="text/javascript">
        function changeView(value){
            
            if(value == "0"// HOME 버튼 클릭시 첫화면으로 이동
            {
                location.href="main.do";
            }
            else if(value == "1"// 로그인 버튼 클릭시 로그인 화면으로 이동
            {
                location.href="LoginForm.do";
            }
            else if(value == "2"// 회원가입 버튼 클릭시 회원가입 화면으로 이동
            {
                location.href="SignUpForm.do";
            }
            else if(value == "3"// 회원정보 버튼 클릭시 회원정보 상세보기 화면으로 이동
            {
                location.href="PwdCheckForm.do";
            }
            else if(value == "4"// 로그아웃 버튼 클릭시 로그아웃 처리
            {
                location.href="MemberLogoutAction.do";
            }
            else if(value == "5"// 보드 버튼 클릭시 보드 게시판 화면으로 이동
            {
                location.href="BoardListAction.bo";
            }
        }
    </script>
 
    <link href="css/navbar-top-fixed.css" rel="stylesheet">
      </head>
      <body>
        <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
            <div class="container-fluid">
                <a class="navbar-brand" onclick="changeView(0)">JSP 웹페이지</a>
                <button class="navbar-toggler"  type="button" data-bs-toggle="collapse" 
                data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" 
                aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarCollapse">
                    <ul class="navbar-nav me-auto mb-2 mb-md-0">
                    <li class="nav-item">
                    <a class="nav-link active" aria-current="page" href="main.do">Home</a>
                    </li>
                    <li class="nav-item">
                    <a class="nav-link" onclick="changeView(5)">Board</a>
                    </li>
                    </ul>
                    <div class="dropdown">
                        <button class="btn btn-secondary dropdown-toggle" type="button" 
                        id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
                             Menu
                        </button>
                        <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
                            <!-- // 로그인 안되었을 경우 - 로그인, 회원가입 버튼을 보여준다. -->
                            <c:if test="${sessionScope.memberID==null}">
                                <li><a id="loginBtn" class="dropdown-item" onclick="changeView(1)">로그인</a></li>
                                <li><a id="joinBtn" class="dropdown-item" onclick="changeView(2)">회원가입</a></li>
                            </c:if>
                            <!-- // 로그인 되었을 경우 - 회원정보, 로그아웃 버튼을 보여준다. -->
                            <c:if test="${sessionScope.memberID!=null}">
                                <li><a id="loginBtn" class="dropdown-item" onclick="changeView(3)">회원정보</a></li>
                                <li><a id="loginBtn" class="dropdown-item" onclick="changeView(4)">로그아웃</a></li>
                            </c:if>
                        </ul>    
                    </div>
                </div>
            </div>
        </nav>
    </body>
</html>
cs

- 화면 상단에는 게시판 이동 버튼, 홈 버튼이 존재합니다.

- 로고, 홈 버튼을 누를 경우 "main.do" url을 요청합니다.(29~32, 70번째 줄)

- .do에 관한 내용은 후술 하겠습니다.

- 로그인을 하지 않았을 경우 '로그인', '회원가입' 버튼을,

  로그인을 했을 경우 '로그아웃', '회원정보' 버튼을 활성화합니다.(83~90번째 줄)

- ${sessionScope.memberID == null}을 사용해 로그인 정보를 확인합니다.

  세션을 확인하여 memberID 값이 세팅되어있는지 확인합니다.(자세한 내용은 후술)

 

 

firstView.jsp

 

- welcom 페이지인 firstView.jsp를 구현합니다.

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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 
<!DOCTYPE html>
<html lang="en">
    <head>
        <style>
        .bd-placeholder-img {
            font-size: 1.125rem;
            text-anchor: middle;
            -webkit-user-select: none;
            -moz-user-select: none;
            user-select: none;
        }
        
        @media (min-width: 768px) {
            .bd-placeholder-img-lg {
            font-size: 3.5rem;
            }
        }
        </style>
        
        <script type="text/javascript">
            function changeFirstView(value) {
                if(value == 0
                {
                    location.href = "SignUpForm.do";
                } 
                else if(value == 1)
                {
                    location.href = "LoginForm.do";
                } else if(value == 2
                {
                    location.href = "BoardListAction.bo"//아직 미구현
                } else if(value == 3
                {
                    const link = "https://determination.tistory.com/";
                    window.open(link);
                }
            }
        </script>
    </head>
    <body>
        <h1 class="visually-hidden">Heroes examples</h1>
        <!-- 세션에 id 값이 널이면?(로그인이 안되어 있으면) -->
        <c:if test="${sessionScope.memberID==null}">
            <div class="px-4 py-5 my-5 text-center">
                <img class="d-block mx-auto mb-4" src="${pageContext.request.contextPath}/docs/5.1/assets/brand/bootstrap-logo.svg" alt="" width="72" height="57">
                <h1 class="display-5 fw-bold">방문을 환영합니다!</h1>
                <div class="col-lg-6 mx-auto">
                    <p class="lead mb-4">게시판에 글을 남기고 댓글을 남겨주세요!
                        <br> 게시판에 글을 남기기 위해서는 회원가입과 로그인이 필요합니다.
                    </p>
                    <div class="d-grid gap-2 d-sm-flex justify-content-sm-center">
                        <button type="button" class="btn btn-primary btn-lg px-4 gap-3" onclick="changeFirstView(0)">회원가입 하러가기</button>
                        <button type="button" class="btn btn-outline-secondary btn-lg px-4" onclick="changeFirstView(1)">로그인 하러가기</button>
                    </div>
                </div>
            </div>
        </c:if> 
        <!-- 세션에 id 값이 있으면?(로그인이 되어 있으면) -->  
        <c:if test="${sessionScope.memberID!=null}">
            <div class="px-4 py-5 my-5 text-center">
                <img class="d-block mx-auto mb-4" src="${pageContext.request.contextPath}/docs/5.1/assets/brand/bootstrap-logo.svg" alt="" width="72" height="57">
                <h1 class="display-5 fw-bold">${sessionScope.memberID}님 환영합니다!</h1>
                <div class="col-lg-6 mx-auto">
                    <p class="lead mb-4">게시판에 글을 남기고 댓글을 남겨주세요!
                        <br> 해당 게시판에 관한 내용은 블로그를 통해 확인할 수 있습니다.
                    </p>
                    <div class="d-grid gap-2 d-sm-flex justify-content-sm-center">
                        <button type="button" class="btn btn-primary btn-lg px-4 gap-3" onclick="changeFirstView(2)">게시판 바로가기</button>
                        <button type="button" class="btn btn-outline-secondary btn-lg px-4" onclick="changeFirstView(3)">블로그 바로가기</button>
                    </div>
                </div>
            </div>
        </c:if>    
    </body>
</html>
 
cs

- JSTL을 활용해 로그인이 되었을 때와 안 되었을 때를 구분하여 firstView.jsp를 구현합니다.

- 세션에 memberID 값이 있는 경우 memberID 정보를 출력합니다.(63~73번째 줄)

- 로그인 정보가 없을 경우 회원가입/로그인 화면을
  로그인 정보가 있을 경우 게시판/블로그 화면을 구성합니다.

 

- 실제 화면 예시

로그인 정보가 없을 경우 웰컴 페이지

 

로그인 했을 경우 웰컴 페이지

 

 

 

Filter

- 글을 마무리하기전에 POST 방식에 대한 인코딩 방식을 알아보겠습니다.

- 모든 글에 인코딩 방식을 지정해주지 않고 Filter를 사용해 모든 경로에 대해 동일한 인코딩 방식을 지정해줬습니다.

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
package jsp.filter;
 
import java.io.IOException;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
 
@WebFilter("/*")
public class EncodingFilter implements Filter{
    //필터 초기화
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }
    
    //필터가 실행할 메서드
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    }
    
    
}
 
cs

- 필터의 경우 하나의 페이지에서 다른 페이지로 전달되는 데이터 사이에 필터를 적용해

  특정 동작을 수행하게 해주는 역할을 합니다.

- 따라서 우리는 필터를 사용해 페이지가 전환되는 사이에 인코딩 방식을 지정해

  한글이 깨지지 않도록 설정할 수 있습니다.

- 해당 필터를 지정해줄 때는 web.xml에서 설정해주거나 위와 같이 '@WebFilter()' Annotation을 사용할 수 있습니다.

- @WebFilter()에서 괄호 안에는 필터를 적용할 특정 서블릿을 등록할 수 있습니다.

- 한글 인코딩의 경우 모든 서블릿에 동일하게 적용할 것이기 때문에 "/*"로 전체 서블릿에서 동작하게 합니다.

- init 메서드는 필터 초기화 시 실행되는 메서드입니다.

- doFilter는 필터가 요청 시 실행할 메서드입니다. 여기서 'request.setCharacterEncoding("UTF-8");을

  입력하여 모든 POST 요청에 대하연 한글이 깨지지 않고 인코딩 될 수 있도록 지정해줍니다.

- 'chain.doFilter(request, response)'는 체인의 다음 필터 처리를 의미합니다.

- 정리하면 다음과 같습니다.

  1. 서블릿에서 특정 요청에 대해 데이터를 처리한다.
  2. View 페이지에 데이터가 전달되기 전에 필터가 동작하여 한글이 깨지지 않게 인코딩한다.
  3. chain.doFilter로 View 페이지로 전환한다.

 


 

이번 글에서는 content 페이지를 포함하지 않고 구현되는

main.jsp/header.jsp/firstView.jsp와 filter에 관해 알아봤습니다.

 

다음 글에서는

회원가입/로그인 그리고 이러한 동작을 처리하기 위한

Action 클래스와 구현 클래스, 요청을 전달받은 Controller 구현 등에 대해 알아보겠습니다.

 

 

반응형

댓글