화면 처리
- BootStrap 이용 : https://startbootstrap.com/template-categories/all/
1. 화면작업 사전 준비
1-1. 한글문제와 UTF-8 필터 처리
- 화면에서 한글 데이터를 보냈을 때, 웹 브라우저의 Network 콘솔에서 한글이 깨지지 않았고, 개발도구 콘솔에서 한글이 깨져서 보이면 아래와 같이 처리한다.
- XML 셋팅 : web.xml
<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>
- Java 셋팅 : WebConfig.java 에 하기의 메소드 추가
@Override
protected Filter[] getServletFilters() {
// TODO Auto-generated method stub
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[] {characterEncodingFilter};
}
1-2. Bootstrap, 프로젝트에 적용하기
- 다운로드 : https://startbootstrap.com/templates
-
SB Admin
다운로드 -
/Users/kim-yunmi/eclipse-workspace/ex02/src/main/webapp/resources
하위에 다운로드 받은 템플릿 파일을 저장한다. -
기본적인
list.jsp
를views/board/
경로에 아래와 같이 만든다.<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h1>List Page</h1> </body> </html>
- 탐캣의 contextRoot를 ‘/'로 변경하고, 서버를 시작한다.
-
http://localhost:8080/board/list
를 호출하고 (4)에서 생성한 list.jsp 페이지가 문제없이 뜨는 것을 확인한다. - 이제 bootstrap의 스타일을 list.jsp 에 적용한다.
- <html lang="en"> ~ </html> 까지의 SB Admin2 tables.html 소스를 list.jsp에 복사한다.
- css, js, img 폴더의 경로를
/resources/
로 시작하도록 변경한다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <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, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>SB Admin 2 - Tables</title> <!-- Custom fonts for this template --> <link href="/resources/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css"> <link href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i" rel="stylesheet"> <!-- Custom styles for this template --> <link href="/resources/css/sb-admin-2.min.css" rel="stylesheet"> <!-- Custom styles for this page --> <link href="/resources/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet"> </head> <body id="page-top"> <!-- Page Wrapper --> <div id="wrapper"> <!-- Sidebar --> <ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar"> <!-- Sidebar - Brand --> <a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.html"> <div class="sidebar-brand-icon rotate-n-15"> <i class="fas fa-laugh-wink"></i> </div> <div class="sidebar-brand-text mx-3">SB Admin <sup>2</sup></div> </a> <!-- Divider --> <hr class="sidebar-divider my-0"> <!-- Nav Item - Dashboard --> <li class="nav-item"> <a class="nav-link" href="index.html"> <i class="fas fa-fw fa-tachometer-alt"></i> <span>Dashboard</span></a> </li> <!-- Divider --> <hr class="sidebar-divider"> <!-- Heading --> <div class="sidebar-heading"> Interface </div> <!-- Nav Item - Pages Collapse Menu --> <li class="nav-item"> <a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="true" aria-controls="collapseTwo"> <i class="fas fa-fw fa-cog"></i> <span>Components</span> </a> <div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionSidebar"> <div class="bg-white py-2 collapse-inner rounded"> <h6 class="collapse-header">Custom Components:</h6> <a class="collapse-item" href="buttons.html">Buttons</a> <a class="collapse-item" href="cards.html">Cards</a> </div> </div> </li> <!-- Nav Item - Utilities Collapse Menu --> <li class="nav-item"> <a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseUtilities" aria-expanded="true" aria-controls="collapseUtilities"> <i class="fas fa-fw fa-wrench"></i> <span>Utilities</span> </a> <div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities" data-parent="#accordionSidebar"> <div class="bg-white py-2 collapse-inner rounded"> <h6 class="collapse-header">Custom Utilities:</h6> <a class="collapse-item" href="utilities-color.html">Colors</a> <a class="collapse-item" href="utilities-border.html">Borders</a> <a class="collapse-item" href="utilities-animation.html">Animations</a> <a class="collapse-item" href="utilities-other.html">Other</a> </div> </div> </li> <!-- Divider --> <hr class="sidebar-divider"> <!-- Heading --> <div class="sidebar-heading"> Addons </div> <!-- Nav Item - Pages Collapse Menu --> <li class="nav-item"> <a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapsePages" aria-expanded="true" aria-controls="collapsePages"> <i class="fas fa-fw fa-folder"></i> <span>Pages</span> </a> <div id="collapsePages" class="collapse" aria-labelledby="headingPages" data-parent="#accordionSidebar"> <div class="bg-white py-2 collapse-inner rounded"> <h6 class="collapse-header">Login Screens:</h6> <a class="collapse-item" href="login.html">Login</a> <a class="collapse-item" href="register.html">Register</a> <a class="collapse-item" href="forgot-password.html">Forgot Password</a> <div class="collapse-divider"></div> <h6 class="collapse-header">Other Pages:</h6> <a class="collapse-item" href="404.html">404 Page</a> <a class="collapse-item" href="blank.html">Blank Page</a> </div> </div> </li> <!-- Nav Item - Charts --> <li class="nav-item"> <a class="nav-link" href="charts.html"> <i class="fas fa-fw fa-chart-area"></i> <span>Charts</span></a> </li> <!-- Nav Item - Tables --> <li class="nav-item active"> <a class="nav-link" href="tables.html"> <i class="fas fa-fw fa-table"></i> <span>Tables</span></a> </li> <!-- Divider --> <hr class="sidebar-divider d-none d-md-block"> <!-- Sidebar Toggler (Sidebar) --> <div class="text-center d-none d-md-inline"> <button class="rounded-circle border-0" id="sidebarToggle"></button> </div> </ul> <!-- End of Sidebar --> <!-- Content Wrapper --> <div id="content-wrapper" class="d-flex flex-column"> <!-- Main Content --> <div id="content"> <!-- Topbar --> <nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow"> <!-- Sidebar Toggle (Topbar) --> <form class="form-inline"> <button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3"> <i class="fa fa-bars"></i> </button> </form> <!-- Topbar Search --> <form class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search"> <div class="input-group"> <input type="text" class="form-control bg-light border-0 small" placeholder="Search for..." aria-label="Search" aria-describedby="basic-addon2"> <div class="input-group-append"> <button class="btn btn-primary" type="button"> <i class="fas fa-search fa-sm"></i> </button> </div> </div> </form> <!-- Topbar Navbar --> <ul class="navbar-nav ml-auto"> <!-- Nav Item - Search Dropdown (Visible Only XS) --> <li class="nav-item dropdown no-arrow d-sm-none"> <a class="nav-link dropdown-toggle" href="#" id="searchDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fas fa-search fa-fw"></i> </a> <!-- Dropdown - Messages --> <div class="dropdown-menu dropdown-menu-right p-3 shadow animated--grow-in" aria-labelledby="searchDropdown"> <form class="form-inline mr-auto w-100 navbar-search"> <div class="input-group"> <input type="text" class="form-control bg-light border-0 small" placeholder="Search for..." aria-label="Search" aria-describedby="basic-addon2"> <div class="input-group-append"> <button class="btn btn-primary" type="button"> <i class="fas fa-search fa-sm"></i> </button> </div> </div> </form> </div> </li> <!-- Nav Item - Alerts --> <li class="nav-item dropdown no-arrow mx-1"> <a class="nav-link dropdown-toggle" href="#" id="alertsDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fas fa-bell fa-fw"></i> <!-- Counter - Alerts --> <span class="badge badge-danger badge-counter">3+</span> </a> <!-- Dropdown - Alerts --> <div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="alertsDropdown"> <h6 class="dropdown-header"> Alerts Center </h6> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="mr-3"> <div class="icon-circle bg-primary"> <i class="fas fa-file-alt text-white"></i> </div> </div> <div> <div class="small text-gray-500">December 12, 2019</div> <span class="font-weight-bold">A new monthly report is ready to download!</span> </div> </a> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="mr-3"> <div class="icon-circle bg-success"> <i class="fas fa-donate text-white"></i> </div> </div> <div> <div class="small text-gray-500">December 7, 2019</div> $290.29 has been deposited into your account! </div> </a> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="mr-3"> <div class="icon-circle bg-warning"> <i class="fas fa-exclamation-triangle text-white"></i> </div> </div> <div> <div class="small text-gray-500">December 2, 2019</div> Spending Alert: We've noticed unusually high spending for your account. </div> </a> <a class="dropdown-item text-center small text-gray-500" href="#">Show All Alerts</a> </div> </li> <!-- Nav Item - Messages --> <li class="nav-item dropdown no-arrow mx-1"> <a class="nav-link dropdown-toggle" href="#" id="messagesDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fas fa-envelope fa-fw"></i> <!-- Counter - Messages --> <span class="badge badge-danger badge-counter">7</span> </a> <!-- Dropdown - Messages --> <div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="messagesDropdown"> <h6 class="dropdown-header"> Message Center </h6> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="dropdown-list-image mr-3"> <img class="rounded-circle" src="/resources/img/undraw_profile_1.svg" alt=""> <div class="status-indicator bg-success"></div> </div> <div class="font-weight-bold"> <div class="text-truncate">Hi there! I am wondering if you can help me with a problem I've been having.</div> <div class="small text-gray-500">Emily Fowler · 58m</div> </div> </a> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="dropdown-list-image mr-3"> <img class="rounded-circle" src="/resources/img/undraw_profile_2.svg" alt=""> <div class="status-indicator"></div> </div> <div> <div class="text-truncate">I have the photos that you ordered last month, how would you like them sent to you?</div> <div class="small text-gray-500">Jae Chun · 1d</div> </div> </a> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="dropdown-list-image mr-3"> <img class="rounded-circle" src="/resources/img/undraw_profile_3.svg" alt=""> <div class="status-indicator bg-warning"></div> </div> <div> <div class="text-truncate">Last month's report looks great, I am very happy with the progress so far, keep up the good work!</div> <div class="small text-gray-500">Morgan Alvarez · 2d</div> </div> </a> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="dropdown-list-image mr-3"> <img class="rounded-circle" src="https://source.unsplash.com/Mv9hjnEUHR4/60x60" alt=""> <div class="status-indicator bg-success"></div> </div> <div> <div class="text-truncate">Am I a good boy? The reason I ask is because someone told me that people say this to all dogs, even if they aren't good...</div> <div class="small text-gray-500">Chicken the Dog · 2w</div> </div> </a> <a class="dropdown-item text-center small text-gray-500" href="#">Read More Messages</a> </div> </li> <div class="topbar-divider d-none d-sm-block"></div> <!-- Nav Item - User Information --> <li class="nav-item dropdown no-arrow"> <a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <span class="mr-2 d-none d-lg-inline text-gray-600 small">Douglas McGee</span> <img class="img-profile rounded-circle" src="/resources/img/undraw_profile.svg"> </a> <!-- Dropdown - User Information --> <div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown"> <a class="dropdown-item" href="#"> <i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i> Profile </a> <a class="dropdown-item" href="#"> <i class="fas fa-cogs fa-sm fa-fw mr-2 text-gray-400"></i> Settings </a> <a class="dropdown-item" href="#"> <i class="fas fa-list fa-sm fa-fw mr-2 text-gray-400"></i> Activity Log </a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="#" data-toggle="modal" data-target="#logoutModal"> <i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i> Logout </a> </div> </li> </ul> </nav> <!-- End of Topbar --> <!-- Begin Page Content --> <div class="container-fluid"> <!-- Page Heading --> <h1 class="h3 mb-2 text-gray-800">Tables</h1> <p class="mb-4">DataTables is a third party plugin that is used to generate the demo table below. For more information about DataTables, please visit the <a target="_blank" href="https://datatables.net">official DataTables documentation</a>.</p> <!-- DataTales Example --> <div class="card shadow mb-4"> <div class="card-header py-3"> <h6 class="m-0 font-weight-bold text-primary">DataTables Example</h6> </div> <div class="card-body"> <div class="table-responsive"> <table class="table table-bordered" id="dataTable" width="100%" cellspacing="0"> <thead> <tr> <th>Name</th> <th>Position</th> <th>Office</th> <th>Age</th> <th>Start date</th> <th>Salary</th> </tr> </thead> <tfoot> <tr> <th>Name</th> <th>Position</th> <th>Office</th> <th>Age</th> <th>Start date</th> <th>Salary</th> </tr> </tfoot> <tbody> <tr> <td>Tiger Nixon</td> <td>System Architect</td> <td>Edinburgh</td> <td>61</td> <td>2011/04/25</td> <td>$320,800</td> </tr> </tbody> </table> </div> </div> </div> </div> <!-- /.container-fluid --> </div> <!-- End of Main Content --> <!-- Footer --> <footer class="sticky-footer bg-white"> <div class="container my-auto"> <div class="copyright text-center my-auto"> <span>Copyright © Your Website 2020</span> </div> </div> </footer> <!-- End of Footer --> </div> <!-- End of Content Wrapper --> </div> <!-- End of Page Wrapper --> <!-- Scroll to Top Button--> <a class="scroll-to-top rounded" href="#page-top"> <i class="fas fa-angle-up"></i> </a> <!-- Logout Modal--> <div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLabel">Ready to Leave?</h5> <button class="close" type="button" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body">Select "Logout" below if you are ready to end your current session.</div> <div class="modal-footer"> <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button> <a class="btn btn-primary" href="login.html">Logout</a> </div> </div> </div> </div> <!-- Bootstrap core JavaScript--> <script src="/resources/vendor/jquery/jquery.min.js"></script> <script src="/resources/vendor/bootstrap/js/bootstrap.bundle.min.js"></script> <!-- Core plugin JavaScript--> <script src="/resources/vendor/jquery-easing/jquery.easing.min.js"></script> <!-- Custom scripts for all pages--> <script src="/resources/js/sb-admin-2.min.js"></script> <!-- Page level plugins --> <script src="/resources/vendor/datatables/jquery.dataTables.min.js"></script> <script src="/resources/vendor/datatables/dataTables.bootstrap4.min.js"></script> <!-- Page level custom scripts --> <script src="/resources/js/demo/datatables-demo.js"></script> </body> </html>
1-3. 페이지 include
- ‘Begin of Page Wrapper' 부분 부터 ‘End of Page Wrapper' 만 list.jsp 에 남겨두고 윗부분은 /views/includes/header.jsp 로, 아랫 부분은 /views/includes/footer.jsp 로 코드를 이동한다.
- list.jsp 의 윗 부분에 header.jsp 를, 아랫 부분에 footer.jsp 를 include 한다.
- list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@include file="../includes/header.jsp" %> <!-- Begin Page Content --> <div class="container-fluid"> <!-- Page Heading --> <h1 class="h3 mb-2 text-gray-800">Tables</h1> <p class="mb-4">DataTables is a third party plugin that is used to generate the demo table below. For more information about DataTables, please visit the <a target="_blank" href="https://datatables.net">official DataTables documentation</a>.</p> <!-- DataTales Example --> <div class="card shadow mb-4"> <div class="card-header py-3"> <h6 class="m-0 font-weight-bold text-primary">DataTables Example</h6> </div> <div class="card-body"> <div class="table-responsive"> <table class="table table-bordered" id="dataTable" width="100%" cellspacing="0"> <thead> <tr> <th>Name</th> <th>Position</th> <th>Office</th> <th>Age</th> <th>Start date</th> <th>Salary</th> </tr> </thead> <tfoot> <tr> <th>Name</th> <th>Position</th> <th>Office</th> <th>Age</th> <th>Start date</th> <th>Salary</th> </tr> </tfoot> <tbody> <tr> <td>Tiger Nixon</td> <td>System Architect</td> <td>Edinburgh</td> <td>61</td> <td>2011/04/25</td> <td>$320,800</td> </tr> </tbody> </table> </div> </div> </div> </div> <!-- /.container-fluid --> </div> <!-- End of Main Content --> <!-- End of Content Wrapper --> </div> <!-- End of Page Wrapper --> <%@include file="../includes/footer.jsp" %>
-
header.jsp
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <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, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>/board/list.jsp</title> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <!-- Custom fonts for this template --> <link href="/resources/vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css"> <link href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i" rel="stylesheet"> <!-- Custom styles for this template --> <link href="/resources/css/sb-admin-2.min.css" rel="stylesheet"> <!-- Custom styles for this page --> <link href="/resources/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet"> </head> <body id="page-top"> <!-- Page Wrapper --> <div id="wrapper"> <!-- Sidebar --> <ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar"> <!-- Sidebar - Brand --> <a class="sidebar-brand d-flex align-items-center justify-content-center" href="index.html"> <div class="sidebar-brand-icon rotate-n-15"> <i class="fas fa-laugh-wink"></i> </div> <div class="sidebar-brand-text mx-3">SB Admin <sup>2</sup></div> </a> <!-- Divider --> <hr class="sidebar-divider my-0"> <!-- Nav Item - Dashboard --> <li class="nav-item"> <a class="nav-link" href="index.html"> <i class="fas fa-fw fa-tachometer-alt"></i> <span>Dashboard</span></a> </li> <!-- Divider --> <hr class="sidebar-divider"> <!-- Heading --> <div class="sidebar-heading"> Interface </div> <!-- Nav Item - Pages Collapse Menu --> <li class="nav-item"> <a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="true" aria-controls="collapseTwo"> <i class="fas fa-fw fa-cog"></i> <span>Components</span> </a> <div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionSidebar"> <div class="bg-white py-2 collapse-inner rounded"> <h6 class="collapse-header">Custom Components:</h6> <a class="collapse-item" href="buttons.html">Buttons</a> <a class="collapse-item" href="cards.html">Cards</a> </div> </div> </li> <!-- Nav Item - Utilities Collapse Menu --> <li class="nav-item"> <a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseUtilities" aria-expanded="true" aria-controls="collapseUtilities"> <i class="fas fa-fw fa-wrench"></i> <span>Utilities</span> </a> <div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities" data-parent="#accordionSidebar"> <div class="bg-white py-2 collapse-inner rounded"> <h6 class="collapse-header">Custom Utilities:</h6> <a class="collapse-item" href="utilities-color.html">Colors</a> <a class="collapse-item" href="utilities-border.html">Borders</a> <a class="collapse-item" href="utilities-animation.html">Animations</a> <a class="collapse-item" href="utilities-other.html">Other</a> </div> </div> </li> <!-- Divider --> <hr class="sidebar-divider"> <!-- Heading --> <div class="sidebar-heading"> Addons </div> <!-- Nav Item - Pages Collapse Menu --> <li class="nav-item"> <a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapsePages" aria-expanded="true" aria-controls="collapsePages"> <i class="fas fa-fw fa-folder"></i> <span>Pages</span> </a> <div id="collapsePages" class="collapse" aria-labelledby="headingPages" data-parent="#accordionSidebar"> <div class="bg-white py-2 collapse-inner rounded"> <h6 class="collapse-header">Login Screens:</h6> <a class="collapse-item" href="login.html">Login</a> <a class="collapse-item" href="register.html">Register</a> <a class="collapse-item" href="forgot-password.html">Forgot Password</a> <div class="collapse-divider"></div> <h6 class="collapse-header">Other Pages:</h6> <a class="collapse-item" href="404.html">404 Page</a> <a class="collapse-item" href="blank.html">Blank Page</a> </div> </div> </li> <!-- Nav Item - Charts --> <li class="nav-item"> <a class="nav-link" href="charts.html"> <i class="fas fa-fw fa-chart-area"></i> <span>Charts</span></a> </li> <!-- Nav Item - Tables --> <li class="nav-item active"> <a class="nav-link" href="tables.html"> <i class="fas fa-fw fa-table"></i> <span>Tables</span></a> </li> <!-- Divider --> <hr class="sidebar-divider d-none d-md-block"> <!-- Sidebar Toggler (Sidebar) --> <div class="text-center d-none d-md-inline"> <button class="rounded-circle border-0" id="sidebarToggle"></button> </div> </ul> <!-- End of Sidebar --> <!-- Content Wrapper --> <div id="content-wrapper" class="d-flex flex-column"> <!-- Main Content --> <div id="content"> <!-- Topbar --> <nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow"> <!-- Sidebar Toggle (Topbar) --> <form class="form-inline"> <button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3"> <i class="fa fa-bars"></i> </button> </form> <!-- Topbar Search --> <form class="d-none d-sm-inline-block form-inline mr-auto ml-md-3 my-2 my-md-0 mw-100 navbar-search"> <div class="input-group"> <input type="text" class="form-control bg-light border-0 small" placeholder="Search for..." aria-label="Search" aria-describedby="basic-addon2"> <div class="input-group-append"> <button class="btn btn-primary" type="button"> <i class="fas fa-search fa-sm"></i> </button> </div> </div> </form> <!-- Topbar Navbar --> <ul class="navbar-nav ml-auto"> <!-- Nav Item - Search Dropdown (Visible Only XS) --> <li class="nav-item dropdown no-arrow d-sm-none"> <a class="nav-link dropdown-toggle" href="#" id="searchDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fas fa-search fa-fw"></i> </a> <!-- Dropdown - Messages --> <div class="dropdown-menu dropdown-menu-right p-3 shadow animated--grow-in" aria-labelledby="searchDropdown"> <form class="form-inline mr-auto w-100 navbar-search"> <div class="input-group"> <input type="text" class="form-control bg-light border-0 small" placeholder="Search for..." aria-label="Search" aria-describedby="basic-addon2"> <div class="input-group-append"> <button class="btn btn-primary" type="button"> <i class="fas fa-search fa-sm"></i> </button> </div> </div> </form> </div> </li> <!-- Nav Item - Alerts --> <li class="nav-item dropdown no-arrow mx-1"> <a class="nav-link dropdown-toggle" href="#" id="alertsDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fas fa-bell fa-fw"></i> <!-- Counter - Alerts --> <span class="badge badge-danger badge-counter">3+</span> </a> <!-- Dropdown - Alerts --> <div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="alertsDropdown"> <h6 class="dropdown-header"> Alerts Center </h6> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="mr-3"> <div class="icon-circle bg-primary"> <i class="fas fa-file-alt text-white"></i> </div> </div> <div> <div class="small text-gray-500">December 12, 2019</div> <span class="font-weight-bold">A new monthly report is ready to download!</span> </div> </a> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="mr-3"> <div class="icon-circle bg-success"> <i class="fas fa-donate text-white"></i> </div> </div> <div> <div class="small text-gray-500">December 7, 2019</div> $290.29 has been deposited into your account! </div> </a> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="mr-3"> <div class="icon-circle bg-warning"> <i class="fas fa-exclamation-triangle text-white"></i> </div> </div> <div> <div class="small text-gray-500">December 2, 2019</div> Spending Alert: We've noticed unusually high spending for your account. </div> </a> <a class="dropdown-item text-center small text-gray-500" href="#">Show All Alerts</a> </div> </li> <!-- Nav Item - Messages --> <li class="nav-item dropdown no-arrow mx-1"> <a class="nav-link dropdown-toggle" href="#" id="messagesDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fas fa-envelope fa-fw"></i> <!-- Counter - Messages --> <span class="badge badge-danger badge-counter">7</span> </a> <!-- Dropdown - Messages --> <div class="dropdown-list dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="messagesDropdown"> <h6 class="dropdown-header"> Message Center </h6> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="dropdown-list-image mr-3"> <img class="rounded-circle" src="/resources/img/undraw_profile_1.svg" alt=""> <div class="status-indicator bg-success"></div> </div> <div class="font-weight-bold"> <div class="text-truncate">Hi there! I am wondering if you can help me with a problem I've been having.</div> <div class="small text-gray-500">Emily Fowler · 58m</div> </div> </a> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="dropdown-list-image mr-3"> <img class="rounded-circle" src="/resources/img/undraw_profile_2.svg" alt=""> <div class="status-indicator"></div> </div> <div> <div class="text-truncate">I have the photos that you ordered last month, how would you like them sent to you?</div> <div class="small text-gray-500">Jae Chun · 1d</div> </div> </a> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="dropdown-list-image mr-3"> <img class="rounded-circle" src="/resources/img/undraw_profile_3.svg" alt=""> <div class="status-indicator bg-warning"></div> </div> <div> <div class="text-truncate">Last month's report looks great, I am very happy with the progress so far, keep up the good work!</div> <div class="small text-gray-500">Morgan Alvarez · 2d</div> </div> </a> <a class="dropdown-item d-flex align-items-center" href="#"> <div class="dropdown-list-image mr-3"> <img class="rounded-circle" src="https://source.unsplash.com/Mv9hjnEUHR4/60x60" alt=""> <div class="status-indicator bg-success"></div> </div> <div> <div class="text-truncate">Am I a good boy? The reason I ask is because someone told me that people say this to all dogs, even if they aren't good...</div> <div class="small text-gray-500">Chicken the Dog · 2w</div> </div> </a> <a class="dropdown-item text-center small text-gray-500" href="#">Read More Messages</a> </div> </li> <div class="topbar-divider d-none d-sm-block"></div> <!-- Nav Item - User Information --> <li class="nav-item dropdown no-arrow"> <a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <span class="mr-2 d-none d-lg-inline text-gray-600 small">Douglas McGee</span> <img class="img-profile rounded-circle" src="/resources/img/undraw_profile.svg"> </a> <!-- Dropdown - User Information --> <div class="dropdown-menu dropdown-menu-right shadow animated--grow-in" aria-labelledby="userDropdown"> <a class="dropdown-item" href="#"> <i class="fas fa-user fa-sm fa-fw mr-2 text-gray-400"></i> Profile </a> <a class="dropdown-item" href="#"> <i class="fas fa-cogs fa-sm fa-fw mr-2 text-gray-400"></i> Settings </a> <a class="dropdown-item" href="#"> <i class="fas fa-list fa-sm fa-fw mr-2 text-gray-400"></i> Activity Log </a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="#" data-toggle="modal" data-target="#logoutModal"> <i class="fas fa-sign-out-alt fa-sm fa-fw mr-2 text-gray-400"></i> Logout </a> </div> </li> </ul> </nav> <!-- End of Topbar -->
-
footer.jsp
<footer class="sticky-footer bg-white"> <div class="container my-auto"> <div class="copyright text-center my-auto"> <span>Copyright © Your Website 2020</span> </div> </div> </footer> <!-- Scroll to Top Button--> <a class="scroll-to-top rounded" href="#page-top"> <i class="fas fa-angle-up"></i> </a> <!-- Logout Modal--> <div class="modal fade" id="logoutModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLabel">Ready to Leave?</h5> <button class="close" type="button" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body">Select "Logout" below if you are ready to end your current session.</div> <div class="modal-footer"> <button class="btn btn-secondary" type="button" data-dismiss="modal">Cancel</button> <a class="btn btn-primary" href="login.html">Logout</a> </div> </div> </div> </div> <!-- Bootstrap core JavaScript--> <!-- <script src="/resources/vendor/jquery/jquery.min.js"></script> --> <script src="/resources/vendor/bootstrap/js/bootstrap.bundle.min.js"></script> <!-- Core plugin JavaScript--> <script src="/resources/vendor/jquery-easing/jquery.easing.min.js"></script> <!-- Custom scripts for all pages--> <script src="/resources/js/sb-admin-2.min.js"></script> <!-- Page level plugins --> <script src="/resources/vendor/datatables/jquery.dataTables.min.js"></script> <script src="/resources/vendor/datatables/dataTables.bootstrap4.min.js"></script> <!-- Page level custom scripts --> <script src="/resources/js/demo/datatables-demo.js"></script> </body> </html>
1-3. jQuery 라이브러리 변경
- footer.jsp 에 선언된 jquery.min.js 부분을 삭제하고 header.jsp 부분에 jquery.min.js 의 CDN 을 추가한다.
<script
src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
crossorigin="anonymous">
</script>
2. 목록화면 처리
-
list.jsp 에
태그 라이브러리
추가<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
-
controller 에서 전해준 Model에 담긴 데이터를 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" %> <!-- Begin Page Content --> <div class="container-fluid"> <!-- Page Heading --> <h1 class="h3 mb-2 text-gray-800">Tables</h1> <p class="mb-4">DataTables is a third party plugin that is used to generate the demo table below. For more information about DataTables, please visit the <a target="_blank" href="https://datatables.net">official DataTables documentation</a>.</p> <!-- DataTales Example --> <div class="card shadow mb-4"> <div class="card-header py-3"> <h6 class="m-0 font-weight-bold text-primary">DataTables Example</h6> </div> <div class="card-body"> <div class="table-responsive"> <table class="table table-bordered" id="dataTable" width="100%" cellspacing="0"> <thead> <tr> <th>#번호</th> <th>제목</th> <th>작성자</th> <th>작성일</th> <th>수정일</th> </tr> </thead> <tfoot> <tr> <th>#번호</th> <th>제목</th> <th>작성자</th> <th>작성일</th> <th>수정일</th> </tr> </tfoot> <tbody> <c:forEach items="${list}" var="board"> <tr> <td>${board.bno}</td> <td>${board.title}</td> <td>${board.writer}</td> <td><fmt:formatDate value="${board.regdate}" pattern="yyyy-mm-dd" /></td> <td><fmt:formatDate value="${board.updateDate}" pattern="yyyy-mm-dd" /></td> </tr> </c:forEach> </tbody> </table> </div> </div> </div> </div> <%@include file="../includes/footer.jsp" %>
3. 등록 입력 페이지 처리
-
BoardController에 get 방식의 register() 를 만든다. (입력화면을 보여주기)
@GetMapping("/register") public void register() { }
-
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="col-lg-12"> <h1 class="page-header">Board Register</h1> </div> <div class="col-lg-12"> <div class="panel panel-default"> <div class="panel-heading">Board Register</div> <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> </div> </div> </div> <%@include file="../includes/footer.jsp" %>
- 탐캣을 Start 한 후, 웹 브라우저에서
http://localhost:8080/board/register
로 접속하여 게시글을 등록해 본다. - 정상적으로 등록되고 목록 화면으로 이동한다. 반드시 목록화면으로 이동해야 한다. 그렇지 않으면 새로고침 시, 계속적으로 같은 게시물이 도배되게 된다.
- 한글이 깨지는 문제가 발생한다면, webConfig.java 또는 web.xml 에 encoding 필터를 추가한다.
- 게시글 등록 후, list.jsp 화면으로 ‘result' 파라미터를 전달하는데 이 결과를 이용하여 입력결과를 모달로 보여준다.
- list.jsp
<!-- table 태그가 끝난 후, 아래 태그를 삽입한다. --> <!-- The Modal --> <div class="modal" id="myModal"> <div class="modal-dialog"> <div class="modal-content"> <!-- Modal body --> <div class="modal-body"> </div> <!-- Modal footer --> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> </div> </div> </div> </div> <!-- End Modal --> <!-- 파일 끝에 자바스크립트로 모달 기능을 추가한다. --> <script type="text/javascript"> $(document).ready(function(){ var result = '<c:out value="${result}"/>'; checkModel(result); function checkModel(result){ if(result){ $("#myModal .modal-body").html("게시글 1건이 등록되었습니다."); $("#myModal").modal(); } } }); </script>
- list.jsp 의 테이블 위에 ‘등록' 버튼을 추가한다.
<div class="card-header py-3"> <h6 class="m-0 font-weight-bold text-primary">Board Table</h6> <div class="container-fluid border mt-3 pr-3 d-flex justify-content-between">Board List Page <button id='regBtn' type="button" class="btn btn-primary btn-sm ">Register New Board</button> </div> </div> <!-- javascript에 추가 --> $("#regBtn").on("click", function(){ self.location = "/board/register"; });
4. 조회 페이지 처리
- list.jsp에서 bno input 요소에
/board/get?bno=2
식의 onclick 이벤트를 추가 한다.<tbody> <c:forEach items="${list}" var="board"> <tr> <td><a href="/board/get?bno=${board.bno}" value="${board.bno}">${board.bno}</a></td> <td>${board.title}</td> <td>${board.writer}</td> <td><fmt:formatDate value="${board.regdate}" pattern="yyyy-mm-dd" /></td> <td><fmt:formatDate value="${board.updateDate}" pattern="yyyy-mm-dd" /></td> </tr> </c:forEach> </tbody>
- register.jsp 를 복사해 수정해서, get.jsp 페이지를 작성한다.(read-only 처리, 버튼 추가)
<%@ 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="col-lg-12"> <h1 class="page-header">Board Read Page</h1> </div> <div class="col-lg-12"> <div class="panel panel-default"> <div class="panel-body"> <div class="form-group"> <label>#Bno</label><input class="form-control" name="bno" readonly="readonly" value="${board.bno}"/> </div> <div class="form-group"> <label>Title</label><input class="form-control" name="title" readonly="readonly" value="${board.title}"/> </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" readonly="readonly" value="${board.writer}"/> </div> <button data-oper='modify' class="btn btn-primary">Modify</button> <button data-oper='list' class="btn btn-info">List</button> <form action='/board/modify' method='get'> <input type='hidden' name='bno' value='${board.bno}'/> </form> </div> </div> </div> </div> <script type='text/javascript'> $(document).ready(function(){ $('button').on('click', function(){ const oper = $(this).data('oper'); const form = $('form'); alert(oper); if(oper == 'list'){ form.attr('action', '/board/list'); form.find('input').remove(); } form.submit(); }) }) </script> <%@include file="../includes/footer.jsp" %>
- 등록 -> 목록 -> 조회 -> ‘뒤로가기' 시, 목록 페이지에 모달창 보이는 문제 해결하기
- 등록 후 목록으로 이동 시 모달창이 발생하고 나면, history 를 초기화 한다.
- 모달 창을 띄울 때, history가 있을 경우만 모달창이 뜨도록 체크하는 로직을 넣는다.(result 값이 없거나, history가 없으면 모달창은 뜨지 않아야 한다.)
- list.jsp 자바스크립트 수정
<script type="text/javascript"> $(document).ready(function(){ var result = '<c:out value="${result}"/>'; checkModel(result); history.replaceState({}, null, null); $("#regBtn").on("click", function(){ self.location = "/board/register"; }); function checkModel(result){ if(result && !history.state){ $("#myModal .modal-body").html("게시글 1건이 등록되었습니다."); $("#myModal").modal(); } } }); </script>
5. 게시글 수정/삭제 처리
- 수정화면을 불러오는 controller 를 작성한다. (BoardController.java)
@GetMapping("/modify") public void modify(@RequestParam("bno") long bno, Model model) { model.addAttribute("board", service.get(bno)); }
- get.jsp 페이지를 복사해와 modify.jsp 페이지를 작성한다.
- 수정가능한 title, content 필드는 readOnly 속성을 삭제한다.
- 날짜 관련 포맷은 ‘yyyy/mm/dd' 로 통일한다.
- 수정, 삭제, 목록 버튼을 추가하고 버튼 기능에 맞게 페이지 이동하도록 로직을 추가한다.
- modify.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="col-lg-12"> <h1 class="page-header">Board Read Page</h1> </div> <div class="col-lg-12"> <div class="panel panel-default"> <div class="panel-body"> <form action='/board/modify' method='post'> <div class="form-group"> <label>#Bno</label><input class="form-control" name="bno" readonly="readonly" value="${board.bno}"/> </div> <div class="form-group"> <label>Title</label><input class="form-control" name="title" value="${board.title}"/> </div> <div class="form-group"> <label>Text area</label><textarea class="form-control" rows="3" name="content"><c:out value="${board.content}" /></textarea> </div> <div class="form-group"> <label>Writer</label><input class="form-control" name="writer" readonly="readonly" value="${board.writer}"/> </div> <div class="form-group"> <label>Writer</label><input class="form-control" name="regdate" readonly="readonly" value="<fmt:formatDate pattern = 'yyyy/mm/dd' value='${board.regdate}'/>"/> </div> <div class="form-group"> <label>Writer</label><input class="form-control" name="updateDate" readonly="readonly" value="<fmt:formatDate pattern = 'yyyy/mm/dd' value='${board.updateDate}'/>"/> </div> <button data-oper='modify' class="btn btn-info">Modify</button> <button data-oper='remove' class="btn btn-danger">Remove</button> <button data-oper='list' class="btn btn-primary" onclick="location.href='/board/list'">List</button> </form> </div> </div> </div> </div> <script type="text/javascript"> $(document).ready(function(){ $('button').on('click',function(e){ e.preventDefault(); const form = $('form'); const oper = $(this).data('oper'); switch(oper){ case 'list': form.attr('action', '/board/list'); form.attr('method', 'get'); form.empty(); break; case 'remove': form.attr('action', '/board/remove'); break; } form.submit(); }) }); <%@include file="../includes/footer.jsp" %>