Back-End/Springboot와 AWS로 혼자 구현하는 웹 서비스

Chapter 04. 머스테치로 화면 구성하기 (5)

yeonx 2022. 3. 19. 16:31
728x90

4.5 게시글 수정, 삭제 화면 만들기

 

게시글 수정

posts-update.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="id" value="{{post.id}}" readonly>
            </div>
            <div class="form-group">
                <label for="title">제목</label>
                <input type="text" class="form-control" id="title" value="{{post.title}}">
            </div>
            <div class="form-group">
                <label for="author"> 작성자 </label>
                <input type="text" class="form-control" id="author" value="{{post.author}}" readonly>
            </div>
            <div class="form-group">
                <label for="content"> 내용 </label>
                <textarea class="form-control" id="content">{{post.content}}</textarea>
            </div>
        </form>
        <a href="/" role="button" class="btn btn-secondary">취소</a>
        <button type="button" class="btn btn-primary" id="btn-update">수정 완료</button>
        <button type="button" class="btn btn-danger" id="btn-delete">삭제</button>
    </div>
</div>

{{>layout/footer}}
① {{post.id}}
 - 머스테치는 객체의 필드 접근 시 점(Dot)으로 구분
 - 즉, Post 클래스의 id에 대한 접근은 post.id로 사용할 수 있다.

② readonly
 - input 태그에 읽기 기능만 허용하는 속성
 - id와 author은 수정할 수 없도록 읽기만 허용하도록 추가

 

 btn-update 버튼을 클릭하면 update 기능을 호출할 수 있게 index.js 파일에도 update function을 하나 추가한다.

 

index.js

var main = {
    init : function () {
        var _this = this;
        ...
        $('#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,
            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();
① $('#btn-update').on('click')
 - btn-update란 id를 가진 HTML 엘리먼트에 click 이벤트가 발생할 때 update function을 실행하도록 이벤트를 등록

② update : function()
 - 신규로 추가될 update function

③ type : 'PUT'
 - 여러 HTTP Method 중 PUT 메서드를 선택
 - PostsApiController에 있는 API에서 이미 @PutMapping으로 선언했기 때문에 PUT을 사용해야 함. 참고로 이는 REST 규약에 맞게 설정된 것 
 - REST에서는 CRUD는 다음과 같이 HTTP Method에 매핑
   생성(Create) - POST
   읽기(Read) - GET
   수정(Update) - PUT
   삭제(Delete) - DELETE

④ url : '/api/v1/posts/' + id
 - 어느 게시글을 수정할지 URL Path로 구분하기 위해 Path에 id를 추가

 

** 수정 페이지로 이동할 수 있게 기능을 추가

index.mustache에 다음 코드 변경

index.mustache

<tbody id="tbody">
{{#posts}}
    <tr>
        <td>{{id}}</td>
        <td><a href="/posts/update/{{id}}">{{title}}</a></td>
        <td>{{author}}</td>
        <td>{{modifiedDate}}</td>
    </tr>
{{/posts}}
</tbody>
① <a href="/posts/update/{{id}}"></a>
 - 타이틀(title)에 a tag 추가
 - 타이틀을 클릭하면 해당 게시글의 수정 화면으로 이동

 

IndexController에 수정 화면을 연결할 다음 코드 추가

 

IndexController.java

@GetMapping("/posts/update/{id}")
public String postsUpdate(@PathVariable Long id, Model model){
    PostsResponseDto dto = postsService.findById(id);
    model.addAttribute("post",dto);
    return "posts-update";

}

 

실행

수정 링크

수정 링크를 클릭하면

제목과 내용 수정
수정 완료 메시지
수정 후 목록

 

위와 같이 변경할 수 있게 됨

 

 


게시글 삭제

 

수정 화면에 삭제 버튼 추가

posts-update.mustache

<a href="/" role="button" class="btn btn-secondary">취소</a>
<button type="button" class="btn btn-primary" id="btn-update">수정 완료</button>
<button type="button" class="btn btn-danger" id="btn-delete">삭제</button>
① btn-delete
 - 삭제 버튼을 수정 완료 버튼 옆에 추가
 - 해당 버튼 클릭 시 JS에서 이벤트를 수신

 

index.js

var main = {
    init : function () {
        var _this = this;
        ...
        $('#btn-delete').on('click', function () {
            _this.delete();
        });
    },
    save : function () {
        ...
    },
    update : function(){
        ...
    },

     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));
        });
    }
};

main.init();

 

삭제 API를 만들어 보자

 

PostsService.java

@Transactional
public void delete (Long id){
    Posts posts = postsRepository.findById(id).orElseThrow(()->new IllegalArgumentException("해당 게시글이 없습니다. id=" +id));

    postsRepository.delete(posts);

}
① postsRepository.delete(posts)
 - JpaRepository에서 이미 delete 메서드를 지원하고 있음
 - 엔티티를 파라미터로 삭제할 수도 있고, deleteById 메소드를 이용하면 id로 삭제할 수 있다.
 - 존재하는 Posts인지 확인을 위해 엔티티 조회 후 그대로 삭제

 

PostsApiController.java

@DeleteMapping("/api/v1/posts/{id}")
public Long delete(@PathVariable Long id){
    postsService.delete(id);
    return id;
}

 

실행

삭제 버튼
삭제 성공 메시지
삭제 확인

 

출처 : 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 [이동욱 지음]