화면은 JSP, JavaScript(jQuery), CSS, HTML을 이용해 작성한다.
부트스트랩은 https://cafe.naver.com/gugucoding 링크의 자료실에서 받는다.
views에 board폴더를 만들고 list.jsp파일을 추가한다.
ex02 프로젝트를 Run on Server로 실행해서 localhost:8080/controller/board/list에 List Page가 출력되는 화면이 보이는지 확인한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>List Page</h1>
</body>
</html>
톰캣 설정을 '/controller'에서 '/'로 조정한다.
SB Admin2 (부트스트랩 파일)의 pages 폴더에 있는 tables.html의 내용을 list.jsp의 내용으로 그대로 복사해서 수정하고 실행하자.
(JSP지시자는 지우면 안 된다.)
SB Admin2의 모든 폴더를 프로젝트 내 webapp 밑의 resources폴더로 복사해 넣는다. (data, dist, js, less, pages, vendor)
list.jsp파일에서 css와 js파일의 경로가 '/resources'로 시작하도록 수정한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>SB Admin 2 - Bootstrap Admin Theme</title>
<!-- Bootstrap Core CSS -->
<link href="/resources/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!-- MetisMenu CSS -->
<link href="/resources/vendor/metisMenu/metisMenu.min.css" rel="stylesheet">
<!-- DataTables CSS -->
<link href="/resources/vendor/datatables-plugins/dataTables.bootstrap.css" rel="stylesheet">
<!-- DataTables Responsive CSS -->
<link href="/resources/vendor/datatables-responsive/dataTables.responsive.css" rel="stylesheet">
<!-- Custom CSS -->
<link href="/resources/dist/css/sb-admin-2.css" rel="stylesheet">
<!-- Custom Fonts -->
<link href="/resources/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div id="wrapper">
<!-- Navigation -->
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html">SB Admin v2.0</a>
</div>
<!-- /.navbar-header -->
<ul class="nav navbar-top-links navbar-right">
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-envelope fa-fw"></i> <i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-messages">
<li>
<a href="#">
<div>
<strong>John Smith</strong>
<span class="pull-right text-muted">
<em>Yesterday</em>
</span>
</div>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend...</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<strong>John Smith</strong>
<span class="pull-right text-muted">
<em>Yesterday</em>
</span>
</div>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend...</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<strong>John Smith</strong>
<span class="pull-right text-muted">
<em>Yesterday</em>
</span>
</div>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend...</div>
</a>
</li>
<li class="divider"></li>
<li>
<a class="text-center" href="#">
<strong>Read All Messages</strong>
<i class="fa fa-angle-right"></i>
</a>
</li>
</ul>
<!-- /.dropdown-messages -->
</li>
<!-- /.dropdown -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-tasks fa-fw"></i> <i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-tasks">
<li>
<a href="#">
<div>
<p>
<strong>Task 1</strong>
<span class="pull-right text-muted">40% Complete</span>
</p>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">
<span class="sr-only">40% Complete (success)</span>
</div>
</div>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<p>
<strong>Task 2</strong>
<span class="pull-right text-muted">20% Complete</span>
</p>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: 20%">
<span class="sr-only">20% Complete</span>
</div>
</div>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<p>
<strong>Task 3</strong>
<span class="pull-right text-muted">60% Complete</span>
</p>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-warning" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%">
<span class="sr-only">60% Complete (warning)</span>
</div>
</div>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<p>
<strong>Task 4</strong>
<span class="pull-right text-muted">80% Complete</span>
</p>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-danger" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100" style="width: 80%">
<span class="sr-only">80% Complete (danger)</span>
</div>
</div>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a class="text-center" href="#">
<strong>See All Tasks</strong>
<i class="fa fa-angle-right"></i>
</a>
</li>
</ul>
<!-- /.dropdown-tasks -->
</li>
<!-- /.dropdown -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-bell fa-fw"></i> <i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-alerts">
<li>
<a href="#">
<div>
<i class="fa fa-comment fa-fw"></i> New Comment
<span class="pull-right text-muted small">4 minutes ago</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<i class="fa fa-twitter fa-fw"></i> 3 New Followers
<span class="pull-right text-muted small">12 minutes ago</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<i class="fa fa-envelope fa-fw"></i> Message Sent
<span class="pull-right text-muted small">4 minutes ago</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<i class="fa fa-tasks fa-fw"></i> New Task
<span class="pull-right text-muted small">4 minutes ago</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="#">
<div>
<i class="fa fa-upload fa-fw"></i> Server Rebooted
<span class="pull-right text-muted small">4 minutes ago</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a class="text-center" href="#">
<strong>See All Alerts</strong>
<i class="fa fa-angle-right"></i>
</a>
</li>
</ul>
<!-- /.dropdown-alerts -->
</li>
<!-- /.dropdown -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-user fa-fw"></i> <i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#"><i class="fa fa-user fa-fw"></i> User Profile</a>
</li>
<li><a href="#"><i class="fa fa-gear fa-fw"></i> Settings</a>
</li>
<li class="divider"></li>
<li><a href="login.html"><i class="fa fa-sign-out fa-fw"></i> Logout</a>
</li>
</ul>
<!-- /.dropdown-user -->
</li>
<!-- /.dropdown -->
</ul>
<!-- /.navbar-top-links -->
<div class="navbar-default sidebar" role="navigation">
<div class="sidebar-nav navbar-collapse">
<ul class="nav" id="side-menu">
<li class="sidebar-search">
<div class="input-group custom-search-form">
<input type="text" class="form-control" placeholder="Search...">
<span class="input-group-btn">
<button class="btn btn-default" type="button">
<i class="fa fa-search"></i>
</button>
</span>
</div>
<!-- /input-group -->
</li>
<li>
<a href="index.html"><i class="fa fa-dashboard fa-fw"></i> Dashboard</a>
</li>
<li>
<a href="#"><i class="fa fa-bar-chart-o fa-fw"></i> Charts<span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li>
<a href="flot.html">Flot Charts</a>
</li>
<li>
<a href="morris.html">Morris.js Charts</a>
</li>
</ul>
<!-- /.nav-second-level -->
</li>
<li>
<a href="tables.html"><i class="fa fa-table fa-fw"></i> Tables</a>
</li>
<li>
<a href="forms.html"><i class="fa fa-edit fa-fw"></i> Forms</a>
</li>
<li>
<a href="#"><i class="fa fa-wrench fa-fw"></i> UI Elements<span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li>
<a href="panels-wells.html">Panels and Wells</a>
</li>
<li>
<a href="buttons.html">Buttons</a>
</li>
<li>
<a href="notifications.html">Notifications</a>
</li>
<li>
<a href="typography.html">Typography</a>
</li>
<li>
<a href="icons.html"> Icons</a>
</li>
<li>
<a href="grid.html">Grid</a>
</li>
</ul>
<!-- /.nav-second-level -->
</li>
<li>
<a href="#"><i class="fa fa-sitemap fa-fw"></i> Multi-Level Dropdown<span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li>
<a href="#">Second Level Item</a>
</li>
<li>
<a href="#">Second Level Item</a>
</li>
<li>
<a href="#">Third Level <span class="fa arrow"></span></a>
<ul class="nav nav-third-level">
<li>
<a href="#">Third Level Item</a>
</li>
<li>
<a href="#">Third Level Item</a>
</li>
<li>
<a href="#">Third Level Item</a>
</li>
<li>
<a href="#">Third Level Item</a>
</li>
</ul>
<!-- /.nav-third-level -->
</li>
</ul>
<!-- /.nav-second-level -->
</li>
<li>
<a href="#"><i class="fa fa-files-o fa-fw"></i> Sample Pages<span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li>
<a href="blank.html">Blank Page</a>
</li>
<li>
<a href="login.html">Login Page</a>
</li>
</ul>
<!-- /.nav-second-level -->
</li>
</ul>
</div>
<!-- /.sidebar-collapse -->
</div>
<!-- /.navbar-static-side -->
</nav>
<div id="page-wrapper">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</div>
<!-- /#page-wrapper -->
</div>
<!-- /#wrapper -->
<!-- jQuery -->
<!-- <script src="/resources/vendor/jquery/jquery.min.js"></script> -->
<!-- Bootstrap Core JavaScript -->
<script src="/resources/vendor/bootstrap/js/bootstrap.min.js"></script>
<!-- Metis Menu Plugin JavaScript -->
<script src="/resources/vendor/metisMenu/metisMenu.min.js"></script>
<!-- DataTables JavaScript -->
<script src="/resources/vendor/datatables/js/jquery.dataTables.min.js"></script>
<script src="/resources/vendor/datatables-plugins/dataTables.bootstrap.min.js"></script>
<script src="/resources/vendor/datatables-responsive/dataTables.responsive.js"></script>
<!-- Custom Theme JavaScript -->
<script src="/resources/dist/js/sb-admin-2.js"></script>
<!-- Page-Level Demo Scripts - Tables - Use for reference -->
<script>
$(document).ready(function(){
$('#dataTables-example').DataTable({
responsive: true
});
$(".sidebar-nav")
.attr("class", "sidebar-nav navbar-collapse collapse")
.attr("aria-expanded", 'false')
.attr("style", "height:1px");
});
</script>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@include file="../includes/header.jsp" %>
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Tables</h1>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
Board List Page
</div>
<!-- /.panel-heading -->
<div class="panel-body">
<table width="100%" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>#번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
<th>수정일</th>
</tr>
</thead>
<c:forEach items="${list}" var="board">
<tr>
<td><c:out value="${board.bno}" /></td>
<td><c:out value="${board.title}" /></td>
<td><c:out value="${board.writer}" /></td>
<td><fmt:formatDate pattern="yyyy-MM-dd" value="${board.regdate }" /></td>
<td><fmt:formatDate pattern="yyyy-MM-dd" value="${board.updateDate }"/></td>
</tr>
</c:forEach>
</table>
</div>
<!-- /.panel-body -->
</div>
<!-- /.panel -->
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<%@include file="../includes/footer.jsp" %>
BoardController에 GET메서드를 추가한다.
@GetMapping("/register")
public void register() {
}
views > board 폴더에 includes를 적용한 입력 페이지 register.jsp를 작성한다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@include file="../includes/header.jsp" %>
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Board Register</h1>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">Board Register</div>
<!-- /.panel-heading -->
<div class="panel-body">
<form role="form" action="/board/register" method="post">
<div class="form-group">
<label>Title</label> <input class="form-control" name="title">
</div>
<div class="form-group">
<label>Text area</label> <textarea class="form-control" rows="3" name="content"></textarea>
</div>
<div class="form-group">
<label>Writer</label> <input class="form-control" name="writer">
</div>
<button type="submit" class="btn btn-default">Submit Button</button>
<button type="reset" class="btn btn-default">Reset Button</button>
</form>
</div>
<!-- end panel-body -->
</div>
<!-- end panel-body -->
</div>
<!-- end panel -->
</div>
<!-- /.row -->
<%@include file="../includes/footer.jsp"%>

