
수정 버튼을 누르면 '수정 페이지'로 이동해야 한다.
[ updateForm (글 수정 화면) 만들기 ] - mustache 코드
{{> /layout/header}}
<div class="container p-5">
<!-- 요청을 하면 localhost:8080/board/save POST로 요청됨
title=사용자입력값&content=사용자값 -->
<div class="card">
<div class="card-header"><b>수정하기 화면입니다</b></div>
<div class="card-body">
<form action="/board/1/update" method="post" enctype="application/x-www-form-urlencoded">
<div class="mb-3">
<input type="text" class="form-control" placeholder="Enter title" name="title" value="제목1">
</div>
<div class="mb-3">
<textarea class="form-control" rows="5" name="content">내용1</textarea>
</div>
<button type="submit" class="btn btn-primary form-control">수정완료</button>
</form>
</div>
</div>
</div>
{{> /layout/footer}}

글을 수정하려면… 기존에 글이 적혀있어야 한다 = DB 조회 필요
그래서 @GetMapping("/board/{id}/updateForm") 라고 {id}를 적은 것.
{id}를 받지 않으면 조회가 안 돼
user 정보까지 필요 없고, board만 가져오면 되니까 findById 메소드를 사용하자
만약 작성자 이름 ssar 이라고까지 적혀 있으면 join을 써야 한다.
join, 서브쿼리, OrderBy = DB에 부하를 심하게 줌
메서드를 구현하다보면 핵심로직 (메서드의 주요 목적과 주요 책임)을 잊을 수 있다. 부가로직 (메서드가 가져야하는 부가적인 기능)을 구현하다 보면 그렇게 된다. 현업에 가게되면 부가로직들은 모두 리플렉션 처리되어 있을 것
[ BoardController 생성 ]
@GetMapping("/board/{id}/updateForm")
public String updateForm(@PathVariable int id, HttpServletRequest request) {
// 인증 체크 (인증 안되면 나가)
User sessionUser = (User) session.getAttribute("sessionUser");
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 권한 체크 (로그인한 유저의 아이디와 작성자 아이디 비교.)(권한 없으면 나가)
// 조회 없이 권한 체크를 못한다. 게시글 누가 썼는지 모르잖아. 그래서 조회 먼저
// 모델 위임 (id로 board를 조회)
Board board = boardRepository.findById(id);
if (board.getUserId() != sessionUser.getId()) {
return "error/403";
}
// 3. 가방에 담기
request.setAttribute("board", board);
return "board/updateForm";
}
[ 핵심 로직 ]
Board board = boardRepository.findById(id);
request.setAttribute("board", board);
return "board/updateForm";
[ updateForm.mustache ] - 머스태치로 데이터 뿌리기

<textarea>는 value 없으니 바로 적어줌
[ detail.mustache ] - 상세보기 화면에서 업데이트 화면으로 이동하는 버튼 수정

get요청이면 그냥 하이퍼링크 하면 되어서 a태그 사용함
수정 버튼 누르면 바로 /updateForm으로 가게끔
[ 테스트 해보기 ]


수정하기 화면이 잘 뜬다
[ 게시글 수정하기 (액션) ]


고치자
1. DTO 만들기

의문 사항... 있는거 쓰면 안되나? 똑같은데… 안돼요!!!!!!!!!!!!!! 유효성이 다를 수가 있어서 똑같아도 만드는게 좋다. 관리를 따로!

DTO는 화면마다 들고 있어야 한다
@RequestBody … 여담

파싱 전략이 json으로 바뀜
@RequestBody + (리퀘스트바디?) 오브젝트를 적으면 = json으로 받아줌
@RequestBody + String이면 = 평문 text/plain ㅇㅇ
포스트맨으로 자기가 만든 컨트롤러를 화면없이 테스트해볼 수 있다

아직 header에 content-type 이없네


포스트맨이 자동으로 x-form으로 잡아주네

평문 전략

포스트맨에서 평문을 전송했다

콘솔창에서 전송된 평문 확인
(+이 세상에 존재하지 않는 데이터 = 평문으로 받고 내가 직접 파싱)

json으로 보내니

json으로 왔다

쿼리를 보고 몇 개를 넘겨줘야 할 지 정한다 (requestDTO와 id까지 넘겨줘야)
[ 컨트롤러 ]
@PostMapping("/board/{id}/update")
public String update(@PathVariable int id, BoardRequest.UpdateDTO requestDTO) {
// 1. 인증 체크
User sessionUser = (User) session.getAttribute("sessionUser");
if (sessionUser == null) {
return "redirect:/loginForm";
}
// 2. 권한 체크
Board board = boardRepository.findById(id);
if (board.getUserId() != sessionUser.getId()) {
return "error/403";
}
// 3. 핵심 로직
// update board_tb set title = ?, content = ? where id = ?;
boardRepository.update(requestDTO, id);
return "redirect:/board/"+id; //상세 보기 화면으로 돌아가기
}
return "redirect:/board/{id}";와 같이 코드를 작성하면 안됩니다.
이유는 {id}는 경로 변수(path variable)로 인식되어 처리되지 않기 때문입니다.
대신에, return "redirect:/board/" + id;와 같이 id 값을 직접 문자열로 연결하여 사용해야 한다.
이렇게 하면 id 값을 동적으로 경로에 포함시킬 수 있습니다.
[ BoardRepository ]
public class BoardRepository {
private final EntityManager em;
@Transactional
public void update(BoardRequest.UpdateDTO requestDTO, int id) {
Query query = em.createNativeQuery("update board_tb set title = ?, content = ? where id = ?");
query.setParameter(1, requestDTO.getTitle());
query.setParameter(2, requestDTO.getContent());
query.setParameter(3, id);
query.executeUpdate();
}
[ 결과 확인하기 ]


수정됐다
AOP - 우리가 코드 짤 때, 핵심 로직만 짜고, 부가로직은 자동화 시킬 수 있는 것
로그 관리의 중요성!
파일에 오류가 터진 시간, 아이디 등을 로그로 남겨놔야 한다. 모든 오류는 Try-Catch로 잡아서 남겨놔야… 그래야 오류를 파악할 수 있음
Share article