본문 바로가기

복습/전자정부-게시판만들기

20240309 전자정부 복습(프로젝트생성~디테일jsp 만들기)

프로젝트 만들기 > myweb

new>project>Spring Boot>Spring Starter Project

 

 

 

이미 만든 프로젝트명이라 오류가 난다.

 

 

 

New Spring Starter Project Dependencies 추가

 

 

 

 

application.properties 설정

# DB
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.myhand.web.dto
# 페이지 구동되면 아래 static 하위 폴더들이 먼저 실행 됨
mybatis.mapper-locations=static/mapper/*.xml 

# 포트변경시
server.port=80

#session time out = 1800 ->30분
server.servlet.session.timeout=1800

 

 

 

 

build.gradle> dependencies 추가된 사항 확인

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
	

	implementation	'org.mariadb.jdbc:mariadb-java-client:3.0.8'
	
	compileOnly 'org.projectlombok:lombok'
	developmentOnly 'org.springframework.boot:spring-boot-devtools'
	runtimeOnly 'com.mysql:mysql-connector-j'
	annotationProcessor 'org.projectlombok:lombok'
	providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3'
}

 

 

 

 

 

controller 패키지, 클래스 생성

이미 만든 패키지, 클래스여서 오류가 난다.

 

 

어노테이션 설정

package com.myhand.web.controller;

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

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

}

 

 

 

 

 

resources> templates >index.hrml 생성

 

 

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>나는 인덱스</title>
</head>
<body>
	<h1>나는 인덱스입니다. </h1>
</body>
</html>

 

 

구동 화면

 

 

 

 

 

데이터 보내기

 

IndexController

@Controller
public class IndexController {
	@GetMapping("/index")
	public String index(Model model) {
		model.addAttribute("test", "테스트 입니다.");
		return "index";
	}

}

 

'/index' 경로로 GET 요청이 들어오면 'index' 메소드가 호출되고, 이 메소드는 Model  객체를 매개변수로 받아 뷰(html)에 데이터 > "테스트 입니다." 라는 문자열을 'test'라는 이름으로 값을 추가한다.

 

'/index' URL로 들어오면  GET요청을 처리하는 메서드, Model 객체를 매개변수로 받아, 뷰에 데이터를 전달하는 역할이다.

 

'return "index";' 구문은 'index'라는 이름의 뷰를 찾아 응답으로 렌더링 하는 의미이다.

Thymeleaf를 사용하기 때문에 'src/main/resources/templates ' 디렉토리 아래 'index.html' 파일의 뷰를 열어준다.

 

 

 

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>나는 인덱스</title>
</head>
<body>
	<h1>나는 인덱스입니다. </h1>
	[[${test}]]<br>
</body>
</html>

 

 

localhost로 접근하면 나오는 페이지.

 

 

localhost/index로 접근하면 나오는 페이지

 

 

[[${test}]]의 또다른 방법으로 출력할 수 있다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>나는 인덱스</title>
</head>
<body>
	<h1>나는 인덱스입니다. </h1>

	<th:block th:text="${test}"></th:block>
</body>
</html>

'th:text' 속성을 사용해서 test 변수의 값을 표시한다. > 테스트 입니다. 출력

 

 

 

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>나는 인덱스</title>
</head>
<body>
	<h1>나는 인덱스입니다.</h1>
	[[${test}]]
	<br>
	<th:block th:text="${test}"></th:block>
</body>
</html>

 

 

 

 

 

board 불러오기

 

IndexController

 

 

 

IndexService 생성해서 @Autowired로 연결

package com.myhand.web.controller;

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

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

import com.myhand.web.service.IndexService;

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

}

 

 

IndexService와 연결

	@Autowired
	private IndexService indexService;

 

 

 

게시판 목록 가져와서 뷰(html)로 반환

	@GetMapping("/index")
	public String index(Model model) {
		model.addAttribute("test", "테스트 입니다.");
		
		List<Map<String, Object>> list = indexService.baordList();//게시판 목록을 가져온다.
		model.addAttribute("list", list);//가져온 목록을 모델에 추가
		return "index"; //뷰 이름을 반환
	}

 

 

 

 

com.myhand.web.service 패키지 생성, IndexService 클래스 생성

어노테이션 설정

package com.myhand.web.service;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.myhand.web.dao.IndexDAO;
@Service
public class IndexService {
	
	@Autowired
	private IndexDAO indexDAO;

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

}

> IndexDAO 생성해서 indexDAO.boardList로 연결

 

 

 

 

 

 

com.myhand.web.dao 패키지 생성, IndexDAO 인터페이스 생성

어노테이션 설정 > 매퍼까지 함께 설정

package com.myhand.web.dao;

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();

}

 

 

 

static > mapper 폴더 생성 > new > other> myBatis XML Mapper >indexMapper 생성

 

 

 

mapper namespace 변경

<?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.myhand.web.dao.IndexDAO"></mapper>

 

 

 

쿼리문 삽입

<select id="boardList" resultType="Map">
SELECT board_no, board_title, board_write, board_date, board_count, comment
FROM boardview
LIMIT 0,10

</select>

 

 

 

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>나는 인덱스</title>
</head>
<body>
	<h1>나는 인덱스입니다.</h1>

	<table>
		<thead>
			<tr>
				<th>번호</th>
				<th>제목</th>
				<th>글쓴이</th>
				<th>날짜</th>
				<th>조회수</th>
			</tr>
		</thead>
		<tbody>
			<tr th:each="row : ${list}">
				<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>

 

 

동적으로 데이터를 포함하는 테이블 만들기

<table> 태그:  테이블 정의

<thead>태그 : 테이블의 헤더 부분을 정의 >테이블의 컬럼명을 담고 있다.

<tbody>태그 : 테이블의 본문 부분을 정의 >  실제 데이터가 표시되는 영역

<tr th:each="row ${boardList}">~</tr> :boardList라는 이름의 객체 리스트를 순회하며 각 객체를 row라는 변수로 참조, model에 추가된 boardList 객체를 사용

 

이 테이블은 서버로부터 받은 boardList라는 리스트 객체를 화면에 표시합니다. boardList는 게시판의 글 목록을 담고 있는 객체의 리스트로, 각 객체는 게시글의 번호, 제목, 글쓴이, 날짜, 조회수 등의 정보를 가지고 있습니다. Thymeleaf의 th:each 지시어를 사용하여 이 리스트를 반복 처리하고, 각 게시글에 대한 정보를 테이블의 각 행에 표시합니다.

 

 

출력되는 index 페이지

 

성공!

 

 

 

multiboard 만들기

 

freeboard생성

 

>controller, service, dao, mapper 생성하기(dto 안쓰게 만들기>map사용)

 

 

IndexController > freebaord 생성

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

 

 

 

 

IndexService > freeboard

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

 

 

 

 

IndexDAO

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

 

 

 

indexMapper

	<select id="freeboard" resultType="Map">
		SELECT mtno, mttitle, mtcontent, mtdate, mtip, mtdel, mtread, mtcate, mno FROM multiboard
	</select>

 

 

 

freeboard.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>나는 프리보드!!</title>
</head>
<body>
	<h1>나는 프리보드임댜</h1>

	<table>
		<thead>
			<tr>
				<th>번호</th>
				<th>제목</th>
				<th>날짜</th>
				<th>조회수</th>
			</tr>
		</thead>
		<tbody>
			<tr th:each="row : ${board}">
				<td th:text="${row.mtno}"></td>
				<td th:text="${row.mttitle}"></td>
				<td th:text="${row.mtdate}"></td>
				<td th:text="${row.mtread}"></td>
			</tr>
		</tbody>

	</table>

</body>
</html>

 

 

 

 

 

부트스트랩 설정하기

 

https://startbootstrap.com/theme/new-age

 

Start Bootstrap

 

startbootstrap.com

 

사용하려는 부트스트랩 다운받아서 index 소스 코드 내 index.html에 넣기

 

나머지 파일들 저장하기

 

 

 

 

 

 

menu.html 만들기

 

상단에 thymeleaf 추가하기

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

 

 

 

index에 있는 <head> 부분 가져오기

>

<th:block th:fragment="head">  으로 구역을 나눠서 다른 파일에서도 쓸 수 있게 해준다.

 

<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)-->
        <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
        <link href="css/styles.css" rel="stylesheet" />
</th:block>

 

 

<th:block th:fragment="menu">

<th:block th:fragment="menu">

		<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="/">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?cate=1">freeboard</a></li>
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/notice?cate=2">notice</a></li>
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/notice?cate=3">notice</a></li>
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/notice?cate=4">notice</a></li>
                        <th:block th:if="${session.mid ne null}">
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/myInfo">[[${session.mname}]]님</a></li>
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/logout">logout</a></li>
                        </th:block>
                        <th:block th:unless="${session.mid ne null}">
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/login">login</a></li>
                        </th:block>
                    </ul>
                </div>
            </div>
        </nav>

</th:block>

 

 

메뉴 전체 코드

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

<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)-->
        <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
        <link href="css/styles.css" rel="stylesheet" />
</th:block>

		<footer class="bg-black text-center py-5" 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">

		<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="/">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?cate=1">freeboard</a></li>
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/notice?cate=2">notice</a></li>
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/notice?cate=3">notice</a></li>
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/notice?cate=4">notice</a></li>
                        <th:block th:if="${session.mid ne null}">
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/myInfo">[[${session.mname}]]님</a></li>
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/logout">logout</a></li>
                        </th:block>
                        <th:block th:unless="${session.mid ne null}">
                        <li class="nav-item"><a class="nav-link me-lg-3" href="/login">login</a></li>
                        </th:block>
                    </ul>
                </div>
            </div>
        </nav>

</th:block>


</body>
</html>

 

 

 

index.html 변경 부분

 

상단에 추가

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

 

 

 

<head>에 추가

    <head>
        <th:block th:insert="~{menu.html :: head}"></th:block>
    </head>

 

 

 

<!-- Navigation--> 부분 메뉴 추가

 <!-- Navigation-->
        <th:block th:insert="~{menu.html :: menu}"></th:block>

 

 

 

 

freeboard 부트스트랩 설정하기

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://thymeleaf.org">
    <head>
        <th:block th:insert="~{menu.html :: head}"></th:block>
    </head>
    <body id="page-top">
        <!-- Navigation-->
        <th:block th:insert="~{menu.html :: menu}"></th:block>
        <!-- Mashead header-->
        
                      
        <!-- Quote/testimonial aside-->
        <aside class="text-center">
            <div class="container px-5">
            <span>[[${#lists.size(board)} ]]개 글이 있습니다.</span>
            <div th:if="${#lists.size(board) le 0}">
            	<h2>출력할 데이터가 없습니다 </h2>
            	<h3>관리자에게 문의하세요.</h3>
            </div>
            <div th:unless="${#lists.size(board) lt 0}">
				<div class="table table-hover">
					<div class="row" th:each="row : ${board }">
						<div class="col-1" th:text="${row.mtno }"></div>
						<div class="col-5 text-start" th:onclick="|location.href='@{/detail(no=${row.mtno})}'|">[[${row.mttitle }]]</div>
						<div class="col-3" th:text="${row.mname }"></div>
						<div class="col-2" th:text="${row.mtdate }"></div>
						<div class="col-1" th:text="${row.mtread }"></div>
					</div>
				</div>
				
				<button type="button" th:with="cate=${board[0].mtcate}"
					class="btn btn-primary"	th:onclick="|location.href='@{/write(cate=${cate})}'|">글쓰기</button>

                    </div>
                </div>
            </div>
        </aside>
        <!-- App features section-->
       
                      
        <!-- Footer-->
        	<th:block th:insert="~{menu.html :: footer}"></th:block>
      
        <!-- Feedback Modal-->
       
    </body>
</html>

 

 

 

다음엔 멀티보드 연결해서 글쓰기까지 가져오기

<div class="col-5 text-start" 
th:onclick="|location.href='@{/detail(no=${row.mtno})}'|">[[${row.mttitle }]]</div>

이렇게 detail로 연결하면

 

mtno가 찍힌다.