게시글 등록은 되지만 한글이 깨진다.

네트워크 탭을 열어 요청을 확인해 보면 브라우저가 한글을 문제없이 보냈음을 알 수 있다. 문제는 Controller 혹은 데이터베이스 쪽이다.

콘솔 로그를 살펴보면 이미 한글이 깨져서 들어가 있다.
web.xml에 UTF-8 필터를 추가한다.
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<servlet-name>appServlet</servlet-name>
</filter-mapping>
list.jsp의 일부
<script type="text/javascript">
$(document).ready(function(){
var result = '<c:out value="${result}"/>';
});
</script>
새 게시물이 등록된 직후 예를 들어 게시물 번호가 15라면 var result = '15'; 로 처리된다.
모달창의 코드는 SB Admin2의 pages 폴더 내 notifications.html파일을 참고한다.
list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@include file="../includes/header.jsp" %>
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Tables</h1>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
Board List Page
</div>
<!-- /.panel-heading -->
<div class="panel-body">
<table width="100%" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>#번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
<th>수정일</th>
</tr>
</thead>
<c:forEach items="${list}" var="board">
<tr>
<td><c:out value="${board.bno}" /></td>
<td><c:out value="${board.title}" /></td>
<td><c:out value="${board.writer}" /></td>
<td><fmt:formatDate pattern="yyyy-MM-dd" value="${board.regdate }" /></td>
<td><fmt:formatDate pattern="yyyy-MM-dd" value="${board.updateDate }"/></td>
</tr>
</c:forEach>
</table>
<!-- Modal 추가-->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">
처리가 완료되었습니다.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
<!-- /.modal -->
</div>
<!-- /.panel-body -->
</div>
<!-- /.panel -->
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<script type="text/javascript">
$(document).ready(function(){
var result = '<c:out value="${result}"/>';
});
</script>
<%@include file="../includes/footer.jsp" %>
jQuery를 이용해 모달창 보여주는 작업을 처리한다.
<script type="text/javascript">
$(document).ready(function(){
var result = '<c:out value="${result}"/>';
checkModal(result);
function checkModal(result){
if(result === ''){
return;
}
if(parseInt(result) > 0){
$(".modal-body").html("게시글 " + parseInt(result) + " 번이 등록되었습니다.");
}
$("#myModal").modal("show");
}
});
</script>
checkModal 함수는 파라미터에 따라 모달창을 보여주거나 내용을 수정한 뒤 보이도록 작성한다. checkModal()에서는 새로운 게시글이 작성되는 경우 RedirectAttributes로 게시물의 번호가 전송되므로 이를 이용해 모달창의 내용을 수정한다.

