목차 | |
1. | list |
2. | layout |
3. | DB |
1. list
◈ TestController.java
package com.example.demo;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.*;
import java.util.stream.IntStream;
@Slf4j
@Controller
public class TestController {
private static final Logger log = LoggerFactory.getLogger(TestController.class);
@GetMapping("/")
public String index(Model m){
m.addAttribute("msg","Test Thymeleaf World!!");
List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee","fff");
m.addAttribute("list", list);
return "index";
}
/* /ex01 => 리스트를 /ex/ex01.html 전송*/
@GetMapping("/ex01")
public String ex01(Model m){
List<String> list = Arrays.asList("영이","철수","영철","길동","순신");
m.addAttribute("list", list);
return "/ex/ex01";
}
@GetMapping("/ex02")
public String ex02(@RequestParam("name")String name, @RequestParam("age")int age, Model m){
log.info("name : {}", name);
log.info("age : {}", age);
TestVO tvo = new TestVO("a","b","c");
m.addAttribute("tvo",tvo);
return "/ex/ex02";
}
@GetMapping("/ex03")
public String ex03(Model m){
List<String> strList = IntStream.range(1,10).mapToObj(i -> "data "+i).toList();
m.addAttribute("strList", strList);
log.info("strList {}", strList);
Map<String, Integer> map = new HashMap<>();
map.put("apple",500);
map.put("orange",600);
map.put("banana",300);
map.put("kiwi",700);
m.addAttribute("map",map);
List<TestVO> testList = new ArrayList<>();
testList.add(new TestVO("value-p1", "value-p2", "value-p3"));
testList.add(new TestVO("value-p1-1", "value-p2-1", "value-p3-1"));
testList.add(new TestVO("value-p1-2", "value-p2-2", "value-p3-2"));
m.addAttribute("testList", testList);
return "/ex/ex03";
}
}
2. layout
◈ bulid.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.11'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
◈ header.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<!-- th:fragment="이름" : 레이아웃에서 사용할 조각 -->
<div th:fragment="header">
<h1>Header Area</h1>
</div>
◈ footer.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<div th:fragment="footer">
<h1>footer Area</h1>
</div>
◈ layout.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8">
<title>My Thymeleaf Test</title>
</head>
<body>
<!-- <div th:replace="~{조각 파일의 경로 :: 이름}"></div> -->
<div th:replace="~{fragments/header :: header}"></div>
<div layout:fragment="content"></div>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
◈ index.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}">
<!-- layout:decorate="~{파일경로}" => layout 파일 경로의 변경 영역 지정 -->
<div layout:fragment="content">
<h1>${msg}</h1>
<h1 th:text="${msg}"></h1>
<h1>[[${msg}]]</h1>
<hr>
<h1>[[${list}]]</h1>
<h1 th:text="${list}"></h1>
<!-- th:each를 이용하여 반복값을 출력 -->
<ul>
<li th:each="str:${list}" th:text="${str}"></li>
</ul>
<hr>
<ul>
<li th:each="str:${list}">[[${str}]]</li>
</ul>
<ul>
<li th:each="str, status:${list}">
[[${status.count}]] --- [[${str}]]
</li>
</ul>
<hr>
<ul>
<li th:each="str, status:${list}">
<span th:if="${status.odd}">ODD --- [[${str}]]</span>
<span th:unless="${status.odd}">EVEN(unless) --- [[${str}]]</span>
</li>
</ul>
<hr>
<ul>
<li th:each="str, status:${list}">
<span th:text="${status.odd} ? 'odd - ' + '${str}' : 'even - ' + '${str}'"></span>
</li>
</ul>
<hr>
<ul>
<li th:each="str, status:${list}">
<th:block th:switch="${status.index % 3}">
<span th:case="0">0 -- [[${str}]]</span>
<span th:case="1">1 -- [[${str}]]</span>
<span th:case="2">2 -- [[${str}]]</span>
</th:block>
</li>
</ul>
<hr>
<th:block th:with="num1=${10}, num2=${20}">
<span>[[${num1+num2}]]</span>
</th:block>
<a th:href="@{/ex01}"><button type="button">Go to ex01</button></a>
</div>
◈ ex01.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}">
<div layout:fragment="content">
<h1>Controller에서 보낸 리스트를 인라인 방식으로 출력</h1>
[[${list}]]
<ul>
<li th:each="str:${list}" th:text="${str}"></li>
</ul>
<a href="/ex02?name=hong&age=20">Go To /ex02</a> <br>
<a th:href="@{/ex02(name='kim', age='30')}">Go To /ex02</a>
</div>
◈ ex02.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}">
<!-- layout:decorate="~{파일경로}" => layout 파일 경로의 변경 영역 지정 -->
<div layout:fragment="content">
<h1> EX02 HTML page</h1>
<h1>[[${param.name}]]</h1>
<h1>[[${param.age}]]</h1>
<h1>[[${tvo}]]</h1>
<a th:href="@{/ex03}">
<button type="button">Go to ex03</button>
</a>
</div>
</html>
◈ ex03.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}">
<!-- layout:decorate="~{파일경로}" => layout 파일 경로의 변경 영역 지정 -->
<div layout:fragment="content">
<h1>Ex03 page</h1>
<div>[[${strList}]]</div>
<div th:text="${strList}"></div>
<div>[[${map}]]</div>
<div>[[${map.apple}]]</div>
<th:block th:each="testvo:${testList}">
<div>[[${testvo.p1}]]</div>
<div>[[${testvo.p2}]]</div>
<div>[[${testvo.p3}]]</div>
</th:block>
<script th:inline="javascript">
const list= [[${strList}]];
console.log(list);
</script>
<script th:inline="javascript">
const strList = [[${strList}]];
console.log(strList);
</script>
</div>
</html>
▷ 출력
3. DB
- 새 프로젝트(이름 : spring) 생성 후
◈ bulid.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.11'
id 'io.spring.dependency-management' version '1.1.6'
}
group = 'com.ezen'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
◈ DatabaseConfig.java
package com.ezen.spring.config;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
import java.nio.file.PathMatcher;
@Configuration
@PropertySource("classpath:/application.properties")
public class DatabaseConfig {
@Autowired
private ApplicationContext applicationContext;
@Value("${mybatis.mapper-locations}")
private String mapperLocations;
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public HikariConfig hikariConfig(){
return new HikariConfig();
}
@Bean
public DataSource dataSource() throws Exception{
return new HikariDataSource(hikariConfig());
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception{
SqlSessionFactoryBean sqlSessionFactoryBean =
new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
/* mybatis-config.xml 존재할 경우*/
sqlSessionFactoryBean.setConfigLocation(
applicationContext.getResource("classpath:/mybatis-config.xml")
);
sqlSessionFactoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResources(mapperLocations));
return sqlSessionFactoryBean.getObject();
}
@Bean
public org.apache.ibatis.session.Configuration mybatisConfig(){
return new org.apache.ibatis.session.Configuration();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
}
◈ mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
◈ BoardController.java
package com.ezen.spring.controller;
import com.ezen.spring.domain.BoardVO;
import com.ezen.spring.service.BoardService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/board/*")
@RequiredArgsConstructor
@Slf4j
@Controller
public class BoardController {
private final BoardService bsv;
@GetMapping("/register")
public String register(){
return"/board/register";
}
@PostMapping("/register")
public String register(BoardVO boardVO){
log.info(">>>> boardVO >>>> {}", boardVO);
int isOk = bsv.register(boardVO);
return "index";
}
@GetMapping("/list")
public String list(Model m){
m.addAttribute("list", bsv.getList());
return"/board/list";
}
}
◈ BoardVO.java
package com.ezen.spring.domain;
import lombok.*;
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BoardVO {
private long bno;
private String title;
private String writer;
private String content;
private String regDate;
}
◈ BoardService.java
package com.ezen.spring.service;
import com.ezen.spring.domain.BoardVO;
import java.util.List;
public interface BoardService {
int register(BoardVO boardVO);
List<BoardVO> getList();
}
◈ BoardServiceImpl.java
package com.ezen.spring.service;
import com.ezen.spring.domain.BoardVO;
import com.ezen.spring.repository.BoardMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@RequiredArgsConstructor
@Service
public class BoardServiceImpl implements BoardService{
private final BoardMapper boardMapper;
@Override
public int register(BoardVO boardVO) {
return boardMapper.register(boardVO);
}
@Override
public List<BoardVO> getList() {
return boardMapper.getList();
}
}
◈ BoardMapper.java
package com.ezen.spring.repository;
import com.ezen.spring.domain.BoardVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface BoardMapper {
int register(BoardVO boardVO);
List<BoardVO> getList();
}
◈ index.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}">
<div layout:fragment="content">
<div class="container-md">
<h1>My String Boot Project</h1>
</div>
</div>
◈ layout.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 부트스태랩 css js 링크 연결 -->
<link rel="sylesheet" th:href="@{/dist/css/bootstrap.min.css}">
<script th:src="@{/dist/js/bootstrap.bundle.min.js}"></script>
</head>
<body>
<!-- <div th:replace="~{조각 파일의 경로 :: 이름}"></div> -->
<div th:replace="~{fragments/header :: header}"></div>
<div layout:fragment="content"></div>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
◈ header.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<!-- th:fragment="이름" : 레이아웃에서 사용할 조각 -->
<div th:fragment="header" class="container">
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">Boot</a>
<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 me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/board/register">BoardRegister</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/board/list">BoardList</a>
</li>
</ul>
</div>
</div>
</nav>
<h5>Header Area</h5>
</div>
◈ footer.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<!-- th:fragment="이름" : 레이아웃에서 사용할 조각 -->
<div th:fragment="footer">
<h5>Footer Area</h5>
</div>
◈ register.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}">
<div layout:fragment="content" class="container-md">
<h1>Boot Register page</h1>
<hr>
<form action="/board/register" method="post">
<div class="mb-3">
<label for="t" class="form-label">Title</label>
<input type="text" class="form-control" name="title" id="t" placeholder="title...">
</div>
<div class="mb-3">
<label for="w" class="form-label">Writer</label>
<input type="text" class="form-control" name="writer" id="w" placeholder="writer...">
</div>
<div class="mb-3">
<label for="c" class="form-label">Content</label>
<textarea class="form-control" name="content" id="c" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-primary">register</button>
</form>
</div>
◈ list.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/layout}">
<div layout:fragment="content" class="container-md">
<h1>Boot List page</h1>
<hr>
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>title</th>
<th>writer</th>
<th>regDate</th>
</tr>
</thead>
<tbody>
<tr th:each="bvo:${list}">
<td>[[${bvo.bno}]]</td>
<td>[[${bvo.title}]]</td>
<td>[[${bvo.writer}]]</td>
<td>[[${bvo.regDate}]]</td>
</tr>
</tbody>
<tfoot></tfoot>
</table>
</div>
◈ ApplicationTests.java
package com.ezen.spring;
import com.ezen.spring.domain.BoardVO;
import com.ezen.spring.repository.BoardMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ApplicationTests {
@Autowired
private BoardMapper boardMapper;
@Test
void contextLoads() {
for(int i=0; i<300; i++){
BoardVO boardVO = BoardVO.builder()
.title("test title " + i)
.writer("tester"+((int)(Math.random()*100)+1))
.content("test content " + i)
.build();
boardMapper.register(boardVO);
}
}
}
▷ 출력
'Java > Spring Boot' 카테고리의 다른 글
Spring Boot 기초(security) - AWS 풀스택 과정 81일차 (0) | 2024.11.20 |
---|---|
Spring Boot 기초(comment) - AWS 풀스택 과정 80일차 (0) | 2024.11.19 |
Spring Boot 기초(file) - AWS 풀스택 과정 79일차 (0) | 2024.11.18 |
Spring Boot 기초(paging) - AWS 풀스택 과정 78일차 (0) | 2024.11.15 |
Spring Boot 설정 및 기초 - AWS 풀스택 과정 76일차 (0) | 2024.11.13 |