์ข์ ํ๋ฃจ ๋์ธ์, ๋
์ ์ฌ๋ฌ๋ถ! ๊ทธ๋ฆฌ๊ณ ๋น๋ก ๊ฑฐ์ฐฝํ ์ด๋ฆ์ด Spring Boot ๊ฐ๋ฐ์ ๋ํ ์ฒซ ๋ง๋จ์ ๋ํ ์๋ฐํ ์ฃผ์ ๋ฅผ ์ดํด๋ณด๊ฒ ๋ ์ฃผ๋ ์ด์ ์์์๋ ๋ถ๊ตฌํ๊ณ ๋ง๋์ ๋ฐ๊ฐ์ต๋๋ค. ์ ๋ JavaRush ํฌํธ์์ ์ธํด์ญ ์
๋ฌธ ๊ณผ์ ๋ฅผ ์๋ฃํ ๊ฒฝํ์ ๊ณต์ ํ๊ณ , ์ถ์ ๋ ์ง์์ ๊ฐ์ ์ ํ
์คํธํ๋ ค๋ ์์ ํ ํ๋ฒํ ๊ธฐ์ ๋ํ์์ ์
์ฅ์์ ๊ฐ์๋ฅผ ์ ์ํ๊ณ ์ถ์ต๋๋ค. ์ ๋ ์ฒจ๋ถ๋ ์ฝ๋๋ ์ฌ๊ณ ๋ฐฉ์์ ๋ฌด๋กํจ์ด ์์ ์ ์๋ค๋ ์ ์ ๊ฒฐ์ฝ ๋ถ์ ํ์ง ์์ผ๋ฉฐ, ๊ฑด์ค์ ์ธ ๋นํ์ ํ์ํฉ๋๋ค. ์๋ํ๋ฉด '๋ถ๋ด'์ด ์๊ธฐ์ ์ ๋ฌธ์ ์ธ ๋ฐฉํฅ์ผ๋ก ๋ฐ์ ํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๋์ฑ์ด ๋๋ ์ฃผ์ด์ง ์กฐ๊ฑด์ ํด๊ฒฐํ๋ ๋ฐ "๋ง๋ณ ํต์น์ฝ"์ธ ์ฒํ์ง ์์ผ๋ฉฐ ์๋์ ์ผ๋ก ํ๋ก๊ทธ๋จ์ ๊ฐ๋ณ ๋ถ๋ถ์ ์๋ตํ์ฌ ์ ๊ฒฝ๊ณ์ ์ฌ์ํ ์ํฅ์ ๋ฏธ์น์ง ์๊ณ ๋น๊ต์ ๋ณต์กํ ์ฃผ์ ์ ๋ค์ด๊ฐ๋ ๊ฒ์ด ํต์ฌ์์ ๋จ๊ฒจ ๋ก๋๋ค. ๋น์ฐํ ์ฌ์ค์ ๋ถ์ ํ๋ ๊ฒ์ ๋ฌด๋ชจํ ์ผ์
๋๋ค. ๋์๊ฒ๋ ํ๋ค์๊ณ ์ด๋ โโ์๊ฐ๊น์ง ๋ช
ํํ ๊ฒ์ด ์ ํ ์์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์์
์ ๋ํ ์ฒซ ๋ง๋จ์์ ๋น์ทํ ๊ฐ์ ์ ๊ฒฝํํ๋ค๋ฉด "ํ์ํฉ๋๋ค!"
์ ์๋ ๊ธฐ์ ์ฌ์์ ๋ฐ๋ผ MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ์์ฑํ๊ธฐ ์ํ ํ์ค์ธ ์ ์ฌ ์ธํธ๋ฅผ ์ฌ์ฉํฉ๋๋ค .
๋ค์์ผ๋ก ๋ฉ์ธ ์ฐฝ์์ ํ์ฌ ๋ก์ปฌ ์๋ฒ๊ฐ ์๋ ์์ด์ฝ์ ํด๋ฆญํ ํ ํ๊ฒฝ์ ์ง์์ ๋ฐ๋ผ ์ํฐํฐ(์ฐธ๊ณ )์ ํ๋์ ๋ฐ๋ผ ํ
์ด๋ธ ๋ค์ด์ด๊ทธ๋จ์ ์์ฑํ๊ณ ์ ์ ํ ๋ฐ์ดํฐ๋ก ์ฑ์๋๋ค. ์ํ๋ ๊ฒฐ๊ณผ๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ๋ฌ์ฑํ๋ ค๋ฉด ์๊ธํ ์ฃผ์๊ฐ ํ์ํ MySQL ๋ฐฉ์ธ์ ๋ฏธ๋ฌํจ์ ๋ณ๋๋ก ๋ช
ํํ ํ ํ์๊ฐ ์์ต๋๋ค.
์ค๋น ๋จ๊ณ๋ฅผ ๋ง์ง๋ง์ผ๋ก ์๋ฃํ ํ ๋๊ตฌ ๋ชจ์์์ "๋ฒ๊ฐ" ์์ด์ฝ์ ํด๋ฆญํ์ฌ ๋ก์ปฌ ์๋ฒ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ "MySQL Workbench"๋ฅผ ํ์ํฉ๋๋ค. ์ด์ ์ ๋ณด ์ถ๊ฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ฃ๋๋ฉด ํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์ฑ์ application.properties(์ผ๋ฐ์ ์ผ๋ก "resources" ๋๋ ํฐ๋ฆฌ์ ์์)์ ์ถ๊ฐํ์ฌ ์์ ์๊ฒ ๊ธฐ๋ณธ IDE๋ก ๋์๊ฐ ๊ฐ๋ฐ์ ๊ณ์ํ ์ ์์ต๋๋ค.
๋ฌผ๋ก , ๋ค๋ฅธ ๋น์ฆ๋์ค ์๊ตฌ ์ฌํญ์ ์ถฉ์กฑํ๊ธฐ ์ํ ๋ฐฉ๋ฒ๋ก ๋ ๊ฐ๋ฐํด์ผ ํฉ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ฌ๋ ฅ์ ๊ฐ๋ฐ์์ ๋
ธ๋ ฅ, ์ง๋ต, ์์๋ ฅ์ ์ํด ์ ํ๋ฉ๋๋ค.
์์งํ๊ณ ๋ด๊ฐ ๊ฑธ์ด์จ ๊ธธ์ ์ฃผ์๋ฅผ ๊ธฐ์ธ์ด๋ฉด์ ๋๋ ์ ํํ ๋ฐฉํฅ์ด ์ ํํ๋ค๋ ๊ฒ์ ๊ณ์ํด์ ํ์ ํ๊ณ JavaRush ๊ต์ก ํฌํธ์์ ๊ณต๋ถํ๋ ๊ฒ์ ์ด์ ์ ๊นจ๋ซ์ต๋๋ค. ๋ค์ํ ์ค๋ฌด ์์
๋๋ถ์ ๋น์ทํ ๋ฐฉํฅ์ ๊ณ ๋ฑ ๊ต์ก ๊ธฐ๊ด์ ๋ก๊ณ ๋๋ผ์ธ ์ ๋๋ก ์ง๋ฃจํ ํ๋ก๊ทธ๋จ์์ ์์ ํ ์ต์๋์๋ ํ๋ก๊ทธ๋๋ฐ ํ์ต์ ๋ํ ๋งคํน์ ์ธ ๊ด์ฌ์ ๋๋๋ฆด ์ ์์์ต๋๋ค. ๋ฐฑ์๋ ๊ธฐ์ ์คํ์ ์๋ฃ๋ฅผ 4๊ฐ์ ๋์ ์ ๊ทน์ ์ผ๋ก ๊ณต๋ถํ ๊ฒ์ ์๋
๋์ ๊ฐ์์ ์คํ์ค ์์
์ ๋ค์๋ ๊ฒ์ ๋นํด ํจ์ฌ ๋ ๋ง์ ์ง์์ ํฌ์ํ์ต๋๋ค. ๋ฏฟ๊ฑฐ ๋ ๋ง๊ฑฐ๋. ๋ณต์กํ ์ฌ๋ฃ์ ๋ค์ด๊ฐ๋ ์ด๋ ค์์ ๊ตด๋ณตํ์ง ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ์ฅ์ ๋ฌผ์ ๊ทน๋ณตํจ์ผ๋ก์จ ์ฐ๋ฆฌ๊ฐ ๋ ๋์์ง๊ณ ์ง์
์ ์ผ๋ก๋ ๊ฐ์ธ์ ์ผ๋ก ๋ฐ์ ํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์ด ์์ ์ด์ผ๊ธฐ๊ฐ SpringBoot๋ผ๋ ๋๋ผ์ด ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋ ๋ฐ ๋ํ ์๋ก์ด ์์ด๋์ด๋ฅผ ๋ฐ๊ฒฌํ๋ ๋ฐ ๋์์ด ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. PS Github .
Thymeleaf
ํ
ํ๋ฆฟ ์์ง์ ์ฌ์ฉ ํ๊ณ query
๋ค์ด์ค๋ ์ ๋ณด ๋ฐฐ์ด์ ํํฐ๋งํ๊ธฐ ์ํด ๋ก์ปฌ MySQL ์๋ฒ์ ๋ํ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ์ธํด์ญ ์
ํ ํ
์คํธ์ ๊ฐ๋จํ ๋น์ ๋ฅผ ์ฌ์ฉํ์ฌ Spring Boot์์ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค . ๊ทธ๋ผ ์์ํด ๋ณด๊ฒ ์ต๋๋ค!
์คํ๋ง ๋ถํธ. ์ด๋ค ๋๋ฌผ์ด๊ณ ์ด๋ป๊ฒ ์๋ฆฌํ๋์?
๊ฐ๋จํ ๋งํด์, ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ฑํ๋ ๊ณผ์ ์์ ๊ท์คํ ์๊ฐ์ ์ ์ฝํ๊ณ , ํ์ฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ง์ ์ฐ๊ฒฐํ๊ณ , ์ธ์์ ์ธ ๋งคํ ์บ๋ฒ์ค์ ์๋ธ๋ฆฟ์ ์์ฑํ ํ์๊ฐ ์๋๋ก ํด์ฃผ๋ Pivotel ์ ํ์ํ ๋๊ตฌ์ ๋๋ค. IntelliJ IDEA Ultimate Edition (ํ์ผ - ์ - ํ๋ก์ ํธ... - Spring Initializr) ์ ํตํฉ๋๊ฑฐ๋ start.spring.io ์น ์๋น์ค ์ ์๋ Spring ์ด๊ธฐํ ๋น๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ํ ๋ฒ์์์ ํฌํจํ ํจํค์ง๋ฅผ ์ง์ ํ๋ ๊ฒ์ผ๋ก ์ถฉ๋ถํฉ๋๋ค. ์ ์ํฉ๋๋ค.- WEB ๋ ํ์ค ์ฃผ์ localhost:8080์ ๋ก์ปฌ Apache Tomcat ์๋ฒ์ ๋ฒ์ฉ Spring MVC ํ๋ ์์ํฌ๋ฅผ ํฌํจํ์ฌ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ํ ์ฃผ์ ๊ตฌ์ฑ ์์์ ๋๋ค.
- DevTools - ์ปดํ์ผ๋ ์ฝ๋๋ ํ ํ๋ฆฟ์์ ๋ณ๊ฒฝ ์ฌํญ์ด ๊ฐ์ง๋๋ฉด ํซ JVM์์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น ๋ฅด๊ฒ ๋ค์ ์์ํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ๋ํ, ์ ํํ ์์ง์ด ํ๋ก์ ํธ์ ํฌํจ๋์ด ์์ผ๋ฉด Thymeleaf๊ฐ ์บ์๋ฅผ ์ง์ฐ์ง ์์๋ ๋ฉ๋๋ค.
- JPA ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ ์ ํ์ํ ๊ธฐ์ ์ด๋ฉฐ Java ๊ฐ์ฒด์ ๊ฐ์ฒด ๊ด๊ณํ ๋งคํ์ ์ ๊ณตํ๊ณ ์ํฐํฐ๋ฅผ ๊ด๋ฆฌ, ์ ์ฅ ๋ฐ ๊ฒ์ํ๊ธฐ ์ํ API(์ฐ๋ฆฌ์ ๊ฒฝ์ฐ Hibernate )๋ฅผ ์ ๊ณตํฉ๋๋ค.
- Thymeleaf(Mustache, AngularJS, Vaadin ๋ฑ) - ์ ํ๋ฆฌ์ผ์ด์ ์๊ฐํ๋ฅผ ์ํ ํ ํ๋ฆฟ ์์ง HTML์ ์๋ฆฌ์ ๋ํ ์๋์ ์ธ ์น์ํจ ๋๋ถ์ ๋๋ ์ธ์ด๋ฅผ ์ธ๊ณ์ ์ด์์ผ๋ก ๋์ด์ฌ๋ฆฐ Thymeleaf๋ฅผ ์ ํํ์ต๋๋ค.
- MySQL - Java ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ๋๋ผ์ด๋ฒ๋ฅผ ์ฐ๊ฒฐํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํด SQL ์ฟผ๋ฆฌ๋ฅผ ์คํํฉ๋๋ค.
<dependencies></dependencies>
๋น์ทํ ๋ฐฉ๋ฒ์ผ๋ก ํ๊ทธ ๊ฐ ์กฐ์์ ํด์ผ ํฉ๋๋ค.
์๋ํ ๋ฏธ๋๋ฅผ ํฅํ ์ฒซ ๊ฑธ์
๋ค์์ผ๋ก ๋ค์ ํฅ๋ฏธ๋กญ๊ณ ์๋นํ ๋ ผ๋ฆฌ์ ์ธ ์ง๋ฌธ์ด ์ ๊ธฐ๋ฉ๋๋ค. โ์ด์ ๋ฌด์์ ํด์ผ ํ ๊น์? ์ด๋ป๊ฒ ์๋ํ๋์? ์ด ํ๋ก๊ทธ๋จ์ ๋ชจ๋ธ-๋ทฐ-์ปจํธ๋กค๋ฌ์ ์์น์ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ถ๋์์ต๋๋ค. ์ฐ๊ฒฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค(๋ชจ๋ธ)์์ ์ํฐํฐ ์ฝ๊ธฐ๋ฅผ ๊ตฌ์ฑํ๊ณ ์ปจํธ๋กค(๋ทฐ)์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ธํฐํ์ด์ค์ ํ์๋ฉ๋๋ค. ๊ตฌ์ฑ ์์ ๊ฐ์ ํต์ ๊ณผ ์ ์ก๋ ์์ฒญ์ ๋ฐ๋ฅธ ์์ ์คํ์ ์ปจํธ๋กค๋ฌ ๋๋ถ์ ์ํ๋ฉ๋๋ค. ์ง์์ ์ธ ๋ฐ์ ์ ์ํ ๊ธฐ์ค์ ์ด ๋๋ ํต์ฌ ์์์ ์ฐฝ์ถ์ ๋๋ค. ๋ฏธ๋๋ฌ์ด ๊ฒฝ์ฌ๋ฅผ ํผํ๊ณ ์์ ํ์ฅ์์ ๋๋ฃ๋ค์ ์กด๊ฒฝ์ฌ์ ์ ์งํ๋ ค๋ฉด ๊ตฌ์ฑ ์์๋ฅผ ์ ์ ํ ๋๋ ํฐ๋ฆฌ์ ๋ฐฐ์นํ๊ณ (์: ์ปจํธ๋กค๋ฌ ํ์ผ์ "java" ๋ถ๊ธฐ์ ์ปจํธ๋กค๋ฌ ํด๋์ ๋ฐฐ์น) ์กฐ์ฌ์ค๋ฝ๊ฒ ๋ณด๊ดํด์ผ ํฉ๋๋ค. ์ง์ฅ์์ ์ฃผ๋ฌธํ์ญ์์ค.๋ณธ์ง์ ํฐ ๋ฉ์ปค๋์ฆ์ ์์ ๋ถ๋ถ์ ๋๋ค
์ฆ, ๋ฌธ์ ์ ์ค์ ๋ ์กฐ๊ฑด์ ๋ฐ๋ฅธ ๋ชจ๋ธ์ ๋๋ค. ๋ ผ์ ์ฃผ์ ์์ ๋ฒ์ด๋ ํ๋ก์ ํธ ์๊ฐ๋ก ๋์๊ฐ์, ์ฐ๋ฆฌ๋ ์์ ๋ค ์ฌ์ด์ ์ต์ํ์ ์ฐจ์ด๊ฐ ์๋ค๋ ๊ฒ์ ์์ ์๊ฒ ์ฃผ์ฅํ ์ ์์ผ๋ฉฐ, ์ถ๊ฐ ๊ฒํ ์์๋ ํ๊ท ์ ์ธ ๊ฐ๋ ์ ๊ณ ์ํ ์ ์์ต๋๋ค. ๋ค์์ ํฌํจํ์ฌ ๋ ธํธ๋ถ์ ๋ฉ๋ชจ๊ฐ ์๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.- ์ผ๋ฐ ํ๋ฆ์์ ์์น๋ฅผ ๊ฒฐ์ ํ๊ธฐ ์ํ ์๋ณ ๋ฒํธ์ ๋๋ค.
- ํน์ ๋ฌธ์ ์๋ก ๊ตฌ์ฑ๋ ๋ฌธ์ ๋ฉ์์ง
- ์ฌ์ฉ์๊ฐ ์ผ๋ฐ ๋ชฉ๋ก์ ์ถ๊ฐํ ๋ ์ง์ ๋๋ค.
- "์๋ฃ ์ฌ๋ถ"("์ฝ๊ธฐ ์ฌ๋ถ")๋ฅผ ๊ฒฐ์ ํ๋ ๋ถ์ธ ๋ณ์์ ๋๋ค.
@Entity
public class Note {
@Id
@GeneratedValue
private int id;
private String message;
private Date date;
private boolean done;
public Note() {
}
public Note(String message) {
this.message = message;
this.date = new Date();
this.done = false;
}
}
์ด๋ก ์ ์
์ฅ์์ ๋ฌด์จ ์ผ์ด ์ผ์ด๋๊ณ ์๋์ง ๋ ์ ์ดํดํ๊ธฐ ์ํด ํ ๋ก ์ฃผ์ ์์ ๋ ๋ค๋ฅธ ์ผํ. Spring์ ๊ตฌ์ฑ ์์ ๊ฐ์ ์ฐ๊ฒฐ์ ์ฃผ์์ผ๋ก ์ง์ ๋ฉ๋๋ค . ๊ฐ ์ฃผ์์ ๋ฉ์ปค๋์ฆ์์ ํน์ ์ญํ ์ ์ํํ๊ณ "@" ๊ธฐํธ๋ก ์์ํ๋ ๊ฐ์ฒด ์์ ํน์ ํฌ์ธํฐ์
๋๋ค. @Entity ์ฃผ์์ Spring Boot์ ํ์ ํด๋์ค ๋ฐ์ดํฐ๊ฐ "Entity"์ ์ํจ์ ๋ํ๋ด๋ฉฐ @Id ๋ฐ @GeneratedValue๋ ์ ๋ณด ๋ฐฐ์ด์ ์ฒ๋ฆฌํ ๋ ๋ฐ๋ณต์๊ฐ ์๋ โโ์์ฑ๋๋ ์๋ณ์๋ก ์ ํํ ํ๋๋ฅผ ์ง์ ํฉ๋๋ค. ์๊ฐ์ ํ์์ ๊ฐ๊ฒฐ์ฑ์ ๋์ด๊ธฐ ์ํด ํ์ค Getter ๋ฐ Setter ์ถ๊ฐ๋ฅผ ์๋์ ์ผ๋ก ์๋ตํ์ต๋๋ค. ๋ค์์ผ๋ก ๋ ์ฝ๋ ์ ์ฅ์ ์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ์ ๊ณ ๋ คํ์ฌ ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ์ ๋ค์ ๋จ๊ณ๋ก ๋์ด๊ฐ๋๋ค. ๊ตํ ์ฒด์ธ์ ์ฐ๊ฒฐ ์์์ธ "repository" ๋๋ ํฐ๋ฆฌ์ NoteRepository ์ธํฐํ์ด์ค๋ฅผ ์์ฑํ๊ณ ๊ฐ์ฅ ๋ง์ ๊ฒ์ ์์ํฉ๋๋ค. ์ถ๊ฐ ์์
์ ์ ํฉํ ์ ์ฅ์๋ก, ์ก์ธ์คํ ์ ์ฅ๋ ์ํฐํฐ์ ์ ์ ๋ฐ๋ณต์๋ฅผ ๋ํ๋
๋๋ค.
public interface NoteRepository extends JpaRepository<Note, Integer> {
}
์ฌ์ค ๊ทธ๊ฒ ์ ๋ถ์
๋๋ค. ๊ฐ๋จํ๊ณ ๊ฐ๊ฒฐํฉ๋๋ค. ์ด์ Spring Boot๋ ์์ฑ๋ ๊ตฌ์ฑ ์์๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ํธ ์์ฉ์ ๊ตฌ์ฑํฉ๋๋ค. ๋ค์ํ ์คํ ๊ฐ๋ฅ์ฑ์ ์ง๋ ๋ ๊ฑฐ์ ์ ์ฅ์ ์ ํ์ด ์๋์ ์ผ๋ก ๋ง์ต๋๋ค. JpaRepository๋ ์ฌ๋ค๋ฆฌ์ ๋งจ ์์ ์์ผ๋ฉฐ ๊ทธ ์๋์ CrudRepository ๋ฐ PageAndSortingRepository๋ฅผ ํฌํจํ์ฌ ๊ฐ์ฅ ํฐ ์ ์ฌ๋ ฅ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ๋ ์ด์ ์งํํ์ง ์๊ณ ์ฃผ์ ์์ ๋ฒ์ด๋์ง ์์ ๊ฒ์
๋๋ค. ์ผ๋ถ ๋ฏธ๋ฌํจ์ Pivotel ์น ์ฌ์ดํธ์ ๊ธฐ์ ๋ฌธ์์์ ์ฐพ์ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ์ด์ ์ ํ๋ฆฌ์ผ์ด์
์ธก์์ ๋ฐ์ดํฐ ์ด๋ฏธ์ง๋ฅผ ๊ตฌํํ๊ณ ํต์ ๋ฐฉ๋ฒ์ ์ง์ ํ ํ ๊ณต์ ๊ฐ๋ฐ์๊ฐ ์ด์
๋ธ๋ฆฌ๋ก ๋ฐ์คํฌํฑ ํ๋ซํผ์ ๋ฏธ๋ฆฌ ์ค์น๋ ์ ์ ํ ์ธ๋ถ ํ๊ฒฝ์ธ โMySQL Workbenchโ์์ MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์์ฑํ๋ ๋ฐ ์ฃผ์ํด์ผ ํฉ๋๋ค. ๋ก์ปฌ ์๋ฒ ์์ฑ์ ์ํ ์ถ๊ฐ ํจํค์ง ํฌํจ:
- ๋ณ๋์ ๋ถ์ธ ์ ํ์ ์์ต๋๋ค. ๋ชจ๋ ์์ฒญ ์ฒ๋ฆฌ ์์ ์ "true" ๋๋ "false"๋ฅผ ๊ฐ๊ฐ ๋นํธ ๊ฐ "1" ๋๋ "0"์ผ๋ก ๋ณํํฉ๋๋ค.
- ๋ ์ง๋ ์ ์ ์ผ๋ก Timestamp ์ ํ์ผ๋ก ์ ์ฅ๋ฉ๋๋ค. ์ฝ์ด์ ์น์ํ Date๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๋ฌ๋ ฅ์์์ ์์น์๋ง ์ ํํด์ผ ํ ๊ฒ์ ๋๋ค.
spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
๋ง์ง๋ง์ผ๋ก ์ฃผ์์ ์ฌ์ฉํ์ฌ Note ์ํฐํฐ๋ฅผ MySQL์ ๋ฐ์ธ๋ฉํฉ๋๋ค. @Table์ ์ ํํ ์ด๋ฆ๊ณผ ์คํค๋ง๋ฅผ ๊ฐ๋ ํ
์ด๋ธ์ ์ฌ์ฉ์ ๋ํ๋ด๊ณ , @Column์ ๋ณ์๊ฐ ํน์ ํ๋์ ์ํจ์ ๋ํ๋
๋๋ค.
@Entity
@Table(name = "test", schema = "test", catalog = "")
public class Note {
@Id
@GeneratedValue
private int id;
@Column(name = "message")
private String message;
@Column(name = "date")
private Date date;
@Column(name = "done")
private boolean done;
public Note() {
}
public Note(String message) {
this.message = message;
this.date = new Date();
this.done = false;
}
}
๋ณด๊ธฐ ๋๋ ์ฌ์ฉ์ ์ธํฐํ์ด์ค
์์, ์ฐ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ด ์์ ํ๊ฒ ๋งํ ์ ์์ต๋๋ค. "์ด๋ก ์ ๋๋ ์ค๋ฌด์ ์ง์์ด ์ ํ ์์ผ๋ฉด ์์ฉ ํ๋ก๊ทธ๋จ์ ์๊ฐํ๊ฐ ์ฃผ์ ๊ฑธ๋ฆผ๋์ด ๋ ๊ฒ์ ๋๋ค." ์์งํ ๋งํด์ ํ๋ก ํธ ์๋ ๊ตฌ์ฑ ์์๋ ์ ์ฒด ์์ ๋์์ ์์ฒญ๋ ์์ ์ฐจ์งํ์ผ๋ฉฐ ์ค๋ ์๊ฐ ๋์ ์์ ์๊ฒ ๋ด ์ ๊ฒฝ์ ์ ์ฝํ๊ฒ ๋ง๋ค์์ต๋๋ค. ๊ทธ๋ฌ๋ Thymeleaf์ ๋๋ผ์ด ๋จ์์ฑ ๋๋ถ์ ์ผ๋ จ์ ๋งคํน์ ์ธ ํจ๋ฐฐ ํ์ ์ ์ ํ ํํ์ ์ ์ฐพ๋ ๊ฒ์ด ๊ฐ๋ฅํ์ต๋๋ค. ์ผ๋ฐ์ ์ธ ๊ฐ๋ ์ ๋น์ทํ ์ ์ฅ์ ๊ณ ์ํ์ง๋ง ์ ํ๋ ์์ง ์ฌ์ฉ์ ๋ณต์ก์ฑ์ ๋ํด ์ถ๊ฐ ๋ ผ์๊ฐ ์ด๋ฃจ์ด์ง ๊ฒ์ ๋๋ค. ์ฃผ์ ๊ธฐ์ ์ ๊ฐ์ฅ ์์ํ HTML์ ์ฌ์ฉํ๊ณ ๊ฐ๋ณ ์กฐ๊ฐ์์ ์ต์ข ๋์คํ๋ ์ด๋ฅผ ์กฐํฉํ์ฌ ๋์ผํ ์น์ ์ด ์ฌ๋ฌ ๋ฒ ๋ฐ๋ณต๋๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๊ธฐ๋ฅ์ ๋๋ค. UI ์ํคํ ์ฒ๊ฐ ์ปจํธ๋กค(์ ํญ๋ชฉ ์ถ๊ฐ, ๊ธฐ๋ณธ ํ์ด์ง๋ก ๋์๊ฐ๊ธฐ)์ด ์๋ ํ์ ๋ชจ์๊ณผ ๋ฉ๋ชจ๊ฐ ์ถ๊ฐ๋ ์๊ฐ์ ๊ธฐ์ค์ผ๋ก ์ค๋ฆ์ฐจ์(ASC)์ผ๋ก ์ ๋ ฌ๋ ์ํฐํฐ๋ฅผ ํ์ํ๋ ๋์ ํ ์ด๋ธ๋ก ๊ตฌ์ฑ๋ ๊ธฐ๋ณธ ํ์ด์ง๋ก ๊ตฌ์ฑ๋์ด ์๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. ๋๋ ๊ฐ์(DESC) ๋ฐฉํฅ. ๋ชจ๋ ๊ธฐ๋ก์ ์ค๋ฆ์ฐจ์์ผ๋ก ํ์ํ๋ ๊ฒ์ ํ์ค ์์น๋ก ์ผ๊ฒ ์ต๋๋ค. ์ ํํ ํ ํ๋ฆฟ ์์ง์ ๊ณ์ธต์ ์ ์ฑ ์ ๋ฐ๋ผ ๊ตฌ์ฑ ์์ ์๊ฐํ ์์๋ "resources" ๋๋ ํฐ๋ฆฌ์ "templates" ๋ถ๊ธฐ์ ์์นํด์ผ ํฉ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ๊ตฌ์ฑ ์์๋ฅผ ์ถ๊ฐ๋ก ์กฐ์ํ ๋ ์ ์๋ ์กฐ๊ฑด์ด ๊ณ ๋ ค๋ฉ๋๋ค. html5 ํ ํ๋ฆฟ์ "index"(๋๋ ๊ฐ์ธ ์ทจํฅ์ ๋ฐ๋ผ ๋ค๋ฅธ ์ด๋ฆ)๋ผ๋ ์ด๋ฆ์ ๋ฉ์ธ ํ์ด์ง๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. ์๋ฅผ ๋ค์ด:<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/head :: head"></head>
<body>
<div class="container">
<div th:replace="fragments/header :: header"></div>
<div th:if="${not #lists.isEmpty(notes)}">
<div th:replace="operations/list :: notebook"></div>
</div>
<div th:replace="fragments/footer :: footer"></div>
</div>
</body>
</html>
์ด์ ์ต์ข
์ ํ๋ฆฌ์ผ์ด์
์ ์ฃผ์ ๊ตฌ์ฑ ์์๋ฅผ ๋ถ์ํด ๋ณด๊ฒ ์ต๋๋ค. Thymeleaf๋ ํ๋ก์์ ์ ์ฌ์ฉ์ ๋ํ๋ด๊ธฐ ์ํด ๋ณ๋์ ๊ตฌ๋ฌธ์ ์ฌ์ฉํ๊ณ "th:"๋ผ๋ ํค์๋๋ก ์์ํฉ๋๋ค. ์ด ํค์๋๋ ์ฌ๋ <html> ํ๊ทธ์ ๋ฐ๋์ ํฌํจ๋์ด์ผ ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋งํฌ์
๋๋ค.
<div th:if="${not #lists.isEmpty(notes)}">
"if" ์์
์ ์์
์ ์ํํ๋ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ๊ณผ ์์ ํ ๋ค๋ฅด์ง ์์ผ๋ฉฐ ์ถ๊ฐ ํ์๋ฅผ ์ํด ๊ฐ์ฒด๊ฐ ์๋์ง ๋ค์ด์ค๋ "notes" ์์ฑ์ ํ์ธํฉ๋๋ค. ๋ชจ๋ธ๊ณผ ์๊ฐํ์ ์ํธ ์์ฉ์ ๊ตฌ์ฑํ๋ ๋ฐ ์ฌ์ฉ๋๋ ๊ฒ์ ๊ณ ๋ คํ์ฌ ์ปจํธ๋กค๋ฌ ์ฌ์ฉ๊ณผ ์ฃผ์ ์ ์ค๋ณต์ ๋ณ๋๋ก ์ธ๊ธํ ๊ฐ์น๊ฐ ์์ต๋๋ค. ์์ผ๋ก๋ ๋ชจํธํ ์๊ฐ์ด ๋ง์ด ์๊ธธ ๊ฒ์
๋๋ค. ์ํ์๋ฉด ๋์๊ฐ์๋ฉด ๋ฉ๋๋ค.
<head th:replace="operations/list :: notebook"></head>
"๊ต์ฒด" ์์
์ "์คํ
" ๋๋ ํ์ฑ ๋ธ๋ก์ ํ์ฌ ๋๋ ๋ณ๋ ํ์ด์ง์์ ์ ํํ ์กฐ๊ฐ์ผ๋ก ๋ฐ๊พธ๋ ๊ฒ์ ๋ํ๋
๋๋ค. ํ์์ ๊ฒฝ์ฐ๋ ์์์ ๋ช
ํํ๊ฒ ๊ด์ฐฐ๋ฉ๋๋ค. โOperationsโ ๋๋ ํฐ๋ฆฌ์ โlist.htmlโ์์ โnotebookโ์ด๋ผ๋ ์กฐ๊ฐ์ โindexโ ํ์ผ์ <div></div>๋ก ๋ณต์ฌํ์ฌ ์ต์ข
๋์์ ์ฝํ
์ธ ๋ฅผ ์์ ํ ๋์ฒดํฉ๋๋ค. ๋๊ฐ๋ ๋ด์ฉ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
<!DOCTYPE html>
<!--suppress ALL -->
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<div th:fragment="notebook">
<table class="table table-bordered table-hover horizontal-align">
<thead>
<tr>
<th style="width: 5%">#</th>
<th style="width: 60%">Message</th>
<th class="dropdown" style="width: 20%">Date
<a th:href="@{'/sort/{sortDate}' (sortDate = 'ASC')}"><i class="fa fa-chevron-circle-up"></i></a>
<a th:href="@{'/sort/{sortDate}' (sortDate = 'DESC')}"><i class="fa fa-chevron-circle-down"></i></a>
</th>
<th style="width: 5%">Done</th>
<th style="width: 5%">Edit</th>
<th style="width: 5%">Delete</th>
</tr>
</thead>
<tbody>
<tr th:each="note : ${notes}">
<td th:text="${note.id}" style="text-align: center">#</td>
<td th:text="${note.message}">Message</td>
<td th:text="${#dates.format(note.date, 'EEE, d MMM yyyy HH:mm')}" style="text-align: center">Date</td>
<td style="text-align: center">
<i th:if="${note.done} == true" class="fa fa-plus-square-o" style="font-size:20px;color:#337ab7"></i>
<i th:if="${note.done} == false" class="fa fa-minus-square-o" style="font-size:20px;color:#337ab7"></i>
</td>
<td style="text-align: center"><a th:href="@{'/edit/{id}'(id=${note.id})}"><i class="fa fa-edit" style="font-size:20px"></i></a></td>
<td style="text-align: center"><a th:href="@{'/delete/{id}'(id=${note.id})}"><i class="fa fa-trash" style="font-size:20px"></i></a></td>
</tr>
</tbody>
</table>
</div>
</html>
๊ตฌ์ฑ์ ์ธ ๊ฐ์๋ก ๋์๊ฐ์ ํ์ค HTML ๊ตฌ๋ฌธ์ด๋ ์ฌ์ฉ๋ ๊ทธ๋ํฝ ์คํ์ผ์ ์๋ตํ๊ณ ํนํ ํ
ํ๋ฆฟ ์์ง ๋ฉ์ปค๋์ฆ์ ์ดํดํ๋ ๋ฐ ์ค์ ์ ๋๊ณ ์ฌ์ฉ๋ Thymeleaf ๊ธฐ๋ฅ์ ์์๋๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค.
<div th:fragment="notebook">
"์กฐ๊ฐ" ์์
์ ์กฐ๊ฐ์ ์ด๋ฆ์ ์ง์ ํ๊ณ "๊ต์ฒด" ๋ช
๋ น์ ๋ธ๋ก์ ๋ด์ฉ์ ์ฌ์ฉํ ์ ์๊ฒ ํฉ๋๋ค. ๊ฒ๋ค๊ฐ! ๋จ์ผ ํ์ด์ง ๋ด์์์ ๋ค์ค ์ฌ์ฉ์ ๊ฒฐ์ฝ ๋ฐฐ์ ๋์ง ์์ผ๋ฉฐ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ํ๋ก์์ ๋๋ ๊ธฐ๋ฅ๊ณผ์ ์ ์ฌ์ ์ ๋ค์ ์ ์ํฉ๋๋ค.
<a th:href="@{'/sort/{sortDate}' (sortDate = 'ASC')}">
@PostMapping ์ฃผ์์ ๋ํ ํธ์ถ์ "/sort/{sortDate}" ๋งคํ์ด ์๋ ์ปจํธ๋กค๋ฌ์์ ์ฌ์ฉ๋ฉ๋๋ค. ์ฌ๊ธฐ์ {sortDate}๋ ๋๊ฐ๋ ์ ๋ ฌ ๋ฐฉํฅ ์์ฑ์
๋๋ค. ๋ฐ๋ณต ๋ฃจํ์์ ์ฌ์ฉ์๊ฐ ์ ํํ ์์์ ์์น์ ๋ฐ๋ผ ๋์ ์ธ ๋ณ๊ฒฝ์ ์ถ๊ฐํ๋ ๋ค์ ๋ธ๋ก์์๋ ๋น์ทํ ๋ด์ฉ์ ๋ณผ ์ ์์ต๋๋ค.
<a th:href="@{'/edit/{id}'(id=${note.id})}">
<tr th:each="note : ${notes}">
๊ฐ์ ์ด๊ฑฐํ๋ ๊ฒ์ Java ๊ตฌ๋ฌธ์์ for ๋ธ๋ก์ ์น์ํ๊ฒ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๋งค์ฐ ์ ์ฌํฉ๋๋ค. ๋ณ์ "note"๋ ์
๋ ฅ ์์ฑ ๋ฐฐ์ด ${notes}(์ํฐํฐ ๋ฐฐ์ด)์์ ํ์ฌ ์์๋ฅผ ๊ฐ์ ธ์ ๊ฐ์ ๋ณ๊ฒฝํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ๋์ค์. ์์งํ ๋งํด์, ์ฐ๋ฆฌ๋ ์ค์ ์ ์ฉ ์ฌ๋ก์ ํจ๊ป ๊ด๋ฒ์ํ Thymeleaf ๊ธฐ๋ฅ์ ๋์ดํ๋ ๋ณ๋์ ๊ธฐ์ฌ๋ฅผ ํ ์ ํ ์ ์์ต๋๋ค. ํ
ํ๋ฆฟ ์์ง์ ๋งค์ฐ ๊ฐ๋จํ๋ฉฐ ์ถ๊ฐ ๊ตฌ๋ฌธ์ ์ธ์์ ์ธ ์ํ๋ฌผ์ ์ ํ ๋ฐฐ์ธ ํ์๊ฐ ์์ต๋๋ค. ์์ ์ค๋ช
๋ ๊ธฐ๋ฅ์ ๊ฐ๋ฐ์ ๊ณต์ ์น์ฌ์ดํธ์ ๊ธฐ์ ๋ฌธ์์ ์ค๋ช
๋์ด ์์ผ๋ฉฐ ๋ฐฑ์๋์์ ํต์ ์ ๊ตฌ์ฑํ๋ ๋ฐ ๋งค์ฐ ์ค์ํฉ๋๋ค. ๋ฐ๋ผ์ ์์ ์๊ฒ ๋ค์ ๋ถ๋ถ๊ณผ ๋ง์ง๋ง ๋ถ๋ถ์ผ๋ก ๋์ด๊ฐ ์ ์์ต๋๋ค. ๋ฌผ๋ก ๊ธฐ์ฌ ๋ง์ง๋ง ๋ถ๋ถ์ ์๋ ์์ฑ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ํ ๋งํฌ์ ์๊ฐํ์ ๋๋จธ์ง ๊ตฌ์ฑ ์์๋ฅผ ์ฒจ๋ถํ๋ฉด ๋ฉ๋๋ค.
์๊ท๋ชจ ํ์ฌ์ ์ปจํธ๋กค๋ฌ, ๊ด๋ฆฌ์
"์น ์ ํ๋ฆฌ์ผ์ด์ ์ํคํ ์ฒ์ ์ด์" - ์๋ง๋ ํ๋ก๊ทธ๋จ ์์ ์ ๊ตฌ์ฑํ๋ ๋ฐ ์์ด ์ปจํธ๋กค๋ฌ ๊ตฌ์ฑ ์์์ ์ค์์ฑ์ ๋ํ ๋ ์ ํํ ์ค๋ช ์ ์ฐพ์ ์ ์๋ ๋ฐฉ๋ฒ์ ์์ ๊ฒ์ ๋๋ค. ๋๋ถ๋ถ์ ์์ ์ ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ์ ์ฐ๊ฒฐ ์์์ ์ํด ์ ํํ๊ฒ ์ํ๋ฉ๋๋ค. ๋ชจ๋ธ๊ณผ ๋ทฐ. Spring Boot์ ์ก์ ๋ฉ์ปค๋์ฆ ๋๋ถ์ ์๋ฌด๋ฐ ๋ฌธ์ ์์ด ๋งคํ ๋ฐ GET/POST ์์ฒญ ๋ฉ์๋๋ฅผ ์์ ์๊ฒ ์ฌ์ฉํ ์ ์์ผ๋ฉฐ ๋ฐ์ดํฐ ์ ์ฅ์๋ฅผ ์๋์ผ๋ก ์ฐ๊ฒฐํ ์ ์์ต๋๋ค. ์ ์ ํ ์ฃผ์์ ์ฌ์ฉ์ ๋ค์ ์ฐธ์กฐํ์ฌ "controllers" ๋๋ ํฐ๋ฆฌ์ ๋ณ๋ ํ์ผ์ NoteController ํด๋์ค๋ฅผ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค.@Controller
public class NoteController {
private NoteService service;
@Autowired
public void setNoteService(NoteService service) {
this.service = service;
}
@GetMapping("/")
public String list(Model model) {
return "index";
}
}
์ฃผ์ ๊น๊ฒ ์ดํด๋ณด๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ด๋ฆฌ ์๋น์ค ์์
์์ ๋น์ฆ๋์ค ๋ก์ง์ ๋ถ๋ฆฌํ๊ธฐ ์ํ ์๋น์ค ์ถ๊ฐ์ ๊ด๋ จ๋ ์ ํ๋ฆฌ์ผ์ด์
์ํคํ
์ฒ ์ค๊ณ์ ์ค์ํ ๋ณ๊ฒฝ ์ฌํญ์ ํ์ธํ ์ ์์ต๋๋ค. ์๋ฃ๋ ์์
์ ์์ ํ์ ๋ค์์ฑ์ ๋์ด๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํต์ ๋ฐฉ๋ฒ์ ๋ณ๊ฒฝํ ํ์ ์์ด ์ฌ์ฉ์ ์ธํฐํ์ด์ค์ ๊ธฐ๋ฅ์ ๋ณ๊ฒฝํ ์ ์๋ ๊ด๋ฒ์ํ ๋ฒ์๋ฅผ ์ ๊ณตํ๋ ๋ฐ ํ์ํฉ๋๋ค. ํ์ค ํํ์ ์ ์ฌํ ํํ ์ค์์ ๋์ ๋์ง ์์ต๋๋ค. ์ธํฐํ์ด์ค๋ ๋ณ๋์ ๋๋ ํ ๋ฆฌ์ ์์ผ๋ฉฐ Spring Boot ๊ฐ์ง๋ฅผ ์ํ @Service ์ฃผ์์ด ์๋ ํด๋์ค์ ์ํด ๊ตฌํ๋ฉ๋๋ค.
public interface NoteService {
Note getNoteById(Integer id);
void saveNote(Note note);
void updateNote(Integer id, String message, boolean done);
void deleteNote(Integer id);
List<Note> findAll();
}
@Service
public class NoteServiceImpl implements NoteService{
private NoteRepository repository;
@Autowired
public void setProductRepository(NoteRepository repository) {
this.repository = repository;
}
@Override
public Note getNoteById(Integer id) {
return repository.findOne(id);
}
@Override
public void saveNote(Note note) {
repository.save(note);
}
@Override
public void updateNote(Integer id, String message, boolean done) {
Note updated = repository.findOne(id);
updated.setDone(done);
updated.setMessage(message);
repository.save(updated);
}
@Override
public void deleteNote(Integer id) {
repository.delete(id);
}
@Override
public List<Note> findAll() {
return repository.findAll();
}
}
์ปจํธ๋กค๋ฌ ๊ฒํ ๋ก ๋์๊ฐ์ Spring Boot ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ์์
์ ๊ตฌ์ฑํ๋ ๋ณต์กํ ๊ณผ์ ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. @Autowired ์ฃผ์์ ์๋น์ค๋ฅผ ์ ์ ํ ์ ํ์ ์ง์ ๋ ๋ณ์์ ์๋์ผ๋ก ๋ฐ์ธ๋ฉํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฐ๊ฒฐ์ ์ค์ ํด์ผ ํจ์ ๋ํ๋
๋๋ค. localhost:8080์ ๋ํ ํธ์ถ์ ์์ ํ ๋ "index"๋ผ๋ ํ์ด์ง๋ฅผ ๋ฐํํ๋ @GetMapping("/") ์ฃผ์์ผ๋ก ํ์๋๋ ๋ทฐ์ ํต์ ๋ฐฉ์์ ๋ ๋ง์ ์ฃผ์๋ฅผ ๊ธฐ์ธ์ฌ์ผ ํฉ๋๋ค. ํ์ฅ๋ ์ค๋ช
@RequestMapping(value = "/", method = RequestMethod.GET)์ ์ง์ ํ๊ฑฐ๋ ๋ฐํ ์ ํ์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ง ModelAndView๋ก ๋ฐ๊พธ๋ ๋ฑ ๋ค๋ฅธ ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ํ์ฌ ์ค์ ์ ์ฉ ๊ฒฝํ์ ๋ฐ๋ฅด๋ฉด ์ต์ข
๊ฒฐ๊ณผ์ ๊ทผ๋ณธ์ ์ธ ์ฐจ์ด์ ์ ๋ฐ๊ฒฌํ์ง ๋ชปํ๊ณ ์ผ๋ฐ์ ์ธ ์ต์
์ ์ฌ์ฉํฉ๋๋ค. ์ถ๊ฐ ํญ์ ์ฌ์ฉํ์ฌ ์ ์์๋ฅผ ์ถ๊ฐํ์ฌ ์ปจํธ๋กค๋ฌ๋ฅผ ํ์ฅํด ๋ณด๊ฒ ์ต๋๋ค. ์ฌ์ฉ์๊ฐ ํ์ ๋ชจ์ ์์๋ฅผ ํด๋ฆญํ๋ฉด @GetMapping("/new")์ด ํธ์ถ๋์ด "์์
" ๋๋ ํฐ๋ฆฌ์์ "์" ํ์ด์ง๋ก ๋ฆฌ๋๋ ์
๋๊ณ , ๋ฒํผ์ ์ฌ์ฉํ์ฌ ์
๋ ฅ๋ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ ๋ "๋ฉ์์ง"๋ผ๋ ๋งค๊ฐ๋ณ์๊ฐ ๋ฐํ๋ฉ๋๋ค. ๋ฉ์ธ ๋ธ๋ก์ผ๋ก ๋ฆฌ๋๋ ์
๋ฉ๋๋ค. ์
๋ ฅ ์ฐฝ์ ๋ณ์ ์ด๋ฆ๊ณผ ์ ์ก๋ ๊ฐ์ ์ด๋ฆ์ด ์์ ํ ์ผ์นํด์ผ ํ๊ธฐ ๋๋ฌธ์ ํน๋ณํ ์ธ๊ธ์ด ํ์ํฉ๋๋ค.
<input type="text" class="form-control" id="message" th:name="message" placeholder="Enter your note." maxlength="100"/>
@GetMapping("/new")
public String newNote() {
return "operations/new";
}
@PostMapping("/save")
public String updateNote(@RequestParam String message) {
service.saveNote(new Note(message));
return "redirect:/";
}
์ ์ฌํ ๊ธฐ์ ์ด ๋ ์ฝ๋๋ฅผ ์
๋ฐ์ดํธํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ปจํธ๋กค์ ํด๋ฆญํ๋ฉด @GetMapping("/edit/{id}") ๋งคํ์ด ํธ์ถ๋๊ณ URL ๋ฌธ์์ด์ ์๋ณ์๊ฐ ์ ์ก๋๋ฉฐ ์ถ๊ฐ ํธ์ง์ ์ํ ํญ๋ชฉ๊ณผ ํจ๊ป "note" ์์ฑ์ด ์ถ๊ฐ๋ฉ๋๋ค. @RequestParam(value = "done", require = false) boolean done) ํน์ ๊ฐ์ ์ง์ ํ๋ ๊ฒ์ Thymeleaf ํ
ํ๋ฆฟ ์์ง์ ์ฌ์ฉํ ๋ ์ฒดํฌ๋ฐ์ค ์ฌ์ฉ์ ์ค์ํ ์ญํ ์ ํ๋ฉฐ ๊ธฐ๋ณธ์ ์ผ๋ก "false"๋ก ์ค์ ๋ฉ๋๋ค.
@GetMapping("/edit/{id}")
public String edit(@PathVariable Integer id, Model model) {
Note note = service.getNoteById(id);
model.addAttribute("note", note);
return "operations/edit";
}
@PostMapping("/update")
public String saveNote(@RequestParam Integer id, @RequestParam String message,
@RequestParam(value = "done", required = false) boolean done) {
service.updateNote(id, message, done);
return "redirect:/";
}
๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํญ๋ชฉ์ ์ ๊ฑฐํ๋ ๊ฒ์ ๋งค์ฐ ๊ฐ๋จํ๋ฉฐ ์ ๋ฌ๋ ๊ฐ์ ์ฌ์ฉํ์ฌ ์ ์ ํ ์๋น์ค ํจ์๋ฅผ ํธ์ถํ์ฌ ์ค์ํ ์กฐ์์ด ํ์ํ์ง ์์ต๋๋ค.
@GetMapping("/delete/{id}")
public String delete(@PathVariable Integer id) {
service.deleteNote(id);
return "redirect:/";
}
์ด์ ์์ฑ๋ ์กฐ๊ฐ์ ์ฝ๊ฐ ์กฐ์ ํ๊ณ Spring Data JPA์ ์ฟผ๋ฆฌ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ MySQL๊ณผ์ ํฅ๋ฏธ๋ก์ด ํต์ ์ผ๋ก ๋์ด๊ฐ๊ณ ์ปจํธ๋กค๋ฌ๋ฅผ ๋ซ๊ธฐ ์ ์ ๊ฐ๋จํ ํํฐ๋ง์ ๊ด๋ฆฌํ๋ ๊ธฐ๋ฅ์ ๋ณ๋๋ก ์ถ๊ฐํด ๋ณด๊ฒ ์ต๋๋ค.
@Controller
public class NoteController {
private String sortDateMethod = "ASC";
@GetMapping("/")
public String list(Model model) {
List<Note> notebook = filterAndSort();
model.addAttribute("notes", notebook);
model.addAttribute("sort", sortDateMethod);
return "index";
}
private List<Note> filterAndSort() {
List<Note> notebook = null;
switch (sortDateMethod) {
case "ASC":
notebook = service.findAllByOrderByDateAsc();
break;
case "DESC":
notebook = service.findAllByOrderByDateDesc();
break;
}
return notebook;
}
์์ฃผ ์์ง๋ง ์ค์ํ ์ฟผ๋ฆฌ์ ๋๋ค.
๊ธฐ๋์๋ ๋ฌ๋ฆฌ ๊ฐ์ ํํฐ๋งํ๋ ๊ฒ์ด ๊ธฐ์ ์์ ์ ์ํํ๋ ๋ฐ ๋ ๋ค๋ฅธ ๊ฑธ๋ฆผ๋๋ก ํ๋ช ๋์์ผ๋ฉฐ ํ์ด์ง ๋งค๊น์ผ๋ก ์ค์ ๋ ๋ณต์ก์ฑ ์๊ณ๊ฐ์ ์์ ์๊ฒ ๊ทน๋ณตํ์ต๋๋ค. ์ฆ, ์ถ๊ฐ ํ์๋ฅผ ์ํด ๋ฐ์ดํฐ ๋ฐฐ์ด์ ํน์ ํฌ๊ธฐ์ ๋ณ๋ ํ์ด์ง๋ก ๋๋๋ ๊ฒ์ ๋๋ค. ์๋ง๋ ๋์ ๋ ํผ๋ก๊ฐ ํฐ ํ๊ฒฉ์ ์ ์์ ๊ฒ์ ๋๋ค. ํ์ง๋ง... ์์ ํ ์ฐ์ฐํ ์ฟผ๋ฆฌ ์ฟผ๋ฆฌ๋ฅผ ๋ง๋ ํ์ ์๊ฐ์ด ์๊ฒผ์ต๋๋ค.public interface NoteRepository extends JpaRepository<Note, Integer> {
List<Note> findAllByOrderByDateAsc();
List<Note> findAllByOrderByDateDesc();
}
Spring Data JPA๋ ์ ๋ณด๊ฐ ์์ ๋๋ฉด ์ ๋ ฌํ ํ์๊ฐ ์๊ณ ๊ด๋ฒ์ํ ์ ํ๋ฆฌ์ผ์ด์
์ ์ฌ๋ ฅ์ ๊ฐ๋ ๊ณ ๋๋ก ์ธ๋ถํ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ์๋ฅผ ๋ค์ด:
List<Note> findAllByOrderByDateAsc();
์ด ๋ฉ์๋๋ SQL ์ฟผ๋ฆฌ๋ก ๋ณํ๋์ด ๋ชจ๋ ๋ ์ฝ๋(findAll)๋ฅผ ๋ ์ง(byDate) ๊ธฐ์ค์ผ๋ก ์ค๋ฆ์ฐจ์(Asc)์ผ๋ก ์ ๋ ฌ(byOrder)ํ์ฌ ํ์ํฉ๋๋ค. ๋ํ ๋จ์ผ ์๊ตฌ ์ฌํญ์ผ๋ก ์ฌ๋ฌ ๋ถ์ผ์ ๊ฑธ์ณ ๋ณต์กํ ์กฐํฉ๊ณผ ์ํ๋ง์ ์์ฑํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ๋ ์ง ๊ฐ(byDate)๋ณ๋ก ๊ฐ์(Decs)ํ๋ ์์(byOrder)๋ก ์๋ฃ๋(byDoneTrue) ๋ชจ๋ (findAll) ๋ ์ฝ๋๋ฅผ ์ ํํฉ๋๋ค.
Page<Note> findAllByDoneTrueOrderByDateDesc(Pageable pageable);
GO TO FULL VERSION