list.jsp에 버튼을 추가하고, 하단 스크립트에 버튼 클릭 동작을 정의한다.
<!-- 생략 -->
<div class="panel-heading">
Board List Page
<button id="regBtn" type="button" class="btn btn-xs pull-right">Register New Board</button>
</div>
<!-- /.panel-heading -->
<!-- 생략 -->
<script type="text/javascript">
$(document).ready(function(){
var result = '<c:out value="${result}"/>';
checkModal(result);
function checkModal(result){
if(result === ''){
return;
}
if(parseInt(result) > 0){
$(".modal-body").html("게시글 " + parseInt(result) + " 번이 등록되었습니다.");
}
$("#myModal").modal("show");
}
//등록 버튼 클릭시 동작
$('#regBtn').on('click', function(){
self.location = "/board/register";
});
});
</script>
<%@include file="../includes/footer.jsp" %>
목록 페이지에서 링크를 통해 GET방식으로 특정 번호의 게시물을 조회할 수 있는 기능을 작성하자.
BoardController의 아래 get() 메서드를 통해 조회를 하게 된다.
@GetMapping("/get")
public void get(@RequestParam("bno") Long bno, Model model) {
log.info("/get");
model.addAttribute("board", service.get(bno));
}
register.jsp를 복사해 get.jsp를 작성한다.
get.jsp에는
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@include file="../includes/header.jsp" %>
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Board Register</h1>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">Board Read Page</div>
<!-- /.panel-heading -->
<div class="panel-body">
<div class="form-group">
<label>Bno</label> <input class="form-control" name="bno" value='<c:out value="${board.bno }"/>' readonly="readonly">
</div>
<div class="form-group">
<label>Title</label> <input class="form-control" name="title" value='<c:out value="${board.title }"/>' readonly="readonly">
</div>
<div class="form-group">
<label>Text area</label> <textarea class="form-control" rows="3" name="content" readonly='readonly'><c:out value="${board.content }"/></textarea>
</div>
<div class="form-group">
<label>Writer</label> <input class="form-control" name="writer" value='<c:out value="${board.writer }"/>' readonly="readonly">
</div>
<button data-oper="modify" class="btn btn-default">Modify</button>
<button data-oper="list" class="btn btn-info">List</button>
</div>
<!-- end panel-body -->
</div>
<!-- end panel-body -->
</div>
<!-- end panel -->
</div>
<!-- /.row -->
<%@include file="../includes/footer.jsp"%>
버튼은 아래와 같이 링크를 추가한다.
<button data-oper="modify"
class="btn btn-default"
onclick="location.href='/board/modify?bno=<c:out value="${board.bno }"/>'">
Modify
</button>
<button data-oper="list"
class="btn btn-info"
onclick="location.href='/board/list'">
List
</button>