이전 게시글에서는 스프링부트를 사용한 포트폴리오를 제작하기 위하여 기본 프로젝트를 생성하고, 프론트앤드에서 사용할 부트스트랩을 적용한 simple sidebar 템플레이트를 적용하였다.(https://talanton.tistory.com/123)

이번 글에서는 포트폴리오에서 사용할 뷰 페이지를 레이아웃을 적용하여 기본 템플레이트를 만든 다음에 페이지의 내용에 따라 뷰 페이지를 만드는 방법을 알아보고자 한다.

src/main/resources 폴더의 templates폴더에 layout 폴더를 생성하고 basic.html 파일을 생성한다.

index.html을 사용하여 basic.html을 다음과 같이 작성한다.

<th:block th:fragment="setContent(content)">태그와 Page content 부분에 <th:block th:replace = "${content}"></th:block>를 사용하여 각 뷰 페이지의 내용을 입력받도록 한다. 종료태그는 맨 마지막 </html> 태그 앞에 있다. 또 Bootstrap core JS와 Core theme JS를 </head> 태그 앞으로 이동한다. sidebarToggle 버튼을 클릭하면 사이드 바의 메뉴가 감춰지거나 보이도록 javascript(jQuery)를 사용하여 제어한다.

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<th:block th:fragment="setContent(content)">
<head>
<meta charset="utf-8" />
<meta name="viewport"
	content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />
<title>Simple Sidebar - Start Bootstrap Template</title>
<!-- Favicon-->
<link rel="icon" type="image/x-icon" href="assets/favicon.ico" />
<!-- Core theme CSS (includes Bootstrap)-->
<link href="css/styles.css" rel="stylesheet" />
<!-- Bootstrap core JS-->
<script
	src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- Core theme JS-->
<script src="js/scripts.js"></script>
</head>
<body>
<div class="d-flex" id="wrapper">
	<!-- Sidebar-->
	<div class="border-end bg-white" id="sidebar-wrapper">
		<div class="sidebar-heading border-bottom bg-light">Start
			Bootstrap</div>
		<div class="list-group list-group-flush">
			<a class="list-group-item list-group-item-action list-group-item-light p-3"
				href="#!">Dashboard</a>
			<a class="list-group-item list-group-item-action list-group-item-light p-3"
				href="#!">Shortcuts</a>
			<a class="list-group-item list-group-item-action list-group-item-light p-3"
				href="#!">Overview</a>
			<a class="list-group-item list-group-item-action list-group-item-light p-3"
				href="#!">Events</a>
			<a class="list-group-item list-group-item-action list-group-item-light p-3"
				href="#!">Profile</a>
			<a class="list-group-item list-group-item-action list-group-item-light p-3"
				href="#!">Status</a>
		</div>
	</div>
	<!-- Page content wrapper-->
	<div id="page-content-wrapper">
		<!-- Top navigation-->
		<nav
			class="navbar navbar-expand-lg navbar-light bg-light border-bottom">
			<div class="container-fluid">
				<button class="btn btn-primary" id="sidebarToggle">Toggle
					Menu</button>
				<button class="navbar-toggler" type="button"
					data-bs-toggle="collapse"
					data-bs-target="#navbarSupportedContent"
					aria-controls="navbarSupportedContent" aria-expanded="false"
					aria-label="Toggle navigation">
					<span class="navbar-toggler-icon"></span>
				</button>
				<div class="collapse navbar-collapse" id="navbarSupportedContent">
					<ul class="navbar-nav ms-auto mt-2 mt-lg-0">
						<li class="nav-item active"><a class="nav-link" href="#!">Home</a></li>
						<li class="nav-item"><a class="nav-link" href="#!">Link</a></li>
						<li class="nav-item dropdown"><a
							class="nav-link dropdown-toggle" id="navbarDropdown" href="#"
							role="button" data-bs-toggle="dropdown" aria-haspopup="true"
							aria-expanded="false">Dropdown</a>
							<div class="dropdown-menu dropdown-menu-end"
								aria-labelledby="navbarDropdown">
								<a class="dropdown-item" href="#!">Action</a> <a
									class="dropdown-item" href="#!">Another action</a>
								<div class="dropdown-divider"></div>
								<a class="dropdown-item" href="#!">Something else here</a>
							</div>
						</li>
					</ul>
				</div>
			</div>
		</nav>
		<!-- Page content-->
		<div class="container-fluid">
			<th:block th:replace = "${content}"></th:block>
		</div>
	</div>
</div>
<script>
$("#sidebarToggle").click(function(e) {
    e.preventDefault();
    $("#wrapper").toggleClass("toggled");
});
</script>
</body>
</th:block>
</html>

home.html을 다음과 같이 수정하여 레이아웃 파일 basic.html을 적용한 메인 페이지를 만든다. <th:block> 태그를 사용하여 home.html 메인 페이지의 내용을 basic.html에 적용하여 메인 페이지를 구성한다. th:fragment="content" 부분에 home.html의 내용을 추가한다.

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<th:block th:replace="~{/layout/basic :: setContent(~{this::content} )}">
    <th:block th:fragment="content">
        <h1 class="mt-4">Main Page</h1>
    </th:block>
</th:block>

다시 앱을 구동하고 브라우저를 사용하여 http://localhost:8080 으로 접속을 한다. 다시 로그인 페이지로 이동하고, Username user와 비밀번호를 입력하여 로그인한다. 로그인이 성공하고 다시 메인 페이지로 이동한다. 따라서 레이아웃 파일이 적용됨을 알 수 있다.

동작원리는 아래 그림을 참조한다.

layout1.html의 내용이 exTemplate.html에 적용(대체)이 되고, layout1.html의 content class의 부분이 exTemplate.html의 th:fragment="content"의 내용으로 대체가 되는 것이다.

전체 소스 코드는 아래와 같다.

sboot.zip
0.14MB

Posted by 세상을 살아가는 사람
,

이전 글에서 새로운 스프링 부트 포트폴리오를 위한 프로젝트를 생성을 했었다. 아무 기능이 없이 그냥 테스트 코드를 실행을 하였고, Database 연동, Spring Data JPA 및 Security 라이브러리 설정을 하였었다.

이 글에서는 간단하게 메인 페이지에 대한 동작을 확인해 본다. 즉, 브라우저에서 http://localhost:8080/을 입력하면 메인 페이지가 표시되도록 한다.

이를 위해 HomeController.java를 com.example.sboot.main.controller에 추가한다. Controller로 동작하기 위하여 @Controller 어노테이션을 추가하고 메소드로 @GetMapping("/")를 가지는 home() 메소드를 추가하고 뷰 페이지인 /home을 반환한다.

package com.example.sboot.main.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import lombok.extern.log4j.Log4j2;

@Controller
@Log4j2
public class HomeController {
	@GetMapping("/")
	public String home(Model model) {
		log.info("home...");
		return "/home";
	}
}

이 글에서는 뷰 페이지를 구성하기 위하여 부트스트랩에서 제공하는 Simple Sidebar 템플리트를 사용하여 화면을 구성하기 위한 설정을 알아본다.

기본적으로 다음 사이트(https://startbootstrap.com/template/simple-sidebar)에서 템플리트 파일을 다운로드 받아 사용한다. 압축을 풀어 src/main/resources 폴더 밑의 static 폴더에 저장한다.

 

Simple Sidebar - Bootstrap Sidebar Template - Start Bootstrap

Like our free products? Our pro products are even better! Go Pro Today!

startbootstrap.com

파일들

- assets/favicon.ico

- css/style.css

- js/script.js

- index.html

뷰 파일 home.html을 templates 폴더에 생성하고 index.html을 그대로 붙여넣기 한다.

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<meta name="viewport"
	content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />
<title>Simple Sidebar - Start Bootstrap Template</title>
<!-- Favicon-->
<link rel="icon" type="image/x-icon" href="assets/favicon.ico" />
<!-- Core theme CSS (includes Bootstrap)-->
<link href="css/styles.css" rel="stylesheet" />
</head>
<body>
	<div class="d-flex" id="wrapper">
		<!-- Sidebar-->
		<div class="border-end bg-white" id="sidebar-wrapper">
			<div class="sidebar-heading border-bottom bg-light">Start
				Bootstrap</div>
			<div class="list-group list-group-flush">
				<a
					class="list-group-item list-group-item-action list-group-item-light p-3"
					href="#!">Dashboard</a> <a
					class="list-group-item list-group-item-action list-group-item-light p-3"
					href="#!">Shortcuts</a> <a
					class="list-group-item list-group-item-action list-group-item-light p-3"
					href="#!">Overview</a> <a
					class="list-group-item list-group-item-action list-group-item-light p-3"
					href="#!">Events</a> <a
					class="list-group-item list-group-item-action list-group-item-light p-3"
					href="#!">Profile</a> <a
					class="list-group-item list-group-item-action list-group-item-light p-3"
					href="#!">Status</a>
			</div>
		</div>
		<!-- Page content wrapper-->
		<div id="page-content-wrapper">
			<!-- Top navigation-->
			<nav
				class="navbar navbar-expand-lg navbar-light bg-light border-bottom">
				<div class="container-fluid">
					<button class="btn btn-primary" id="sidebarToggle">Toggle
						Menu</button>
					<button class="navbar-toggler" type="button"
						data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
						aria-controls="navbarSupportedContent" aria-expanded="false"
						aria-label="Toggle navigation">
						<span class="navbar-toggler-icon"></span>
					</button>
					<div class="collapse navbar-collapse" id="navbarSupportedContent">
						<ul class="navbar-nav ms-auto mt-2 mt-lg-0">
							<li class="nav-item active"><a class="nav-link" href="#!">Home</a></li>
							<li class="nav-item"><a class="nav-link" href="#!">Link</a></li>
							<li class="nav-item dropdown"><a
								class="nav-link dropdown-toggle" id="navbarDropdown" href="#"
								role="button" data-bs-toggle="dropdown" aria-haspopup="true"
								aria-expanded="false">Dropdown</a>
								<div class="dropdown-menu dropdown-menu-end"
									aria-labelledby="navbarDropdown">
									<a class="dropdown-item" href="#!">Action</a> <a
										class="dropdown-item" href="#!">Another action</a>
									<div class="dropdown-divider"></div>
									<a class="dropdown-item" href="#!">Something else here</a>
								</div></li>
						</ul>
					</div>
				</div>
			</nav>
			<!-- Page content-->
			<div class="container-fluid">
				<h1 class="mt-4">Simple Sidebar</h1>
				<p>The starting state of the menu will appear collapsed on
					smaller screens, and will appear non-collapsed on larger screens.
					When toggled using the button below, the menu will change.</p>
				<p>
					Make sure to keep all page content within the
					<code>#page-content-wrapper</code>
					. The top navbar is optional, and just for demonstration. Just
					create an element with the
					<code>#sidebarToggle</code>
					ID which will toggle the menu when clicked.
				</p>
			</div>
		</div>
	</div>
	<!-- Bootstrap core JS-->
	<script
		src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
	<!-- Core theme JS-->
	<script src="js/scripts.js"></script>
</body>
</html>

앱을 구동하고 브라우저에서 http://localhost:8080/으로 접속한다.

security에 의하여 인증을 요구하여 /login 페이지로 이동이 된다.

Username user와 앱 구동 시 발급된 비밀번호(아래 그림 참조)를 사용하여 로그인을 한다.

로그인이 성공하고 다시 http://localhost:8080으로 리다이렉트가 되고 아래 그림과 같이 부트스트랩 template가 표시됨을 알 수 있다.

이로서 간단하게 기본 security가 적용이 되면서 부트스트랩 template가 적용이 되는것까지 알아보고, 다음으로는 thymeleaf를 이용하여 기본 레이아웃 파일을 만들고 이를 적용하여 뷰 페이지를 만드는 방법을 알아본다.

전체 소스 코드는 아래와 같다.

sboot.zip
0.14MB

Posted by 세상을 살아가는 사람
,

이 글에서는 스프링 부트를 사용하여 포트폴리오를 만드는 과정을 기술한다.

개발환경은 다음과 같다.

- IDE : STS4

- 자바 : JDK 11.0.7

- 데이터베이스 : MySQL 8.0.29

먼저 STS4를 이용하여 프로젝트를 생성한다.

STS4에서 메뉴 File->New->Spring Start Project를 선택한다.

아래 그림과 같이 설정하고 Next 버튼을 클릭한다.

다음과 같이 dependencies를 설정하고 Finish 버튼을 클릭한다.

Spring Boot DevTools, Lombok, Spring Data JPA, Spring Security, Thymeleaf, Spring Web을 설정해 주었다. 예를 들어 Available에서 security를 입력하면 Security->Spring Security 항목을 입력할 수 있다.

아래 그림과 같은 폴더가 Package Explorer에서 생성됨을 알 수 있다.

build.gradle 파일을 열어보면 다음과 같은 정보가 있음을 알 수 있다.

plugins {
	id 'java'
	id 'war'
	id 'org.springframework.boot' version '2.7.6'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	implementation 'org.springframework.boot:spring-boot-starter-security'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	annotationProcessor 'org.projectlombok:lombok'
	providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.security:spring-security-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

추가로 MySQL connector-java 라이브러리를 build.gradle dependency 부분에 추가한다.

	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.springframework.security:spring-security-test'
	
	implementation("mysql:mysql-connector-java:8.0.29")	// 추가된 부분
}

 

데이터베이스 연동을 위해 MySQL 데이터베이스에서 database myapp을 생성하고, 사용자 'bootuser'@'localhost'와 'bootuser'@'%'를 추가하고, 사용자에게 테입터베이스 접근 권한을 부여한다.

-- 데이터베이스 생성

create database myapp;

-- 사용자 생성
create user 'bootuser'@'localhost' identified by 'bootuser';	-- 서버에서 접속할 수 있는 사용자
create user 'bootuser'@'%' identified by 'bootuser';			-- 다른 컴퓨터에서 접속할 수 있는 사용자

-- 권한 부여
grant all privileges on myapp.* to 'bootuser'@'localhost';
grant all privileges on myapp.* to 'bootuser'@'%';

-- 디스크에 저장
commit;

프로젝트의 설정 파일 application.properties 파일은 다음과 같다. JDBC 연동을 위한 Database 설정과 Spring Data JPA를 위한 설정을 추가하고, security 로그를 위한 설정을 추가한다.

# Database
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/myapp
spring.datasource.username=bootuser
spring.datasource.password=bootuser

# Spring Data JPA
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true

spring.thymeleaf.cache=false

# security
logging.level.org.springframework.security.web= debug
logging.level.kr.talanton.sboot.security = debug

아직 security를 위한 설정은 추가되지 않은 상태이다.

마우스로 프로젝트를 선택하고 우클릭 후 Gradle->Refresh Gradle Project를 선택하여 필요한 라이브러리를 다운로드 받는다. Project and External Dependencies에서 build.gradle에 설정한 라이브러리가 존재하는지 확인해 본다.

아래와 같이 기본 테스트 코드를 추가한 후 테스트 코드를 실행한다.

package com.example.sboot;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class SbootApplicationTests {

	@Test
	void contextLoads() {
		System.out.println("context loaded");
	}
}

간단하게 context가 로딩이 되는지 확인할 수 있는 코드이다. 테스트 코드를 마우스로 선택한 후 우클릭하고 Run AS->JUnit Test를 선택한다.

위 그림과 같이 security를 위한 user의 password가 추력되고, 테스트가 수행되어 context loaded가 출력됨을 알 수 있다.

또한 JUnit 테스트 수행결과가 표시됨을 알 수 있다.

소스 코드는 다음과 같다.

sboot.zip
0.08MB

Posted by 세상을 살아가는 사람
,