본문 바로가기
Project/🥑JPA + SpringSecurity 게시판

[JPA + SpringSecurity 게시판] #8 글 수정하기

by 로띠 2022. 5. 10.

이전 글에서 글 상세보기까지 만들었는데

 

✏️ 글 수정 update에 대해서 만들어보자 ✏️

JPA에서는 table을 조회해 이미 있는 data라면 변경사항을 병합해준다👍

 


코딩시작 👩🏻‍💻

기존 class에 아래 코드를 추가

 

 

 

 

 

 

1. controller

 

 

 

[ BoardController ]

@GetMapping("/post/edit/{id}")
    public String edit(@PathVariable("id") Long id, Model model){
        BoardDto boardDto = boardService.postDtl(id);
        model.addAttribute("board", boardDto);
        return "board/edit";
    }

@PutMapping("/post/edit/{id}")
    public String update(@Valid BoardDto boardDto, BindingResult bindingResult, Model model) {
        // 유효성 검사 실패 시 -- edit 화면 바로리턴
        if (bindingResult.hasErrors()) {
            return "board/edit";
        }
        
        try {
            boardService.savePost(boardDto);
            
        } catch (IllegalStateException e) {
            model.addAttribute("errorMessage", e.getMessage());
            return "board/edit";
        }

        return "redirect:/";
    }

 

   @GetMapping("/post/edit/{id}")  

 

글 수정 시 @GetMapping으로 수정 요청을 받는데

 @PathVariable(”id”) 으로 요청이 들어온 id값을 사용할 수 있다.

 

id값을 받는 이유는

  1. 어떤 id글을 수정할 것인지 식별, 수정 처리를 위해
  2. 해당 id의 원글을 수정 view에 보여주기 위해

 

수정하는데 백지를 주면 수정이라고 하기 좀 곤란행,,, 🥴

 

 

@GetMapping  2번의 이유 boardService.postDtl(id) 호출,

model객체에 담아 view인 board/edit.html을 리턴한다 (타임리프 .html subfix 지원)

 

 

그러면 edit.html에서 ${post.title} ${post.author}  value를 사용 가능

그리고 view는 1번의 이유 ${post.id}를 다시 서버로 전송한다

 

 

 

 

 

  @PutMapping("/post/edit/{id}")  

 

@PutMapping으로 매핑 시 비즈니스 로직을 호출한다

html에서 PutMapping이 지원되지 않지만 아래에 사용법이 나온다

 

 

JPA에서 Data처리 방식은 id를 조회하여

  1. 없으면 생성하고
  2. 있으면 변경사항을 병합하기 때문에

 

insert, update를 모두 save()를사용하고

게시글 Create에서 사용했던 로직인 boardService.savePost(boardDto)를 호출한다

 

 

 

bindingResult 유효성 체크는 글쓰기와 동일.

 

 


2. edit.html

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout/layout}">

<!-- 사용자 CSS 추가 -->
<th:block layout:fragment="css">
    <style>
        .fieldError {
            color: #b73a3a;
        }
    </style>
</th:block>

<!-- 사용자 스크립트 추가 -->
<th:block layout:fragment="script">

    <script th:inline="javascript">
        $(document).ready(function(){
            var errorMessage = [    [${errorMessage}]    ];
            if(errorMessage != null){
                alert(errorMessage);
            }
        });
    </script>
</th:block>

