본문 바로가기

컴퓨터/Spring Boot

STS (Spring Boot) 게시판 CRUD_3. Bootstrap 적용과 SiteMesh 설정

나의 초라한 실력으로는 게시판을 절대로 이쁘게 꾸밀 수 없다는 것을 알기에

부트스트랩을 적용해보았다.

 

Free Bootstrap Themes, Templates, Snippets, and Guides - Start Bootstrap

 

위 사이트를 이용하였는데, 무료 템플릿이 몇 개 있어서 로그인 한 뒤 마음에 드는 템플릿을 골라 다운받으면 된다.

부트스트랩을 사용하면 별도의 프론트 작업을 할 필요가 없기 때문에 시간이 매우 단축되고 여러 기능들도 포함되어 있어 개발 시 매우 편리하다.

 

마음에 드는 템플릿을 골라 다운받은 후 압축을 해제하면

다음과 같은 화면을 확인할 수 있다.

 

부트스트랩 다운 예시

여기서 css,img, js,scss,vendor 폴더를 복사하여 그대로 스프링부트에 붙여넣기를 한다.

static 폴더에 bootstrap이라는 폴더를 하나 생성한 뒤에 그 안에 폴더들을 복사해주었다.

 

폴더 붙여넣기 예시

view 페이지는 jsp 파일을 사용할 것이기 때문에 .html을 모두 .jsp로 변경해준다.

(다운받은 파일들 중 사용하고 싶은 html파일들만 복사하여 사용한다.)

다음과 같이 [webapp] -> [WEB-INF] -> [views] 의 경로를 만든 후 파일들을 옮겨주었다.

.jsp파일 경로 예시

 

마지막으로 .html 파일의 내용을 jsp 설정에 맞게 바꿔주면 되는데 이 부분은 SiteMesh설명 시 같이 하도록 하겠다.

 


▶ SiteMesh란?
웹페이지는 보통 정해진 구조(head,header,body,footer)로 구성되는데 메뉴를 이동할 때마다 기존의 레이아웃은 그대로이고 중간 컨텐츠만 변경할 경우 모든 페이지에 같은 레이아웃에 대한 중복된 설정을 해주어야 한다. 이런 비효율성을 해결하기 위해 공통된 부분을 따로 구분하고 변경되는 부분만 따로 처리하여 웹 페이지의 레이아웃을 효율적으로 구성할 수 있게 도와주는 프레임워크이다.

 

크게

1. SiteMesh 설정

2. decorator 설정

이렇게 두 가지 순서를 거치면 SiteMesh를 사용할 수 있다.

 

* 참고링크

 

☞ SiteMesh 설정

1. pom.xml에 sitemesh 의존성 추가

<dependency>
	<groupId>org.sitemesh</groupId>
	<artifactId>sitemesh</artifactId>
	<version>3.0.1</version>
</dependency>

2. SitemeshFilter 설정, Bean 등록

//sitemeshfilter 설정
public class SitemeshFilter extends ConfigurableSiteMeshFilter {
	@Override
	protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
		builder.addDecoratorPath("/*", "/WEB-INF/decorator/default.jsp")		
		;
	}
}


//bean 등록
@Configuration
public class ServletFileterConfig {
		
	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Bean
	public FilterRegistrationBean siteMeshFilter() {
		FilterRegistrationBean filter = new FilterRegistrationBean();
		filter.setFilter(new SitemeshFilter());
		return filter;
	}
	
   }

 

decorator 설정

SiteMesh의 decorator란 jsp 페이지로, 공통된 html 페이지를 데코레이션한다.

간단히 말하면 사이드바나 navication 같이 모든 페이지에 공통으로 들어가는 영역을 여러번 작성할 필요 없이 따로 분리해 놓은 것이다.

 

decorator 예시

폴더 구조는 다음과 같이 잡았고, defalut.jsp 파일에는 include폴더의 head,header,footer의 경로를 넣어주었다.

 

<defalut.jsp>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang ="ko">
		<!-- head content -->
		<%@ include file="/WEB-INF/include/head.jsp" %>
		<!-- /head content -->
<body id="page-top">

    <!-- bootstrap Page Wrapper -->
    <div id="wrapper">
		<!-- header content -->
			<%@ include file="/WEB-INF/include/header.jsp" %>
		<!-- /header content -->
        
		<!-- page content -->
			<sitemesh:write property='body' />
		<!-- /page content -->
        
		<!-- footer content -->
			<%@ include file="/WEB-INF/include/footer.jsp" %>
		<!-- /footer content -->
	</div>
    <!-- bootstrap End of Page Wrapper -->
</body>
</html>

 위와같이 html로 기본 틀을 잡아놓고 각 경로를 넣어주면 해당 부분에 콘텐츠가 꽂히게 된다. 

(bootstrap Page Wrapper 부분은 부트스트랩에서 body 부분 전체를 감싸는 div였기 때문에 미리 추가해 놓았다.)

나머지 부분은 이후 다음과 같이 수정하였다.

 

