들어가기 앞서
- JSP/Servlet을 활용한 MVC Model2 게시판에 관한 내용입니다.
- 구현 기능 : 로그인, 로그아웃, 회원가입, 글쓰기, 글 수정, 글 삭제
MVC란?
- MVC는 Model/View/Controller의 약자입니다.
- MVC는 위 3가지로 이루어진 '디자인 패턴'을 말합니다.
Model 1이란?
- Model 1은 View와 Controller가 분리되지 않은 형식을 말합니다.
- 모델 1 예시
- 모델 1은 크게 JSP랑 Java Bean(Model)으로 구성됩니다.
- JSP에서 사용자 요청에 대한 응답을 처리하고 Model에 DB정보를 요청합니다.
- Model이 요청에 따라 데이터베이스에 접근하여 데이터를 처리합니다.
- 처리된 요청을 View 페이지에서 처리해 사용자에게 응답합니다.
Model 2란?
- Model 1에서 View와 Controller를 분리한 것을 의미합니다.
- 모델 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}를 앞에 붙여줍니다.
- 다운로드한 부트스트랩은 WebContent 폴더 아래에 추가해줍니다.
- js 폴더 안에 다운로드한 jQuery 파일을 추가합니다.
- 기본적으로 페이지를 [Header]와 [Content]로 구성합니다.
- 따라서 [Header] 페이지는 기본적으로 화면에 추가해줍니다.(34번째 줄)
- 전달받은 Content가 있으면 헤더 아래에 Content를
전달받은 Content 페이지가 없다면 헤더 아래에 firstView.jsp를 추가해줍니다.(36~41번째 줄)
- 위 기능을 구현하기 위해 JSTL을 사용합니다.
- JSTL을 사용하기 위해 라이브러리를 다운로드하여 'WEB-INF\lib' 에 추가해줍니다.
- 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)'는 체인의 다음 필터 처리를 의미합니다.
- 정리하면 다음과 같습니다.
- 서블릿에서 특정 요청에 대해 데이터를 처리한다.
- View 페이지에 데이터가 전달되기 전에 필터가 동작하여 한글이 깨지지 않게 인코딩한다.
- chain.doFilter로 View 페이지로 전환한다.
이번 글에서는 content 페이지를 포함하지 않고 구현되는
main.jsp/header.jsp/firstView.jsp와 filter에 관해 알아봤습니다.
다음 글에서는
회원가입/로그인 그리고 이러한 동작을 처리하기 위한
Action 클래스와 구현 클래스, 요청을 전달받은 Controller 구현 등에 대해 알아보겠습니다.
댓글