//Spring Boot + Thymeleaf
- New > Spring Starter Project
~ Name > boot-thymeleaf
~ Package > com.test.thymeleaf
~ Spring Boot Version > 2.7.13
~ Spring Web
~ Oracle Driver
~ MyBatis Framework
~ Lombok
~ SpringBoot Dev Tools
~ Thymeleaf
// Thymeleaf Standard Expression, 타임리프 표현식
1. Variable Expression, 변수 표현식
- ${}
- 컨트롤러 > 전달된 값 출력
2. Selection Variable Expression, 선택 변수 표현식
- *{}
- 객체/맵 프로퍼티 출력
- th:object 속성과 같이 사용
3. Message Expression, 메시지 표현식
- #{}
- 스프링 메시지 전용 출력(특수)
4. Link URL Expression, 링크 주소 표현식
- @{}
- 링크의 URL 전용 출력(특수)
5. Fragment Expression, 조각 표현식
- ~{}
- 조각 페이지 삽입(include 지시자 or tiles와 유사한 기능)
- MyBatis + Thyemleaf 설정
~ application.properties
# 톰캣 포트 번호
server.port = 8092
# HikariCP settings
spring.datasource.hikari.minimumIdle=5
spring.datasource.hikari.maximumPoolSize=20
spring.datasource.hikari.idleTimeout=30000
spring.datasource.hikari.maxLifetime=2000000
spring.datasource.hikari.connectionTimeout=30000
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=hr
spring.datasource.password=java1234
# Thymeleaf
spring.thymeleaf.enabled=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
# cache 활성화 > 개발 시에는 false
spring.thymeleaf.cache=false
spring.thymeleaf.encoding=UTF-8
# MyBatis > 패키지 별칭
# mybatis.type-aliases-package=com.test.domain
# MyBatis > 클래스 별칭
mybatis.config-location=classpath:mybatis-config.xml
# 스프링 메시지
spring.messages.basename=messages
spring.messages.encoding=UTF-8
~ "com.test.mapper" > "ThymeleafMapper.java"(I)
package com.test.mapper;
import java.util.List;
import com.test.domain.BoardDTO;
public interface ThymeleafMapper {
int getNum();
String getTxt();
BoardDTO getDTO();
List<String> getNames();
List<BoardDTO> getList();
}
~ "com.test.domain" > "BoardDTO.java"
package com.test.domain;
import lombok.Data;
@Data
public class BoardDTO {
private String seq;
private String id;
private String subject;
private String content;
private String regdate;
}
~ "com.test.controller" > "ThymeleafController.java"
package com.test.controller;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpSession;
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.test.domain.BoardDTO;
import com.test.mapper.ThymeleafMapper;
@Controller
public class ThymeleafController {
@Autowired
private ThymeleafMapper mapper;
@GetMapping("/m1")
public void m1() {
//요청 메소드의 반환값 > void > m1.html (thymeleaf suffix 설정대로 호출)
System.out.println("m1");
}
//페이지 요청
//1. 동적 페이지("m2.html") > localhost:8092/m2
//2. 정적 페이지("m2.html") > localhost:8092/m2.html
// * 정적 페이지와 동적 페이지 url이 완전히 똑같아서 충돌할 땐 동적 페이지 win
@GetMapping("/m2")
public String m2() {
//templates > m2.html
return "m2";
}
@GetMapping("/m3")
public String m3(Model model) {
//단일값 출력
int num = mapper.getNum();
String txt = mapper.getTxt();
BoardDTO dto = mapper.getDTO();
Map<String,String> map = new HashMap<String, String>();
map.put("dog", "강아지");
map.put("cat", "고양이");
model.addAttribute("num", num);
model.addAttribute("txt", txt);
model.addAttribute("now", Calendar.getInstance());
model.addAttribute("dto", dto);
model.addAttribute("map", map);
return "m3";
}
@GetMapping("/m4")
public String m4(Model model) {
int a = 10;
int b = 3;
model.addAttribute("a", a);
model.addAttribute("b", b);
return "m4";
}
@GetMapping("/m5")
public String m5(Model model) {
model.addAttribute("name", "age");
model.addAttribute("size", 30);
model.addAttribute("color", "cornflowerblue");
return "m5";
}
@GetMapping("/m6")
public String m6(Model model) {
//PCDATA 출력
String name = mapper.getTxt();
BoardDTO dto = mapper.getDTO();
String txt = "안농하세요. <i>홍길동</i>입니다.";
int num = 100;
List<String> names = mapper.getNames();
model.addAttribute("name", name);
model.addAttribute("dto", dto);
model.addAttribute("txt", txt);
model.addAttribute("num", num);
model.addAttribute("names", names);
return "m6";
}
@GetMapping("/m7")
public String m7(Model model) {
int num1 = 1234567;
double num2 = 12345.6789;
Calendar now = Calendar.getInstance();
model.addAttribute("num1", num1);
model.addAttribute("num2", num2);
model.addAttribute("now", now);
return "m7";
}
@GetMapping("/m8")
public String m8(Model model) {
int seq = 10;
String mode = "add";
model.addAttribute("seq", seq);
model.addAttribute("mode", mode);
return "m8";
}
@GetMapping("/m9")
public String m9(Model model) {
int num1 = 100;
int num2 = 5;
String mode = "add";
model.addAttribute("num1", num1);
model.addAttribute("num2", num2);
model.addAttribute("mode", mode);
return "m9";
}
@GetMapping("/m10")
public String m10(Model model) {
List<String> names = mapper.getNames();
List<BoardDTO> list = mapper.getList();
model.addAttribute("names", names);
model.addAttribute("list", list);
return "m10";
}
@GetMapping("/m11")
public String m11(HttpSession session) {
session.setAttribute("id", "hong");
session.invalidate();
return "m11";
}
@GetMapping("/m12")
public String m12() {
return "m12";
}
}
~ src/main/resources > templates > "m1.html", "m2.html", "m3.html", "m4.html", "m5.html", "m6.html", "m7.html", "m8.html"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf</h1>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf</h1>
<div>m2.html</div>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf <small>단일값 출력</small></h1>
<h2>변수 표현식</h2>
<div>${num}</div>
<div th:text=${num}>200</div>
<div th:text="100"></div>
<h2>타입별</h2>
<div>숫자: 100</div>
<div th:text="${num}">숫자: </div>
<div>숫자: <span th:text="${num}"></span></div>
<div>텍스트: <span th:text="${txt}"></span></div>
<div>객체: <span th:text="${dto}"></span></div>
<div>맵: <span th:text="${map}"></span></div>
<!-- 변수 표현식 -->
<h2>복합 데이터(객체, 맵) 프로퍼티</h2>
<div>제목: <span th:text="${dto.getSubject()}"></span></div>
<div>제목: <span th:text="${dto.subject}"></span></div>
<div>아이디: <span th:text="${dto.id}"></span></div>
<div>날짜: <span th:text="${dto.regdate}"></span></div>
<!-- 선택 변수 표현식 -->
<div th:object = "${dto}">
<div>제목: <span th:text="*{subject}"></span></div>
<div>아이디: <span th:text="*{id}"></span></div>
<div>제목: <span th:text="*{regdate}"></span></div>
</div>
<hr>
<div th:text="${map.get('dog')}"></div>
<div th:text="${map.dog}"></div>
<div th:text="${map.cat}"></div>
<div th:object = "${map}">
<div th:text="*{dog}"></div>
<div th:text="*{cat}"></div>
</div>
<hr>
<h2>다국어 지원 <small>스프링 메시지</small></h2>
<div class="message" title="사용 언어" th:text="#{language}"></div>
<div class="message" title="상품">
<div>상품명: <span th:text="#{item.name}"></span></div>
<div>색상: <span th:text="#{item.color}"></span></div>
<div>가격: <span th:text="#{item.price}"></span></div>
</div>
<div th:text="#{hello('홍길동')}"></div>
<div th:text="#{hello(#{item.name})}"></div>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf</h1>
<!--
타임리프 연산자
- 산술 연산자 > 동일
- 비교 연산자 > 동일 + 영문
- 논리 연산자 > 동일 + 영문
- 삼항 연산자 > 동일
- 문자열 연산자 > 동일
-->
<div>10 + 3 = 13</div>
<div><span th:text="${a}"></span> + <span th:text="${b}"></span> = <span th:text="${a + b}"></span></div>
<div th:text="${a + ' + ' + b + ' = ' + (a + b)}"></div>
<div th:text="${a} + ' + ' + ${b} + ' = ' + ${a + b}"></div>
<div th:text="|홍길동|"></div>
<div th:text="|${a}|"></div>
<div th:text="|${a} + ${b} = ${a+b}|"></div>
<hr>
<div th:text="${a} + ${b}"></div>
<div th:text="${a} - ${b}"></div>
<div th:text="${a} * ${b}"></div>
<div th:text="${a} / ${b}"></div>
<div th:text="${a} % ${b}"></div>
<hr>
<div th:text="${a} > ${b}"></div>
<div th:text="${a} >= ${b}"></div>
<div th:text="${a} < ${b}"></div>
<div th:text="${a} <= ${b}"></div>
<div th:text="${a} == ${b}"></div>
<div th:text="${a} != ${b}"></div>
<hr>
<div th:text="${a > 5} and ${b < 10}"></div>
<div th:text="${a > 5} or ${b < 10}"></div>
<hr>
<div th:text="${a > 0} ? '양수' : '음수'"></div>
<hr>
<div th:text="${c} != null ? ${c} : '데이터 없음'"></div>
<div th:text="${c} ? ${c} : '데이터 없음'"></div>
<div th:text="${c} ?: '데이터 없음'"></div> <!-- Elvis 연산자 -->
<div th:text="${c} ?: _">데이터 없음</div> <!-- No-Operation -->
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
<style>
.one { color: gold; }
.two { text-decoration: underline; }
.three { font-size: 3rem; }
</style>
</head>
<body>
<h1>Thyemleaf + HTML Attribute</h1>
<!--
HTML 속성 조작
- th:HTML속성명="값"
- 기존에 동일한 속성이 선언되어 있으면 대체한다.
- 기존에 동일한 속성이 선언되어 있지 않으면 추가한다.
**대부분 서버에서 전달 받은 값(model)은
- 직접 표현식은 반드시 th:속성에만 적용이 가능
-->
<input type="text" name="age">
<input type="text" th:name="age">
<input type="text" name="${name}">
<input type="text" th:name="${name}">
<input type="text" th:name="${name}" th:size="${size}">
<input type="text" th:value="${color}">
<hr>
<div class="one">Box 1</div>
<div th:class="one">Box 2</div>
<div class="one" th:class="two">Box 3</div>
<div class="one" th:attrappend="class=' two'">Box 4</div>
<div class="one" th:attrprepend="class='two '">Box 5</div>
<div class="one" th:classappend="two">Box 6</div>
<input type="checkbox" name="cb" th:checked="true">
<input type="checkbox" name="cb" th:checked="false">
<div style="background-color:${color}">Box 7</div>
<div th:style="'background-color:'+${color}">Box 7</div>
<div th:style="|background-color:${color}|">Box 7</div>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf Text</h1>
<!--/*
HTML 콘텐츠 영억 > 데이터 출력
1. th:text
- escaped text
- '<' -> <
- '>' -> >
2. th:utext
- unexcaped text
- 그대로 출력
인라인 출력
1. th:inline="text" > 사용 잘 안 함
2. th:inline="javascript" > 많이 사용(필수)
1. th:inline + [[]] > escaped text
2. th:inline + [()] > unescaped text
*/-->
<div th:text="${txt}"></div>
<div th:utext="${txt}"></div>
<hr>
<div th:inline="text">[[${name}]]</div>
<div th:inline="text">[(${name})]</div>
<div th:inline="text">[[${txt}]]</div>
<div th:inline="text">[(${txt})]</div>
<div th:inline="text">[[${txt}]]</div>
<div th:inline="text">[(${txt})]</div>
<!--/*
<div th:inline="text">[[${a}]] + [[$b}]] = [[${a + b}]]</div>
*/-->
<div id="label1"></div>
<div id="label2"></div>
<script>
let name1 = '[[${name}]]';
let num1 = [[${num}]];
let names1 = '[[${names}]]';
let dto1 = '[[${dto}]]';
document.getElementById('label1').textContent = name1;
</script>
<script th:inline="javascript">
let name2 = [[${name}]];
let num2 = [[${num}]];
let names2 = [[${names}]];
let dto2 = [[${dto}]];
document.getElementById('label2').textContent = name2;
</script>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf Format</h1>
<!--
데이터를 일정한 형식으로 표현하는 도구
- #numbers
- #dates
-->
<h2>숫자</h2>
<div th:text="${num1}"></div>
<div th:text="${#numbers.formatInteger(num1, 10, 'COMMA')}"></div>
<div th:text="${#numbers.formatInteger(num1, 10, 'POINT')}"></div>
<div th:text="${num2}"></div>
<div th:text="${#numbers.formatDecimal(num2, 3, 'COMMA', 2, 'POINT')}"></div>
<h2>날짜</h2>
<!-- <div th:text="${now}"></div> -->
<div th:text="${#dates.year(now)}"></div>
<div th:text="${#dates.month(now)}"></div>
<div th:text="${#dates.monthName(now)}"></div>
<div th:text="${#dates.monthNameShort(now)}"></div>
<div th:text="${#dates.day(now)}"></div>
<div th:text="${#dates.hour(now)}"></div>
<div th:text="${#dates.minute(now)}"></div>
<div th:text="${#dates.second(now)}"></div>
<div th:text="${#dates.millisecond(now)}"></div>
<div th:text="${#dates.dayOfWeek(now)}"></div>
<div th:text="${#dates.dayOfWeekName(now)}"></div>
<div th:text="${#dates.dayOfWeekNameShort(now)}"></div>
<div th:text="${#dates.format(now)}"></div>
<div th:text="${#dates.format(now, 'yyyy-MM-dd HH:mm:ss')}"></div>
<div th:text="${#dates.format(now, 'yyyy-MM-dd hh:mm:ss')}"></div>
<div th:text="${#dates.format(now, 'yyyy-MM-dd aa hh:mm:ss')}"></div>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf Links</h1>
<!--
Link URL Expressions
- @{}
- 링크의 URL 표현
a. 매개변수 처리 쉽다.
b. Context Root Path가 자동으로 삽입
-->
<div><a href="/m7">이전 페이지</a></div>
<div><a href="/spring/m7">이전 페이지</a></div>
<div><a th:href="@{/m7}">이전 페이지</a></div>
<hr>
<h3>QueryString, 매개변수</h3>
<div><a href="/m7?seq=100">이전 페이지</a></div>
<div><a href="/m7?seq=${seq}">이전 페이지</a></div> <!-- 에러 -->
<div><a th:href="@{/m7(seq=${seq})}">이전 페이지</a></div>
<div><a href="/m7?seq=100&mode=add">이전 페이지</a></div>
<div><a th:href="@{/m7(seq=${seq}, mode=${mode})}">이전 페이지</a></div>
<hr>
<!--
기본 웹(QueryString)
- /m7?seq=10
REST(Path Variable)
- /m7/10
-->
<div><a th:href="@{/m7/{seq}(seq=${seq})}">이전 페이지</a></div>
<div><a th:href="@{/m7/{mode}/{seq}(seq=${seq},mode=${mode})}">이전 페이지</a></div>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf Conditions</h1>
<!--
1. th:if
2. th:switch
-->
<h2>if</h2>
<div th:if="${num1 > 0}">num1: 양수</div>
<div th:if="${num1 < 0}">num1: 음수</div>
<div th:if="${num2 > 0}">num2: 양수</div>
<div th:if="${num2 < 0}">num2: 음수</div>
<div th:if="${num1 > 0}">
<span th:text="'양수 ' + ${num1} + '입니다.'"></span>
</div>
<div th:if="${num2 > 0}" th:text="'양수 ' + ${num2} + '입니다.'"></div>
<div th:if="${num2 > 0}" th:text="|양수 ${num2}입니다.|"></div> <!-- 권장 -->
<div th:if="${num2 > 0}">양수 [[${num2}]]입니다.</div> <!-- 비권장 -->
<div th:unless="${num2 > 0}">음수</div>
<hr>
<h2>switch</h2>
<div th:switch="${mode}">
<div th:case="add">추가하기</div>
<div th:case="remove">삭제하기</div>
<div th:case="*">기타</div>
</div>
</body>
</html>
~ src/main/resources > "com" > "test" > "mapper" > "ThymeleafMapper.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.test.mapper.ThymeleafMapper">
<select id="getNum" resultType="Integer">
select salary from employees where rownum = 1
</select>
<select id="getTxt" resultType="String">
select first_name from employees where rownum = 1
</select>
<!--
<select id="getDTO" resultType="BoardDTO">
select * from tblBoard where rownum = 1
</select>
-->
<select id="getDTO" resultType="dto">
select * from tblBoard where rownum = 1
</select>
<select id="getNames" resultType="String">
select first_name from employees where rownum <= 10
</select>
<select id="getList" resultType="dto">
select * from tblBoard
</select>
</mapper>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf Iterations</h1>
<h2>each</h2>
<ul>
<li th:each="name : ${names}" th:text="${name}">이름</li>
</ul>
<ul>
<li th:each="name : ${names}"><span th:text="${name}"></span></li>
</ul>
<ul th:each="name: ${names}">
<li th:text="${name}"></li>
</ul>
<hr>
<ul>
<li th:each="dto : ${list}" th:text="|${dto.subject}(${dto.id})|"></li>
</ul>
<ul>
<li th:each="dto : ${list}" th:object="${dto}" th:text="*{subject}"></li>
</ul>
<hr>
<table>
<tr>
<th>번호</th>
<th>아이디</th>
<th>제목</th>
<th>index</th>
<th>count</th>
<th>size</th>
<th>even</th>
<th>odd</th>
<th>first</th>
<th>last</th>
</tr>
<tr th:each="dto, status : ${list}">
<td th:text="${dto.seq}"></td>
<td th:text="${dto.id}"></td>
<td th:text="${subject}"></td>
<td th:text="${status.index}"></td>
<td th:text="${status.count}"></td>
<td th:text="${status.size}"></td>
<td th:text="${status.even}"></td>
<td th:text="${status.odd}"></td>
<td th:text="${status.first}"></td>
<td th:text="${status.last}"></td>
</tr>
</table>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf Expression Basic Objects</h1>
<!--/*
${#request}
${#response}
${#locale}
${#session}
${#servletContext}
*/-->
<div th:text="${#request}"></div>
<div th:text="${#response}"></div>
<div th:text="${#locale}"></div>
<div th:text="${#session}"></div>
<div th:text="${#servletContext}"></div>
<hr>
<div th:if="${session.id != null}">
인증: <span th:text="${session.id}">아이디</span>
</div>
<div th:unless="${session.id != null}">미인증</div>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://me2.do/5BvBFJ57">
</head>
<body>
<h1>Thymeleaf Fragment</h1>
<h2>insert</h2>
<div th:insert="~{inc/sub.html}"></div>
<h2>replace</h2>
<div th:replace="~{inc/sub.html}"></div>
<hr>
<!-- 확장자 생략 가능 -->
<div th:insert="~{inc/sub}"></div>
<!-- ~{} 생략 가능, but 비권장 -->
<div th:insert="inc/sub"></div>
<hr>
<div th:insert="~{inc/sub2.html :: part}"></div>
<hr>
<div th:insert="~{inc/sub2.html :: part2}"></div>
<hr>
<div th:insert="~{inc/sub2.html :: owner('아무개', '010-1111-2222')}"></div>
<div th:insert="~{inc/sub2.html :: owner('테스트', '010-3333-4444')}"></div>
</body>
</html>
~ templates > "inc" > "sub.html", "sub2.html"
<div>조각 페이지</div>
<!DOCTYPE html>
<html xmlns:th="https://thymeleaf.org">
<body>
<div th:fragment="part">조각 페이지2</div>
<div th:fragment="part2">조각 페이지3</div>
<div th:fragment="owner(name,tel)">
<div>소유주: <span th:text="${name}"></span></div>
<div>연락처: <span th:text="${tel}"></span></div>
</div>
</body>
</html>
~ boot-thymeleaf > "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>
<typeAliases>
<typeAlias type="com.test.domain.BoardDTO" alias="dto"/>
</typeAliases>
</configuration>
'서버 > SprintBoot' 카테고리의 다른 글
[스프링부트(Spring Boot)] 검색 기능 구현 (0) | 2023.07.27 |
---|---|
[스프링부트(Spring Boot)] 페이징(Paging) (0) | 2023.07.27 |
[스프링부트(Spring Boot)] JPA (0) | 2023.07.02 |
[스프링부트(Spring Boot)] MyBatis (0) | 2023.06.27 |
Spring Boot 설치 및 환경 설정 (0) | 2023.06.26 |