<div layout:fragment="content">
    <div class="container">
        <form th:object="${board}" th:action="@{'/post/edit/' + ${id}}" method="post" >
            <input type="hidden" name="_method" value="put"/>
            <input type="hidden" name="id" th:value="${id}"/>
            <div class="form-group row">
                <label for="inputTitle" class="col-sm-2 col-form-label"><strong>제목</strong></label>
                <div class="col-sm-10">
                    <input type="text" name="title" class="form-control" id="inputTitle" th:value="${board.title}">
                    <p th:if="${#fields.hasErrors('title')}" th:errors="*{title}" class="fieldError">Incorrect data</p>

                </div>
            </div>
            <div class="form-group row">
                <label for="inputAuthor" class="col-sm-2 col-form-label"><strong>작성자</strong></label>
                <div class="col-sm-10">
                    <input type="text" name="author" class="form-control" id="inputAuthor" th:value="${board.author}" readonly>
                </div>
            </div>
            <div class="form-group row">
                <label for="inputContent" class="col-sm-2 col-form-label"><strong>내용</strong></label>
                <div class="col-sm-10">
                    <textarea type="text" name="content" class="form-control" id="inputContent"th:text="${board.content}"></textarea>
                </div>
            </div>
            <div class="row">
                <div class="col-auto mr-auto"></div>
                <div class="col-auto">
                    <input class="btn btn-success" type="submit" role="button" value="수정">
                    <a class="btn btn-danger" th:href="@{'/post/' + ${id}}" role="button">취소</a>
                </div>
            </div>
        </form>
    </div>
</div>

</html>
 
 

✅ Html에서

  • <form> Get, Post의 method만 사용가능하고
  • 클라이언트가 입력한 값을 전송
  • 하지만 Type=”hidden” 사용 시 value를 서버로 전송

 

 

이 점을 이용해 html에서도 Put, Delete Mapping이 사용가능 

 

  1. form 자체는 Post로 전송하면서
  2.   <input type="hidden" name="_method" value="put"/>  를 같이 전송하면 Put으로 전송
  3. → @PutMapping 매핑 가능
  4. ✅ application.propertie 에서 히든필터 활성화 필요 (아래 3 참고)

 

 

  <input type="hidden" name="id" th:value="${board.id}"/>  

 

hidden 으로 id값을 넘겨주는 이유는

 

글쓰기와 글수정은 JPA에서 같은 save()메소드를 사용하는데

글쓰기 create는 원본글이 없으니 id값이 존재하지않고 자동생성을 한다

 @GeneratedValue(strategy = GenerationType.IDENTITY) (DB위임)

 

 

하지만 수정은 원본글에 새 내용을 병합하기 때문에 기존 id값을 알아야한다

위 controller에서 @GetMapping을 기억해보자

 

@GetMapping("/post/edit/{id}")
    public String edit(@PathVariable("id") Long id, Model model){
        BoardDto boardDto = boardService.postDtl(id);
        model.addAttribute("board", boardDto);
        return "board/edit";
    }

 

이미 “post”모델 객체에 담아서 view로 보냈기 때문에

view는 ${board.id}값을 알고있고 다시 서버로 전송한다

 

 

 


 

3. application.properties

 

 

스프링 2.2부터는 Put, Delete 사용을 위해 별도 설정

 

✅ hidden 필터 활성화

spring.mvc.hiddenmethod.filter.enabled=true

 

 

 


4. detail.html

 

✅ 글 상세보기에서 수정으로 넘어갈 수 있도록 button 추가

<div class="row mt-3">
	<div class="col-auto">
		<a class="btn btn-info" th:href="@{'/post/edit/' + ${board.id}}" role="button">수정</a>
	</div>
	<div class="col-left mr-auto"></div>
	<div class="col-auto">
		<a class="btn btn-success" th:href="@{'/'}" role="button">목록</a>
	</div>
</div>

 

약 18행 쯤 <class = “row mt-3”> 태그 바로 밑에 수정 코드 추가

 

오예 이거 끝인거 같은데?

 

 

 

 

끝!!!!!

 

 

 

 

수정 전 (상세보기) 에서 수정을 누르면

작성자는 readOnly 수정이 안되는게 맞고 수정버튼을 누르면

 

수정사항이 반영된 상세보기 view로 redirect된다 성공이다 !

 

 

 

 

👩🏻‍💻다음 글에서는 제일 쉬운

Delete 레츠고~~~~

 

 

 

 

👋그럼이만