본문 바로가기

IntelliJ/Spring boot

[Springboot]게시판 만들기 1장 프로젝트 설정 및 테이블 생성 - hoyhi

1. 프로젝트 생성

 

2. build.gradle -> dependencies 에 코드 추가

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    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'
    
    //여기부터 2줄 추가
    compile group: 'org.mariadb.jdbc', name: 'mariadb-java-client'
    compile group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-java8time'

}

 

3. application.properties 에 코드 추가

spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:3307/bootex
spring.datasource.username=root
spring.datasource.password=root

spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true

spring.thymeleaf.cache=false

 

4. resources -> static 폴더 안에 복사

static.zip
1.05MB

 

5. templates -> layout 폴더 아래에 basic.html , layout.html 파일 생성

 

basic.html

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

<th:block th:fragment="setContent(content)">
    <head>

<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>

    <title>Simple Sidebar - Start Bootstrap Template</title>

    <!-- Bootstrap core CSS -->
    <link th:href="@{/vendor/bootstrap/css/bootstrap.min.css}" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link th:href="@{/css/simple-sidebar.css}" rel="stylesheet">

    <!-- Bootstrap core JavaScript -->
    <script th:src="@{/vendor/jquery/jquery.min.js}"></script>
    <script th:src="@{/vendor/bootstrap/js/bootstrap.bundle.min.js}"></script>

</head>

<body>

<div class="d-flex" id="wrapper">

    <!-- Sidebar -->
    <div class="bg-light border-right" id="sidebar-wrapper">
        <div class="sidebar-heading">Start Bootstrap </div>
        <div class="list-group list-group-flush">
            <a href="#" class="list-group-item list-group-item-action bg-light">Dashboard</a>
            <a href="#" class="list-group-item list-group-item-action bg-light">Shortcuts</a>
            <a href="#" class="list-group-item list-group-item-action bg-light">Overview</a>
            <a href="#" class="list-group-item list-group-item-action bg-light">Events</a>
            <a href="#" class="list-group-item list-group-item-action bg-light">Profile</a>
            <a href="#" class="list-group-item list-group-item-action bg-light">Status</a>
        </div>
    </div>
    <!-- /#sidebar-wrapper -->

    <!-- Page Content -->
    <div id="page-content-wrapper">

        <nav class="navbar navbar-expand-lg navbar-light bg-light border-bottom">
            <button class="btn btn-primary" id="menu-toggle">Toggle Menu</button>

            <button class="navbar-toggler" type="button" data-toggle="collapse" data-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 ml-auto mt-2 mt-lg-0">
                    <li class="nav-item active">
                        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></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" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                            Dropdown
                        </a>
                        <div class="dropdown-menu dropdown-menu-right" 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>
        </nav>

        <div class="container-fluid">

            <th:block th:replace = "${content}"></th:block>

        </div>

    </div>
    <!-- /#page-content-wrapper -->

</div>
<!-- /#wrapper -->




<!-- Menu Toggle Script -->
<script>
    $("#menu-toggle").click(function(e) {
        e.preventDefault();
        $("#wrapper").toggleClass("toggled");
    });
</script>

</body>
</th:block>
</html>

 

layout.html

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


<th:block th:fragment="setContent(content)">

    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>

<body>

<style>
    * {
        margin: 0;
        padding: 0;
    }
    .header {
        width:100vw;
        height: 20vh;
        background-color: aqua;
    }
    .content {
        width: 100vw;
        height: 70vh;
        background-color: lightgray;
    }
    .footer {
        width: 100vw;
        height: 10vh;
        background-color: green;
    }
</style>


<div class="header">
    <h1>HEADER</h1>
</div>
<div class="content" >

    <th:block th:replace = "${content}">
    </th:block>

</div>

<div class="footer">
    <h1>FOOTER</h1>
</div>

</body>
</th:block>
</html>

 

 

 

6. GuestbookController 클래스 생성

package com.example.chapter4.controller;

import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/guestbook")
@Log4j2
public class GuestbookController {
    @GetMapping({"/", "/list"})
    public String list(){
        log.info("list..................");
        return "/guestbook/list";
    }
}

 

7. list.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>GuestBook List Page</h1>
    </th:block>
</th:block>

 

 

8. BaseEntity 생성

package com.example.chapter4.Entity;

import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.Column;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;

//객체의 입장에서 공통 매핑 정보가 필요할때 사용
//테이블로 생성되지않음 -> 실제 테이블은 BaseEntity를 상속한 엔티티 클래스로 생성
@MappedSuperclass

//엔티티 객체에 어떠한 변화가 일어나는 것을 감지하는 리스너
@EntityListeners(value = {AuditingEntityListener.class})
@Getter
abstract class BaseEntity {

    @CreatedDate
    //updateable = false : 해당 엔티티 객체를 DB에 반영할 때 regdate 칼럼 값은 변경 X
    @Column(name="regdate", updatable = false)
    private LocalDateTime regDate;

    @LastModifiedDate
    @Column(name="moddate")
    private LocalDateTime modDate;

}

 

9. Chapter4Application 클래스 코드 추가

package com.example.chapter4;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication

//AuditingEntityListener 활성화
@EnableJpaAuditing
public class Chapter4Application {

    public static void main(String[] args) {
        SpringApplication.run(Chapter4Application.class, args);
    }

}

 

10. Guestbook 클래스 추가

package com.example.chapter4.Entity;

import lombok.*;

import javax.persistence.*;

@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Guestbook extends BaseEntity{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long gno;

    @Column(length = 100, nullable = false)
    private String title;

    @Column(length = 1500, nullable = false)
    private String content;

    @Column(length = 50, nullable = false)
    private String writer;

}

 

11. 프로젝트 실행

Heidi SQL