본문 바로가기
개발 공부 Today I Learned

[국비 72일차 TIL] 전자정부 프레임워크 스프링 프로젝트

by 개발자신입 2024. 3. 7.
반응형

전자정부 프레임 4.1

스프링 프로젝트 생성

New Spring Starter Project

 

 

 

application.properties

# jsp경로
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
# Mariadb
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://----------
spring.datasource.username=-----
spring.datasource.password=-----
# mybatis
mybatis.type-aliases-package=com.example.web.mybatis
mybatis.mapper-locations=static/mapper/*.xml
# 포트변경시
server.port=80

indexMapper.xml

mapper파일은 Mybatis XML Mapper 형식으로 만들어야 함!

Mybatis XML Mapper

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="static.mapper.indexMapper">

</mapper>

 

프로그램 실행

Boot Dashboard에서 실행해야함.

 

IndexController.java

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class IndexController {
	
	@GetMapping("/index") 
		public ModelAndView index() { 
		ModelAndView mv = new ModelAndView("index");
		mv.addObject("test", "테스트 문장입니다 나오나용");
		
		return mv; 
	}
}

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>인덱스페이지~~</title>
</head>
<body>
	<h1>인덱스입니다 20240307</h1>
	${test }
</body>
</html>

IndexService.java

import org.springframework.stereotype.Service;

@Service
public class IndexService {

}

 

-> 컨트롤러랑 연결시키기

IndexController

@Controller
public class IndexController {
	
	@Autowired
	private IndexService indexService;

 IndexDAO (인터페이스)

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Repository
@Mapper

public interface IndexDAO {

}

IndexService.java

@Service
public class IndexService {

	@Autowired
	private IndexDAO indexDAO;
	
}

IndexController.java

@Controller
public class IndexController {
	
	@Autowired
	private IndexService indexService;
	
	@GetMapping("/index") 
		public ModelAndView index() { 
		ModelAndView mv = new ModelAndView("index");
		mv.addObject("test", "테스트 문장입니다 나오나용");
		
		List<Map<String,Object>> list = indexService.boardList();
		mv.addObject("boardList", list);
		
		return mv; 
	}
}

 

-> boardList() 생성 (서비스, DAO)

IndexService.java

@Service
public class IndexService {

	@Autowired
	private IndexDAO indexDAO;

	public List<Map<String, Object>> boardList() {
		return indexDAO.boardList();
	}

IndexDAO.java (인터페이스)

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

@Repository
@Mapper

public interface IndexDAO {

	List<Map<String, Object>> boardList();
}

indexMapper.xml

<mapper namespace="com.example.web.dao.IndexDAO">
	<select id="boardList" resultType="Map">
		SELECT board_no, board_title, board_write, board_count, comment
		FROM boardview
		LIMIT 0, 10
	</select>
</mapper>


start.spring.io에서 만들어보기

create해서 zip 파일 다운로드하기. (인텔리제이에서는 이렇게 사용해야 한다고 함.)

start.spring.io

IndexController.java 

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

@Controller
public class IndexController {

	@GetMapping("/index")
		public String index() {
			return "index";
		}
}

index.html

경로

 

* 경로 : src/main/resources - templates - index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>인덱스입니다....</h1>
	
	[[${test ]]<br>
	<th:block th:text="${test}"></th:block>
</body>
</html>

 

실행 방법

실행하기 위한 경로 Run As - Java Application
WebApplication 선택

 

크롬 확장 프로그램 LiveReload

https://chromewebstore.google.com/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei?hl=ko

 

IndexController.java

@Controller
public class IndexController {

	@Autowired
	private IndexService indexService;
	
	
	@GetMapping("/index")
	public String index(Model model) {
		model.addAttribute("test","테스트입니다 히히히히히");
		
		List<Map<String, Object>> boardList = indexService.boardList();
		model.addAttribute("list", boardList);
				
		return "index";
	}
}

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>인덱스입니다....</h1>

<hr>

	<table>
		<thead>
			<tr>
				<th>번호</th>
				<th>제목</th>
				<th>글쓴이</th>
				<th>날짜</th>
				<th>조회수</th>
			</tr>
		</thead>
		<tbody>
			<tr th:each="row : ${boardList}">
				<td th:text="${row.board_no}"></td>
				<td th:text="${row.board_title}"></td>
				<td th:text="${row.board_write}"></td>
				<td th:text="${row.board_date}"></td>
				<td th:text="${row.board_count}"></td>
			</tr>
		</tbody>
	</table>
</body>
</html>

indexMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.web.dao.IndexDAO">
	<select id="boardList" resultType="Map">
		SELECT board_no, board_title, board_write, board_count, comment, board_date 
		FROM boardview
		LIMIT 0, 10
	</select>
</mapper>


index.html

th:href="@{/detail(no=${row.board_no})}" 

		<tbody>
			<tr th:each="row : ${list}">
				<td th:text="${row.board_no}"></td>
				<td>
					<a th:href="@{/detail(no=${row.board_no})}" th:text="${row.board_title}"></a>
				</td>
				<td th:text="${row.board_title}"></td>
				<td th:text="${row.board_write}"></td>
				<td th:text="${row.board_date}"></td>
				<td th:text="${row.board_count}"></td>
			</tr>
		</tbody>

 


게시글 상세보기 (detail)

 IndexController

	// 2024-03-07 안드로이드 앱 프로그래밍
	// 상세보기 -> no 잡기 -> 확인
	// detail.html
	// 값 -> DB에 물어보고 어떤 형태로 오는지? BoardDTO에 담아준 형태로 옴.
	
	@GetMapping("/detail")
	public String detail(@RequestParam("no") int no, Model model) {
		
		BoardDTO detail = indexService.detail(no);
		model.addAttribute("detail", detail);
		
		return "detail";
	}
}

IndexService.java

	public BoardDTO detail(int no) {
		return indexDAO.detail(no);
	}

IndexDAO.java

@Repository
@Mapper

public interface IndexDAO {

	List<Map<String, Object>> boardList();

	BoardDTO detail(int no);

}

BoardDTO.java

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter

public class BoardDTO {
	private int board_no, board_count, comment;
	private String board_title, board_write, board_content, board_date;
	
}

application.properties

mybatis 패키지를 dto로 변경

# mybatis
mybatis.type-aliases-package=com.example.web.dto
mybatis.mapper-locations=static/mapper/*.xml

indexMapper.xml

	<select id="detail" parameterType="int" resultType="BoardDTO">
		SELECT board_no, board_title, board_content,board_date 
		FROM board
		WHERE board_no=#{no}
	</select>

detail.html

<!DOCTYPE html>
<html xmlns:th="http://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>detail</title>
</head>
<body>
	[[${detail.board_no}]]
	[[${detail.board_title}]]
	<th:block th:utext="${detail.board_content}"></th:block> <!-- th:utext 이미지 출력 -->
</body>
</html>

데이터베이스 테이블 생성

multiboard 테이블 만들기

CREATE TABLE `multiboard` (
	`mtno` INT(11) NOT NULL AUTO_INCREMENT,
	`mttitle` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_general_ci',
	`mtcontent` LONGTEXT NOT NULL COLLATE 'utf8mb4_general_ci',
	`mno` INT(11) NOT NULL,
	`mtdate` DATETIME NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
	`mtip` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci',
	`mtdel` INT(1) NULL DEFAULT '1',
	`mtread` INT(11) NULL DEFAULT '1',
	`mtcate` INT(1) NOT NULL DEFAULT '1',
	`mid` VARCHAR(10) NOT NULL DEFAULT '0' COLLATE 'utf8mb4_general_ci',
	`mname` VARCHAR(10) NOT NULL DEFAULT '0' COLLATE 'utf8mb4_general_ci',
	PRIMARY KEY (`mtno`) USING BTREE,
	INDEX `FK_board_member` (`mno`) USING BTREE,
	CONSTRAINT `FK_multiboard_member` FOREIGN KEY (`mno`) REFERENCES `member` (`mno`) ON UPDATE NO ACTION ON DELETE NO ACTION
)
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=26
;

);

 

multiboard 테이블 생성

IndexController

	@GetMapping("/freeboard")
	public String freeboard(Model model) {
		List<BoardDTO> board = indexService.freeboard();
		model.addAttribute("board",board);
		return "board";
	}

IndexService.java

	public List<BoardDTO> freeboard() {
		return indexDAO.freeboard();
	}

IndexDAO.java

List<BoardDTO> freeboard();

BoardDTO.java

@Getter
@Setter

public class BoardDTO {
	private int mtno, mno, mtread, mtcate;
	private String mttitle, mtcontent, mtdate, mtdel, mtip, mname, mid; 
}

indexMapper.xml

<mapper namespace="com.example.web.dao.IndexDAO">

	<select id="freeboard" resultType="BoardDTO">
		SELECT mtno, mno, mname, mid, mtdel, mtread, mtcate, mttitle, mtcontent, mtdate, mtip
		FROM multiboard
		LIMIT 0, 10
	</select>

	<select id="detail" parameterType="int" resultType="BoardDTO">
		SELECT board_no, board_title, board_content,board_date
		FROM board
		WHERE board_no=#{no}
	</select>

</mapper>

board.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>board???</title>
</head>
<body>
	<h1>멀티보드 인덱스입니다....???</h1>

<hr>
	<table>
		<thead>
			<tr>
				<th>번호</th>
				<th>제목</th>
				<th>글쓴이</th>
				<th>날짜</th>
				<th>조회수</th>
			</tr>
		</thead>
		<tbody>
			<tr th:each="row : ${board}">
				<td th:text="${row.mtno}"></td>
				<td>
					<a th:href="@{/detail(no=${row.mtno})}" th:text="${row.mttitle}"></a>
				</td>
				<td th:text="${row.mno}"></td>
				<td th:text="${row.mtdate}"></td>
				<td th:text="${row.mtip}"></td>
				<td th:text="${row.mtread}"></td>
			</tr>
		</tbody>
	</table>
	<a th:href="@{/write(mtcate=${board[0].mtcate})}">글쓰기</a>
</body>
</html>

 

부트스트랩 테마 적용하기

board.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>

    <!-- Add Bootstrap CSS link -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>

<div class="container mt-5">
    <table class="table table-bordered">
        <thead class="thead-dark">
            <tr>
                <th>번호</th>
                <th>제목</th>
                <th>글쓴이</th>
                <th>날짜</th>
                <th>아이피</th>
                <th>조회수</th>
            </tr>
        </thead>
        <tbody>
            <tr th:each="row : ${board}">
                <td th:text="${row.mtno}"></td>
                <td>
                    <a th:href="@{/detail(no=${row.mtno})}" th:text="${row.mttitle}"></a>
                </td>
                <td th:text="${row.mno}"></td>
                <td th:text="${row.mtdate}"></td>
                <td th:text="${row.mtip}"></td>
                <td th:text="${row.mtread}"></td>
            </tr>
        </tbody>
    </table>
    <a class="btn btn-primary" th:href="@{/write(mtcate=${board[0].mtcate})}">글쓰기</a>
</div>

<!-- Add Bootstrap JS and Popper.js scripts (required for Bootstrap functionality) -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>

</body>
</html>

Index.html

장문의 인덱스 코드는 접어두기

더보기

<!DOCTYPE html>
<html lang="ko" 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>New Age - Start Bootstrap Theme</title>
<link rel="icon" type="image/x-icon" href="assets/favicon.ico" />
<!-- Bootstrap icons-->
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css" rel="stylesheet" />
<!-- Google fonts-->
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,wght@0,600;1,600&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Mulish:ital,wght@0,300;0,500;0,600;0,700;1,300;1,500;1,600;1,700&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Kanit:ital,wght@0,400;1,400&display=swap" rel="stylesheet" />
<!-- Core theme CSS (includes Bootstrap)-->
<link href="css/styles.css" rel="stylesheet" />
</head>
    <body id="page-top">

        <!-- Navigation-->
        <nav class="navbar navbar-expand-lg navbar-light fixed-top shadow-sm" id="mainNav">
            <div class="container px-5">
                <a class="navbar-brand fw-bold" href="#page-top">Start Bootstrap</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
                    Menu
                    <i class="bi-list"></i>
                </button>
                <div class="collapse navbar-collapse" id="navbarResponsive">
                    <ul class="navbar-nav ms-auto me-4 my-3 my-lg-0">
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/freeboard">Freeboard</a></li>
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/notice">Notice</a></li>
                    </ul>
                    <button class="btn btn-primary rounded-pill px-3 mb-2 mb-lg-0" data-bs-toggle="modal" data-bs-target="#feedbackModal">
                        <span class="d-flex align-items-center">
                            <i class="bi-chat-text-fill me-2"></i>
                            <span class="small">Send Feedback</span>
                        </span>
                    </button>
                </div>
            </div>
        </nav>
        <!-- Mashead header-->
        <header class="masthead">
            <div class="container px-5">
                <div class="row gx-5 align-items-center">
                    <div class="col-lg-6">
                        <!-- Mashead text and app badges-->
                        <div class="mb-5 mb-lg-0 text-center text-lg-start">
                            <h1 class="display-1 lh-1 mb-3">Showcase your app beautifully.</h1>
                            <p class="lead fw-normal text-muted mb-5">Launch your mobile app landing page faster with this free, open source theme from Start Bootstrap!</p>
                            <div class="d-flex flex-column flex-lg-row align-items-center">
                                <a class="me-lg-3 mb-4 mb-lg-0" href="#!"><img class="app-badge" src="assets/img/google-play-badge.svg" alt="..." /></a>
                                <a href="#!"><img class="app-badge" src="assets/img/app-store-badge.svg" alt="..." /></a>
                            </div>
                        </div>
                    </div>
                    <div class="col-lg-6">
                        <!-- Masthead device mockup feature-->
                        <div class="masthead-device-mockup">
                            <svg class="circle" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
                                <defs>
                                    <linearGradient id="circleGradient" gradientTransform="rotate(45)">
                                        <stop class="gradient-start-color" offset="0%"></stop>
                                        <stop class="gradient-end-color" offset="100%"></stop>
                                    </linearGradient>
                                </defs>
                                <circle cx="50" cy="50" r="50"></circle></svg
                            ><svg class="shape-1 d-none d-sm-block" viewBox="0 0 240.83 240.83" xmlns="http://www.w3.org/2000/svg">
                                <rect x="-32.54" y="78.39" width="305.92" height="84.05" rx="42.03" transform="translate(120.42 -49.88) rotate(45)"></rect>
                                <rect x="-32.54" y="78.39" width="305.92" height="84.05" rx="42.03" transform="translate(-49.88 120.42) rotate(-45)"></rect></svg
                            ><svg class="shape-2 d-none d-sm-block" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50"></circle></svg>
                            <div class="device-wrapper">
                                <div class="device" data-device="iPhoneX" data-orientation="portrait" data-color="black">
                                    <div class="screen bg-black">
                                        <!-- PUT CONTENTS HERE:-->
                                        <!-- * * This can be a video, image, or just about anything else.-->
                                        <!-- * * Set the max width of your media to 100% and the height to-->
                                        <!-- * * 100% like the demo example below.-->
                                        <video muted="muted" autoplay="" loop="" style="max-width: 100%; height: 100%"><source src="assets/img/demo-screen.mp4" type="video/mp4" /></video>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </header>
        <!-- Quote/testimonial aside-->
        <aside class="text-center bg-gradient-primary-to-secondary">
            <div class="container px-5">
                <div class="row gx-5 justify-content-center">
                    <div class="col-xl-8">
                        <div class="h2 fs-1 text-white mb-4">"An intuitive solution to a common problem that we all face, wrapped up in a single app!"</div>
                        <img src="assets/img/tnw-logo.svg" alt="..." style="height: 3rem" />
                    </div>
                </div>
            </div>
        </aside>
        <!-- App features section-->
        <section id="features">
            <div class="container px-5">
                <div class="row gx-5 align-items-center">
                    <div class="col-lg-8 order-lg-1 mb-5 mb-lg-0">
                        <div class="container-fluid px-5">
                            <div class="row gx-5">
                                <div class="col-md-6 mb-5">
                                    <!-- Feature item-->
                                    <div class="text-center">
                                        <i class="bi-phone icon-feature text-gradient d-block mb-3"></i>
                                        <h3 class="font-alt">Device Mockups</h3>
                                        <p class="text-muted mb-0">Ready to use HTML/CSS device mockups, no Photoshop required!</p>
                                    </div>
                                </div>
                                <div class="col-md-6 mb-5">
                                    <!-- Feature item-->
                                    <div class="text-center">
                                        <i class="bi-camera icon-feature text-gradient d-block mb-3"></i>
                                        <h3 class="font-alt">Flexible Use</h3>
                                        <p class="text-muted mb-0">Put an image, video, animation, or anything else in the screen!</p>
                                    </div>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-md-6 mb-5 mb-md-0">
                                    <!-- Feature item-->
                                    <div class="text-center">
                                        <i class="bi-gift icon-feature text-gradient d-block mb-3"></i>
                                        <h3 class="font-alt">Free to Use</h3>
                                        <p class="text-muted mb-0">As always, this theme is free to download and use for any purpose!</p>
                                    </div>
                                </div>
                                <div class="col-md-6">
                                    <!-- Feature item-->
                                    <div class="text-center">
                                        <i class="bi-patch-check icon-feature text-gradient d-block mb-3"></i>
                                        <h3 class="font-alt">Open Source</h3>
                                        <p class="text-muted mb-0">Since this theme is MIT licensed, you can use it commercially!</p>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="col-lg-4 order-lg-0">
                        <!-- Features section device mockup-->
                        <div class="features-device-mockup">
                            <svg class="circle" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
                                <defs>
                                    <linearGradient id="circleGradient" gradientTransform="rotate(45)">
                                        <stop class="gradient-start-color" offset="0%"></stop>
                                        <stop class="gradient-end-color" offset="100%"></stop>
                                    </linearGradient>
                                </defs>
                                <circle cx="50" cy="50" r="50"></circle></svg
                            ><svg class="shape-1 d-none d-sm-block" viewBox="0 0 240.83 240.83" xmlns="http://www.w3.org/2000/svg">
                                <rect x="-32.54" y="78.39" width="305.92" height="84.05" rx="42.03" transform="translate(120.42 -49.88) rotate(45)"></rect>
                                <rect x="-32.54" y="78.39" width="305.92" height="84.05" rx="42.03" transform="translate(-49.88 120.42) rotate(-45)"></rect></svg
                            ><svg class="shape-2 d-none d-sm-block" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="50"></circle></svg>
                            <div class="device-wrapper">
                                <div class="device" data-device="iPhoneX" data-orientation="portrait" data-color="black">
                                    <div class="screen bg-black">
                                        <!-- PUT CONTENTS HERE:-->
                                        <!-- * * This can be a video, image, or just about anything else.-->
                                        <!-- * * Set the max width of your media to 100% and the height to-->
                                        <!-- * * 100% like the demo example below.-->
                                        <video muted="muted" autoplay="" loop="" style="max-width: 100%; height: 100%"><source src="assets/img/demo-screen.mp4" type="video/mp4" /></video>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>
        <!-- Basic features section-->
        <section class="bg-light">
            <div class="container px-5">
                <div class="row gx-5 align-items-center justify-content-center justify-content-lg-between">
                    <div class="col-12 col-lg-5">
                        <h2 class="display-4 lh-1 mb-4">Enter a new age of web design</h2>
                        <p class="lead fw-normal text-muted mb-5 mb-lg-0">This section is perfect for featuring some information about your application, why it was built, the problem it solves, or anything else! There's plenty of space for text here, so don't worry about writing too much.</p>
                    </div>
                    <div class="col-sm-8 col-md-6">
                        <div class="px-5 px-sm-0"><img class="img-fluid rounded-circle" src="https://source.unsplash.com/u8Jn2rzYIps/900x900" alt="..." /></div>
                    </div>
                </div>
            </div>
        </section>
        <!-- Call to action section-->
        <section class="cta">
            <div class="cta-content">
                <div class="container px-5">
                    <h2 class="text-white display-1 lh-1 mb-4">
                        Stop waiting.
                        <br />
                        Start building.
                    </h2>
                    <a class="btn btn-outline-light py-3 px-4 rounded-pill" href="https://startbootstrap.com/theme/new-age" target="_blank">Download for free</a>
                </div>
            </div>
        </section>
        <!-- App badge section-->
        <section class="bg-gradient-primary-to-secondary" id="download">
            <div class="container px-5">
                <h2 class="text-center text-white font-alt mb-4">Get the app now!</h2>
                <div class="d-flex flex-column flex-lg-row align-items-center justify-content-center">
                    <a class="me-lg-3 mb-4 mb-lg-0" href="#!"><img class="app-badge" src="assets/img/google-play-badge.svg" alt="..." /></a>
                    <a href="#!"><img class="app-badge" src="assets/img/app-store-badge.svg" alt="..." /></a>
                </div>
            </div>
        </section>
        <!-- Footer-->
        <footer class="bg-black text-center py-5">
            <div class="container px-5">
                <div class="text-white-50 small">
                    <div class="mb-2">&copy; Your Website 2023. All Rights Reserved.</div>
                    <a href="#!">Privacy</a>
                    <span class="mx-1">&middot;</span>
                    <a href="#!">Terms</a>
                    <span class="mx-1">&middot;</span>
                    <a href="#!">FAQ</a>
                </div>
            </div>
        </footer>
        <!-- Feedback Modal-->
        <div class="modal fade" id="feedbackModal" tabindex="-1" aria-labelledby="feedbackModalLabel" aria-hidden="true">
            <div class="modal-dialog modal-dialog-centered">
                <div class="modal-content">
                    <div class="modal-header bg-gradient-primary-to-secondary p-4">
                        <h5 class="modal-title font-alt text-white" id="feedbackModalLabel">Send feedback</h5>
                        <button class="btn-close btn-close-white" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div class="modal-body border-0 p-4">
                        <!-- * * * * * * * * * * * * * * *-->
                        <!-- * * SB Forms Contact Form * *-->
                        <!-- * * * * * * * * * * * * * * *-->
                        <!-- This form is pre-integrated with SB Forms.-->
                        <!-- To make this form functional, sign up at-->
                        <!-- https://startbootstrap.com/solution/contact-forms-->
                        <!-- to get an API token!-->
                        <form id="contactForm" data-sb-form-api-token="API_TOKEN">
                            <!-- Name input-->
                            <div class="form-floating mb-3">
                                <input class="form-control" id="name" type="text" placeholder="Enter your name..." data-sb-validations="required" />
                                <label for="name">Full name</label>
                                <div class="invalid-feedback" data-sb-feedback="name:required">A name is required.</div>
                            </div>
                            <!-- Email address input-->
                            <div class="form-floating mb-3">
                                <input class="form-control" id="email" type="email" placeholder="name@example.com" data-sb-validations="required,email" />
                                <label for="email">Email address</label>
                                <div class="invalid-feedback" data-sb-feedback="email:required">An email is required.</div>
                                <div class="invalid-feedback" data-sb-feedback="email:email">Email is not valid.</div>
                            </div>
                            <!-- Phone number input-->
                            <div class="form-floating mb-3">
                                <input class="form-control" id="phone" type="tel" placeholder="(123) 456-7890" data-sb-validations="required" />
                                <label for="phone">Phone number</label>
                                <div class="invalid-feedback" data-sb-feedback="phone:required">A phone number is required.</div>
                            </div>
                            <!-- Message input-->
                            <div class="form-floating mb-3">
                                <textarea class="form-control" id="message" type="text" placeholder="Enter your message here..." style="height: 10rem" data-sb-validations="required"></textarea>
                                <label for="message">Message</label>
                                <div class="invalid-feedback" data-sb-feedback="message:required">A message is required.</div>
                            </div>
                            <!-- Submit success message-->
                            <!---->
                            <!-- This is what your users will see when the form-->
                            <!-- has successfully submitted-->
                            <div class="d-none" id="submitSuccessMessage">
                                <div class="text-center mb-3">
                                    <div class="fw-bolder">Form submission successful!</div>
                                    To activate this form, sign up at
                                    <br />
                                    <a href="https://startbootstrap.com/solution/contact-forms">https://startbootstrap.com/solution/contact-forms</a>
                                </div>
                            </div>
                            <!-- Submit error message-->
                            <!---->
                            <!-- This is what your users will see when there is-->
                            <!-- an error submitting the form-->
                            <div class="d-none" id="submitErrorMessage"><div class="text-center text-danger mb-3">Error sending message!</div></div>
                            <!-- Submit Button-->
                            <div class="d-grid"><button class="btn btn-primary rounded-pill btn-lg disabled" id="submitButton" type="submit">Submit</button></div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
        <!-- Bootstrap core JS-->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
        <!-- Core theme JS-->
        <script src="js/scripts.js"></script>
        <!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *-->
        <!-- * *                               SB Forms JS                               * *-->
        <!-- * * Activate your form at https://startbootstrap.com/solution/contact-forms * *-->
        <!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *-->
        <script src="https://cdn.startbootstrap.com/sb-forms-latest.js"></script>
    </body>
</html>

 menu.html

인덱스에 있는 head, footer, navigation(menu)을 menu.html에 나눠서 넣어줌.

<th:block th:fragment="head"> </th:block>
<th:block th:fragment="footer"> </th:block>
<th:block th:fragment="menu"> </th:block>

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<body>

	<!-- 이렇게 menu.html에 여러가지 구역을 나눠서 필요한 거만 가져다가 씀 -->
	<th:block th:fragment="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>New Age - Start Bootstrap Theme</title>
		<link rel="icon" type="image/x-icon" href="assets/favicon.ico" />
		<!-- Bootstrap icons-->
		<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css" rel="stylesheet" />
		<!-- Google fonts-->
		<link rel="preconnect" href="https://fonts.gstatic.com" />
		<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,wght@0,600;1,600&amp;display=swap" rel="stylesheet" />
		<link href="https://fonts.googleapis.com/css2?family=Mulish:ital,wght@0,300;0,500;0,600;0,700;1,300;1,500;1,600;1,700&amp;display=swap" rel="stylesheet" />
		<link href="https://fonts.googleapis.com/css2?family=Kanit:ital,wght@0,400;1,400&amp;display=swap" rel="stylesheet" />
		<!-- Core theme CSS (includes Bootstrap)-->
		<link href="css/styles.css" rel="stylesheet" />
	</th:block>

	<!-- Footer-->
	<!-- th:block없이 바로 footer에 삽입해도 됨. -->
	<footer class="bg-black text-center py-5 fixed-bottom" th:fragment="footer">
		<div class="container px-5">
			<div class="text-white-50 small">
				<div class="mb-2">&copy; Your Website 2023. All Rights Reserved.</div>
				<a href="#!">Privacy</a> <span class="mx-1">&middot;</span> <a href="#!">Terms</a> <span class="mx-1">&middot;</span> <a href="#!">FAQ</a>
			</div>
		</div>
	</footer>

	<th:block th:fragment="menu">
		<!-- Navigation-->
		<nav class="navbar navbar-expand-lg navbar-light fixed-top shadow- sm" id="mainNav">
			<div class="container px-5">
				<a class="navbar-brand fw-bold" href="#page-top">Start Bootstrap</a>
				<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
					Menu <i class="bi-list"></i>
				</button>
				<div class="collapse navbar-collapse" id="navbarResponsive">
					<ul class="navbar-nav ms-auto me-4 my-3 my-lg-0">
						<li class="nav-item"><a class="nav-link me-lg-3" href="/freeboard">Freeboard</a></li>
						<li class="nav-item"><a class="nav-link me-lg-3" href="/notice">Notice</a></li>
					</ul>
					<button class="btn btn-primary rounded-pill px-3 mb-2 mb-lg-0" data-bs-toggle="modal" data-bs-target="#feedbackModal">
						<span class="d-flex align-items-center"> <i class="bi-chat-text-fill me-2"></i> <span class="small">Send Feedback</span>
						</span>
					</button>
				</div>
			</div>
		</nav>
	</th:block>
</body>
</html>

 

index.html

각각 맞는 위치에 th:block 넣어주기.

	<!-- menu -->
	<th:block th:insert="~{menu.html :: head}"/>
	
	<!-- Navigation -->
	<th:block th:insert="~{menu.html :: menu}"/>
			
	<!-- footer -->
	<th:block th:insert="~{menu.html :: footer}"/>
반응형

댓글