Day 7
์ด์ ์ ๋ง๋ค์๋ mustache ํ
ํ๋ฆฟ์ ์ปจํธ๋กค๋ฌ๋ฅผ ๋ง๋ค์ด๋ณด์
ํ์ด์ง์ ๊ด๋ จ๋ ์ปจํธ๋กค๋ฌ๋ IndexController์ ์ถ๊ฐ
src/main/java/com/kyu/book/springboot/web/dto/IndexController
@GetMapping("/posts/save")
public String postSave(){
return "posts-save";
}
์ฌ๊ธฐ์ posts-save๋ฅผ ํธ์ถํ๋ ์ฝ๋๋ฅผ ์ถ๊ฐ
๊ธ์ ๋ฑ๋กํ๋ ํ์ด์ง๋ฅผ ์์ฑ
src/main/resource/template/posts-save.mustache
{{>layout/header}}
<h1>๊ฒ์๊ธ ๋ฑ๋ก</h1>
<div class="col-md-12">
<div class="col-md-4">
<form>
<div class="form-group">
<label for="title">์ ๋ชฉ</label>
<input type="text" class="form-control" id="title" placeholder="์ ๋ชฉ์ ์
๋ ฅํ์ธ์">
</div>
<div class="form-group">
<label for="author"> ์์ฑ์ </label>
<input type="text" class="form-control" id="author" placeholder="์์ฑ์๋ฅผ ์
๋ ฅํ์ธ์">
</div>
<div class="form-group">
<label for="content"> ๋ด์ฉ </label>
<textarea class="form-control" id="content" placeholder="๋ด์ฉ์ ์
๋ ฅํ์ธ์"></textarea>
</div>
</form>
<a href="/" role="button" class="btn btn-secondary">์ทจ์</a>
<button type="button" class="btn btn-primary" id="btn-save">๋ฑ๋ก</button>
</div>
</div>
{{>layout/footer}}
ํ์ฌ๊น์ง๋ localhost:8080์ผ๋ก ์ ์ โ ๊ธ ๋ฑ๋ก(๋ฒํผ)์ ๋๋ฆ โ posts-save.mustache๋ก ์ด๋๋์ ๊ธ ๋ฑ๋กํ๋ ํ์ด์ง๋ฅผ ๋ณผ ์ ์์
๊ธ์ ๋ฑ๋กํ๋ ๋ฒํผ์ ๋๋ฅด๋ฉด API๋ฅผ ํธ์ถํด์ฃผ๋ jsํ์ผ์ ์์ฑํด์ผํจ
src/main/resources/static/js/app/index.js
var main = {
init : function(){
var _this = this;
$('#btn-save').on('click', function(){
_this.save();
});
},
save : function(){
var data = {
title: $('#title').val(),
author: $('#author').val(),
content: $('#content').val()
};
$.ajax({
type: 'POST',
url: '/api/v1/posts',
dataType: 'json',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(data)
}).done(function(){
alert('๊ธ์ด ๋ฑ๋ก๋์์ต๋๋ค.');
window.location.href='/';
}).fail(function(error){
alert(JSON.stringify(error));
});
}
};
main.init();
์๋ ๋ง๋ค์ด๋์๋ API๋ฅผ ํธ์ถํ๋ javascriptํ์ผ
๋ธ๋ผ์ฐ์ ์ ์ค์ฝํ๋ ๊ณต์ฉ ๊ณต๊ฐ์ผ๋ก ์ฐ์ด๊ธฐ ๋๋ฌธ์ ๋์ค์ ๋ก๋ฉ๋ js์ init, save๊ฐ ๋จผ์ ๋ก๋ฉ๋ js์ function์ ๋ฎ์ด์ฐ๊ฒ ๋๋ค โ ๊ทธ๋์ index.js๋ง์ ์ ํจ๋ฒ์(scope)๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉ
var index๋ผ๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ํด๋น ๊ฐ์ฒด์์ ํ์ํ ๋ชจ๋ function์ ์ ์ธํ์ โ index๊ฐ์ฒด ์์์๋ง function์ด ์ ํจํ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ js์๋ ๊ฒน์น ์ํ์ด ์ฌ๋ผ์ง๊ฒ ๋จ
ํ์ฌ index์ ํธ์ถ ์ฝ๋๋ฅผ ๋ณด๋ฉด /(์ ๋๊ฒฝ๋ก)์์ ์์
์คํ๋ง๋ถํธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก src/main/resource/static์ ์์นํ js, css ๋ฑ ์ ์ ์ธ ํ์ผ๋ค์ URL์์ /๋ก ์ค์
๋ฑ๋ก ๋ฒํผ์ ๋๋ฅด๋ฉด ์๋๋ฆฌ๋ ๋ฌธ์ ๊ฐ ์๋ค
resources์์ static/js/app ๋๋ ํ ๋ฆฌ๋ฅผ ๋ง๋ค๊ณ ์์ index.js๋ฅผ ์์ฑํ๋๋ฐ IDE์์ ๋ณผ๋ ๊ตฌ๋ถ์ด . ์ผ๋ก ๋์ด์์ด์ ์๋ฌด์๊ฐ์์ด . ์ผ๋ก ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํ์๋ค
โ๊ฒฐ๊ณผ์ ์ผ๋ก static/js/app ์ด๋ฆ์ผ๋ก ๋๋ ํ ๋ฆฌ๋ฅผ ๋ค์ ์์ฑํด์ค
์ ์ฒด ์กฐํ ํ๋ฉด ๋ง๋ค๊ธฐ
index.mustachedml UI๋ฅผ ๋ณ๊ฒฝ
src/main/resources/templates/index.mustache
{{>layout/header}}
<h1>์คํ๋ง ๋ถํธ๋ก ์์ํ๋ ์น ์๋น์ค</h1>
<div class="col-md-12">
<div class="col-md-6">
<a href="posts/save" role="button" class="btn btn-primary">๊ธ ๋ฑ๋ก</a>
</div>
<br>
<table class="table table-horizontal table-bordered">
<thread class="thead-strong">
<tr>
<th>๊ฒ์๊ธ๋ฒํธ</th>
<th>์ ๋ชฉ</th>
<th>์์ฑ์</th>
<th>์ต์ข
์์ ์ผ</th>
</tr>
</thread>
<tbody id="tbody">
{{#posts}}
<tr>
<td>{{id}}</td>
<td>{{title}}</td>
<td>{{author}}</td>
<td>{{modifiedDate}}</td>
</tr>
{{/posts}}
</tbody>
</table>
</div>
{{>layout/footer}}
๋จธ์คํ ์น์ ๋ฌธ๋ฒ์ด ์ฌ์ฉ๋จ
{{#posts}} : posts๋ผ๋ List๋ฅผ ์ํํ๋ค
Java์ for๋ฌธ์ด๋ผ๊ณ ์๊ฐ
{{id}}๋ฑ์ ๋ณ์๋ช : List์์ ๋ฝ์๋ธ ๊ฐ์ฒด์ ํ๋๋ฅผ ์ฌ์ฉ
Controller, Service, Repository ์ฝ๋๋ฅผ ์์ฑ
๊ธฐ์กด์ ์๋ Repository์ธํฐํ์ด์ค์ ์ฟผ๋ฆฌ๊ฐ ์ถ๊ฐ๋จ
src/main/java/com/kyu/book/springboot/domain/posts/PostsRepository
package com.kyu.book.springboot.domain.posts;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface PostsRepository extends JpaRepository<Posts, Long> {
@Query("SELECT p FROM Posts p ORDER BY p.id DESC ")
List<Posts> findAllDesc();
}
์ฒ์์ผ๋ก ์ฟผ๋ฆฌ๋ฌธ์ ์์ฑํ๊ฒ ๋์๊ณ ์ฟผ๋ฆฌ๋ฌธ์ ์ฌ์ฉํ๊ธฐ ์ํด์ @Query ํ๊ทธ๋ฅผ ์ฌ์ฉ
๋ฐ์ดํฐ์ ์กฐํ๊ฐ ๋ณต์กํด์ง๋ฉด
read๋ MyBatis ๋ฅผ ์ฌ์ฉ
create, update, delete๋ SpringDataJPA๋ฅผ ์ฌ์ฉ
๋ค์์ผ๋ก๋ PostsService์ ์ฝ๋๋ฅผ ์ถ๊ฐ
src/main/java/com/kyu/book/springboot/service/posts/PostsService
@Transactional(readOnly = true)
public List<PostsListResponseDto> findAllDesc(){
return postsRepository.findAllDesc().stream().map(PostsListResponseDto::new).collect(Collectors.toList());
}
@Transactional(readOnly = true)์ด๋ ๊ฒ ์ต์ ์ ์ถ๊ฐ
readOnly = true ๋ ํธ๋์ ์ ์ ๋ฒ์๋ ์ ์งํ๋, ์กฐํ ๊ธฐ๋ฅ๋ง ๋จ๊ฒจ๋๋ ๊ฒ
์กฐํ ์๋๊ฐ ๊ฐ์
create, update, delete๊ธฐ๋ฅ์ด ์ ํ ์๋ ์๋น์ค ๋ฉ์๋์์ ์ฌ์ฉํ๋ ๊ฒ์ ์ถ์ฒ
์ฌ๊ธฐ์ PostsListResponseDto๊ฐ ์์
๋ฐ๋ก ์ฌ๊ธฐ์ ์์ฑํด์ค
src/main/java/com/kyu/book/springboot/web/dto/PostsListResponseDto
package com.kyu.book.springboot.web.dto;
import com.kyu.book.springboot.domain.posts.Posts;
import lombok.Getter;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
@Getter
public class PostsListResponseDto {
private Long id;
private String title;
private String author;
private LocalDateTime modifiedDate;
public PostsListResponseDto(Posts entity){
this.id = entity.getId();
this.title = entity.getTitle();
this.author = entity.getAuthor();
this.modifiedDate = entity.getModifiedDate();
}
}
์ฝ์์ผ๋๊น ์ฝ์ ๊ฒ์ ์ถ๋ ฅํด์ฃผ๊ธฐ ์ํด์ IndexController ์์
src/java/main/kyu/book/springboot/web/dto/IndexController
package com.kyu.book.springboot.web.dto;
import com.kyu.book.springboot.service.posts.PostsService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@RequiredArgsConstructor
@Controller
public class IndexController {
private final PostsService postsService;
//๋ณ๊ฒฝ์ฌํญ์ด ์๋ ๊ณณ
@GetMapping("/")
public String index(Model model){
model.addAttribute("posts", postsService.findAllDesc());
return "index";
}
//////////////////
@GetMapping("/posts/save")
public String postSave(){
return "posts-save";
}
}
Model
์๋ฒ ํ ํ๋ฆฟ ์์ง์์ ์ฌ์ฉํ ์ ์๋ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ ์ ์์
์ฌ๊ธฐ์์๋ postsService.findAllDesc()๋ก ๊ฐ์ ธ์จ ๊ฒฐ๊ณผ๋ฅผ posts๋ก index.mustache์ ์ ๋ฌํ๋ค
Last updated
Was this helpful?