<default.jsp> 수정

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang ="ko">
		<%@ include file="/WEB-INF/include/head.jsp" %>
<body id="page-top">

    <!-- Page Wrapper -->
    <div id="wrapper">

		<!-- header content -->
			<%@ include file="/WEB-INF/include/header.jsp" %>
		<!-- /header content -->

		<div id="content-wrapper" class="d-flex flex-column">
		
		 <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>

                      

                        <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="/bootstrap/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 -->

		<!-- page content -->
			<sitemesh:write property='body' />
		<!-- /page content -->
				
				</div>
		<!-- footer content -->
			<%@ include file="/WEB-INF/include/footer.jsp" %>
		<!-- /footer content -->
		</div>
	</div>
    <!-- End of Page Wrapper -->
</body>
</html>

* 원래 include의 header 부분에 추가하려했던 부분인데 어차피 모든 페이지에 공통으로 들어가는 부분인데다 너무 길어져서 여기로 옮겨놨다. 이후 부트스트랩 레이아웃을 따로 수정한다면 사용할 수도 있기 때문에 일단은 보류!

 

 

다음은 include 폴더의 head, header, footer 부분이다.

 

<head.jsp>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
	<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="/bootstrap/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="/bootstrap/css/sb-admin-2.min.css" rel="stylesheet">
	
	    <!-- Custom styles for this page -->
	    <link href="/bootstrap/vendor/datatables/dataTables.bootstrap4.min.css" rel="stylesheet">
	    
	    
	        <!-- Bootstrap core JavaScript-->
	    <script src="/bootstrap/vendor/jquery/jquery.min.js"></script>
	    <script src="/bootstrap/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
	
	    <!-- Core plugin JavaScript-->
	    <script src="/bootstrap/vendor/jquery-easing/jquery.easing.min.js"></script>
	
	    <!-- Custom scripts for all pages-->
	    <script src="/bootstrap/js/sb-admin-2.min.js"></script>
	
	    <!-- Page level plugins -->
	    <script src="/bootstrap/vendor/datatables/jquery.dataTables.min.js"></script>
	    <script src="/bootstrap/vendor/datatables/dataTables.bootstrap4.min.js"></script>
	
	    <!-- Page level custom scripts -->
	    <script src="/bootstrap/js/demo/datatables-demo.js"></script>
	    
	    <script src="/bootstrap/js/common.js"></script>
	</head>

head 부분에는 부트스트랩에서 쓰인 경로들을 다 모아놨다.

이때 href와 src에 있는 모든 경로들을 구조에 맞게 변경해주어야 한다.

여기서는 모든 파일을 bootstrap 폴더 안에 넣어놨기 때문에 위와 같이 변경해주었다.

 

<header.jsp>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

  <!-- 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="login">
                <div class="sidebar-brand-icon rotate-n-15">
                    <i class="fas fa-laugh-wink"></i>
                </div>
                <div class="sidebar-brand-text mx-3">게시판 Project</div>
            </a>

            <!-- Divider -->
            <hr class="sidebar-divider my-0">

            <!-- Nav Item - Dashboard -->
            <li class="nav-item">
                <a class="nav-link" href="index">
                    <i class="fas fa-fw fa-tachometer-alt"></i>
                    <span>게시판 CRUD</span></a>
            </li>

            <!-- Divider -->
            <hr class="sidebar-divider">

            <!-- Heading -->
            <div class="sidebar-heading">
                Board
            </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>Boards</span>
                </a>
                <div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionSidebar">
                    <div class="bg-white py-2 collapse-inner rounded">
                        <a class="collapse-item" href="index">Board1</a>
                        <a class="collapse-item" href="">Board2</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>미정</span>
                </a>
                <div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities"
                    data-parent="#accordionSidebar">
                    <div class="bg-white py-2 collapse-inner rounded">
                        <a class="collapse-item" href="utilities-other.html">미정</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>게시판 CRUD</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 -->

head 부분에는 공통으로 들어가는 사이드바와 상단 nav들을 모아놓았다.

 

<footer.jsp>

 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 <!-- Footer -->
            <footer class="sticky-footer bg-white">
                <div class="container my-auto">
                    <div class="copyright text-center my-auto">
                        <span>Copyright &copy; Your Website 2020</span>
                    </div>
                </div>
            </footer>
            <!-- End of Footer -->

        <!-- End of Content 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>

 

 

이제 SiteMesh 설정과 Decorator 분리 까지 진행하였다.

원래 부트스트랩을 다운받은 이후 login.html 페이지는 이렇게 전체 화면으로 떴었는데

login.html

사이트매쉬 적용 후 공통 레이아웃 안에 넣고 싶어서 다음과 같이 변경하였다.

login.jsp

이 부분을 메인 페이지로 설정한 후 

사이드 바 메뉴 부분을 조금 수정하여 게시판을 만들기 위한 설정을 해 놓았다.

나머지 설정 부분은 게시판 CRUD 부분에서 추가하려 한다!

728x90