{{>layout/header}}<h1>스프링 부트로 시작하는 웹 서비스</h1>{{>layout/footer}}
{{>layout/header}}<h1>스프링 부트로 시작하는 웹 서비스</h1><div class = "col-md-12"> <div class = "row"> <div class = "col-md-6"> <a href="/posts/save" role="button" class="btn btn-primary">글 등록</a> </div> </div></div>{{>layout/footer}}
public class IndexController{ // 기존 코드 @GetMapping("/posts/save") public String postSave() { return "posts-save"; }}
{{>layout/header}}<h1>스프링 부트로 시작하는 웹 서비스</h1><div class = "col-md-12"> <div class = "row"> <div class = "col-md-6"> <a href="/posts/save" role="button" class="btn btn-primary">글 등록</a> </div> </div> <br> <!--목록 출력 영역--> <table class="table table-horizontal table-bordered"> <thread class="thread=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}}
package com.jojoldu.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();}
// 기존 코드import com.jojoldu.book.springboot.web.dto.PostsListResponseDto;import java.util.List;import java.util.stream.Collectors;@RequiredArgsConstructor@Servicepublic class PostsService{ // 기존 코드 @Transactional(readOnly = true) // 트랜잭션 범위는 유지하되 조회 기능만 남겨두어 조회 속도 개선 public List<PostsListResponseDto> findAllDesc() { return postsRepository.findAllDesc().stream() .map(PostsListResponseDto::new) .collect(Collectors.toList()); }}
// 기존 코드import org.springframework.ui.Model;import lombok.RequiredArgsConstructor;@RequiredArgsConstructor@Controllerpublic class IndexController{ private final PostsService postsService; @GetMapping("/") public String index(Model model) // 기존 index 수정 { model.addAttribute("posts", postsService.findAllDesc()); return "index"; } // 기존 코드}
public class PostsApiController{ // 아래 내용 추가 @PutMapping("/api/v1/posts/{id}") public Long update(@PathVariable Long id, @RequestBody PostsUpdateRequestDto requestDto) { return postsService.update(id, requestDto); }}
var main = { init : function () { // ... // btn-update란 id를 가진 HTML 엘리먼트에 click 이벤트가 발생할 때 update function을 실행하는 이벤트 등록 $('#btn-update').on('click', function (){ _this.update(); }); }, save : function () { //... }, update : function (){ var data = { title: $('#title').val(), content: $('#content').val() }; var id = $('#id').val(); $.ajax({ type: 'PUT', url: '/api/v1/posts/'+id, // 어느 게시글을 수정할지 URL PATH로 구분하기 위해 id 추가 dataType: 'json', contentType: 'application/json; charset=urf-8', data: JSON.stringify(data) }).done(function (){ alert('글이 수정되었습니다.'); window.location.href = '/'; }).fail(function (error) { alert(JSON.stringify(error)); }); }};
var main = { init : function () { //... $('#btn-delete').on('click', function (){ _this.delete(); }); }, //... delete : function (){ var id = $('#id').val(); $.ajax({ type: 'DELETE', url: '/api/v1/posts/' +id, dataType: 'json', contentType: 'application/json; charset=utf-8' }).done(function (){ alert('글이 삭제되었습니다.'); window.location.href = '/'; }).fail(function (error){ alert(JSON.stringify(error)) }); }};
@RequiredArgsConstructor@Servicepublic class PostsService{ // ... @Transactional public void delete (Long id) { Posts posts = postsRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다. id=" + id)); // JpaRepository에서 지원하는 메소드 활용 // deleteById(id)도 사용 가능 postsRepository.delete(posts); }}
@RequiredArgsConstructor@RestControllerpublic class PostsApiController{ //... @DeleteMapping("/api/v1/posts/{id}") public Long delete(@PathVariable Long id) { postsService.delete(id); return id; }}