스프링 부트(Spring Boot)로 간단한 게시판 만들기 - 4
이전 단계였던 게시물 삭제 기능 구현에 이어, 게시물 수정을 해보도록 하자
6) 게시물 수정
- 게시물 수정 페이지 생성
우선, 게시물 수정 버튼을 만들어주자. view부분에 넣어줘야하기에 boardview.html 파일에 아래와 같이 a태그를 한 줄 추가해준다.
위 a태그에서 id를 지정하는 것과 우리가 써야할 a태그의 id지정 방식이 다른데, 위 방식은 query string방식으로 url 관점에서 볼 때 ?id={번호} 이런 식으로 나타난다. 우리가 하는 path variable방식은 주소창에 비교적 깔끔하게 /{번호} 식으로 나타난다.
그리고 해당 수정페이지가 구현되지 않았기 때문에 Controller에 매핑해준다.
여기서 경로 매핑에서 이전에 사용하지 않은 path variable 방식을 사용했는데 위와 같이 변수로 경로를 지정해놓는 것을 말하고 나머진 거의 비슷하다. 메서드에 들어가는 인자 @PathVariable("id")를 해주어야 한다. 위에서 GetMapping에서의 {id}부분은, modify/이후 나오는 값이 id값이라는 점을 의미하고, @PathVariable("id") Integer id 부분은 Path variable로 얻은 id 변수가 Integer자료형이라는 점을 알리는 역할이다.
그리고 이제 창에 드러날 boardmodify.html파일을 만들자. 수정은 write와 거의 차이가 없기에 boardwrite.html을 복붙했다. 그리고 한번 실행해보자.
글 수정 버튼이 있고, 눌러보았다.
이전에 우리가 만들었었던 boardwrite.html이 modify/(id값) 경로에 잘 나타나는 것을 확인할 수 있다.
- 게시물 수정 처리
하지만 수정하려면 원래 textarea에 들어있던 텍스트가 그대로 탑재된 상태로 불러와져야 수정이 가능할 것이다. 한번 가져와보도록 하자.
Controller로 이동 후, Modify메서드 매개변수에 모델을 추가하고, 내용을 불러 넘겨다 줄 명령을 추가해준다.
그리고 아래와 같이 boardmodify.html을 수정해준다.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">(수정됨)
<head>
<meta charset="UTF-8">
<title>게시물 작성폼</title>
</head>
<style>
.layout{
width : 500px;
margin : 0 auto;
margin-top : 40px;
}
</style>
<body>
<div class="layout">
<form action="/board/writedo" method="post">
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">Name</label>
<input type="text" name="title" id="exampleFormControlInput1" th:value="${board.title}">(수정됨)
</div>
<br>
<div class="mb-3">
<label for="exampleFormControlTextarea1" class="form-label">Example textarea</label><br>
<textarea id="exampleFormControlTextarea1" name="content" rows="5" th:text="${board.content}">(수정됨)</textarea>
</div>
<button type="submit">작성</button>
</form>
</div>
</body>
</html>
위의 수정된 부분들을 추가해준다. 그리고 한번 재실행 후 아까 페이지로 들어가게 되면,
위와같이 id가 2인 게시물 수정 창에 그 title과 content가 들어가 수정할 수 있는 것을 확인할 수 있다.
그리고 여기서 버튼을 누르면 수정이 되어야하는데, 그것을 구현해보기위해 boardmodify.html을 더 수정한다.
id에 따른 update경로를 지정, 해당 폼이 수정버튼이 눌러지면 넘어갈 수 있게 설정해줬다.
그리고 controller로 이동.
그리고 board 자료형을 이용해 우리가 write를 수행했듯 비슷하게 수정한 내용도 board자료형에 담아 다시 써주는 과정을 거친다.
그리고 re run후 접속,
위와 같은 내용으로 수정을 누르면
redirect로 list로 이동하게 되고 수정된 title이 보인다.
content까지 잘 수정된 것을 볼 수 있다.
+ 글 작성, 수정 시 메세지 띄우기
글 작성 시에 작성이 된 것을 확인하려면 리스트에서 가장 아래까지 내려야 하는 불편함이 있다. 글 작성을 잘 완수했으면 글 작성이 되었다고 알려주는 메시지를 만들어보자
우선 templates에 message.html을 만들어주고 아래 코드를 넣는다.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<script th:inline="javascript">
/*<![CDATA[*/
var message = [[${message}]];
alert(message);
location.replace([[${searchUrl}]]);
/*]]>*/
// controller에서 메시지를 여기서 전송, 메시지를 여기서 받아서 자바스크립트에서 창을 띄워즈는 alert에 담아 띄우고,
페이지를 이동시키는 location.replace로 경로를 담아 작성해준 것
</script>
<body>
</body>
</html>
script내부 코드는 자바스크립트에서 메시지를 띄우는 코드이다.
message.html을 만들었고 코드를 추가했다면 controller로 이동한다.
controller에서 글 작성하는 메서드에서 model인자를 추가 후 몇 줄 더 추가해준다.
message, searchUrl이라는 변수에 값을 저렇게 담고 message.html에 보내주는 것이다.
한번 re run하고 글을 작성해보도록 하자.
내용을 아무거나 넣고 작성 버튼을 누르니 위와 같은 메세지와 함께 list페이지로 이동했다.
나중에 if문을 활용해 등록성공, 실패에 따라 메시지를 다르게 할 수도 있겠다.
수정시 메시지를 띄우는 것도 작성 시 메시지 띄우는 것 만큼 쉬우니 따라해보길 바란다.
+ 게시판 파일 업로드
게시판이면 필요 시 파일 업로드 기능도 있어야 할 것이다.(사진, 영상 등) 한번 구현해보도록 하자.
우선은 게시판에 파일을 탑재하기 위해선 데이터베이스 내 column들도 파일을 위해 추가해야하는 부분이 있는데 workbench에 들어가서 추가해주도록 하겠다.
board 테이블 옆 스패너 버튼을 누르면 column들을 볼 수 있는데 여기서 추가해줄 수 있다.
위와 같이 filename, filepath column을 추가해주고, 오른쪽 하단의 apply를 눌러주면 적용이 된다.
이렇게 데이터베이스 column이 바뀌면 이전에 만든 entity 양식도 바뀌어야 하니 entity폴더 내 Board 파일을 열어주자
그리고 위와 같이 기존에 추가했던 column들을 추가해주면 된다.
그리고 작성 탭에서 파일을 등록할 수 있는 버튼을 만들기 위해 boardwrite.html에 들어가서,
빨간 밑줄부분을 추가해주자.
그리고 확인해보면 파일 선택이라는 버튼이 생겼고 파일을 첨부할 수 있다. 하지만 아직 파일이 데이터베이스까지 담기기 위한 코드를 작성하지 않았기에 마저 만들어보자.
일단 resources폴더 아래, static폴더 하에 files라는 이름의 디렉토리를 생성한다
이 폴더는 파일을 탑재하면 해당 파일이 저장될 공간으로 설정될 것이다.
이후 서비스 폴더에 boardService로 이동, 글 작성시 파일을 받아오는 메서드를 만들어줘야한다.
write 메서드에서 몇 줄을 더 추가해줘야 하는데, 코드는 아래와 같다.
public void write(Board board, MultipartFile file) throws Exception{ // 오류처리 throws Exception
String projectPath = System.getProperty("user.dir") + "\\src\\main\\resources\\static\\files"; // 저장경로 지정
UUID uuid = UUID.randomUUID(); // 파일 이름에 붙일 랜덤이름 생성
String filename = uuid + "_" + file.getOriginalFilename(); // 랜덤이름을 파일네임 앞에 붙인 후 _ 그리고 원래 파일이름으로 파일이름 생성
File saveFile = new File(projectPath, filename); // 파일을 생성해줄건데, projectPath에 담기고, name이름으로 담긴다는 의미
file.transferTo(saveFile); // 예외처리 필요하기에 throws를 이용, 해주기
boardRepository.save(board); // 이렇게 생성한 서비스는 다시 컨트롤러에서 사용할 것
}
각각 주석으로 설명을 두었으니 읽어보길 바라며 오류처리, 예외처리를 controller에서도 해줘야하기에 controller로 이동
위에서 주의할 점 : String projectPath를 설정하는 줄에서, "\\src,,,"부분을(실행에 오류가 난다면)
"/src/main/resources/static/files";
로 바꿔야한다,
이것도 모르고 컨트롤러만 한 3일 잡고 왜 안돼지 하고 삽질하고있었다.. 흑흑,,
아까 수정한 메서드 형식에 맞게 file 변수를 추가하고 예외처리도 해준다.
그리고 아래에 아까 수정할 때도 write 메서드를 이용했었기에 변수를 추가해주고, 예외처리를 해준다.
이상태로 re run해보면,
아래와 같은 에러가 뜬다.
브레이크 포인트와 디버깅기능을 활용해서 대충 어디가 문제인지 유추할 수 있다.
null pointerException 즉, 아무것도 지정되지 않았다는 것이다. 그래서 해당 부분인 Service의 25번 부분을 (1)브레이크 포인트(빨간 원)으로 잡아주고 (2)디버그 버튼을 누르면, (3)file명이 null이라는 것을 볼 수 있다.
그 이유는 write.html에 이름이 지정되지 않았기 때문이다.
그래서 컨트롤러에서 받아오는 파일 변수명인 file과 같게 file이라는 이름으로 지정해준다. 이후 재 디버깅해주면
이상태로 대기하는데 여기서 F9를 누르면 디버깅을 종료한다.
그렇게 종료하게되면 짠!
글 작성이 완료된 것을 볼 수 있다.
그리고 아까 설정한 static/files 폴더에 해당 사진파일이 잘 업로드 되어있는 것을 확인할 수 있다.
하지만 데이터베이스에는 들어가 있지 않은 것을 확인할 수 있는데, 데이터 넣는 처리를 해주어야하기 때문이다.
아래처럼 filename과 filepath 부분을 지정해주자.
그리고 boardview 부분에
<a>다운받기</a>
를 하나 추가해주고 실행해줬다.(저건 실제로 실행되지 않는 a 태그이므로 따라해도, 안해도 상관없다.)
아무 이미지 파일이나 넣고 글을 작성한 후에, workbench로 데이터베이스를 확인해보니,
나머지 칸도 잘 들어가있다.
이제 등록한 이미지를 볼 수 있게 view 부분을 수정해야한다.
위와같이 filepath 부분을 지정하는 a태그 하나를 만들어주고, 실행해보자.
다운로드 버튼을 누르면,
이렇게 이미지가 있는 경로로 가서 이미지를 보여준다. 오른쪽 클릭으로 다운로드 할 수 있지만 한번 클릭으로 자동 다운로드가 되게 할 수 있을 것이다. 그 부분은 완성된 이후에 보강하는 부분에서 계속 설명하도록 하겠다.
다음 부분인
7) 게시물 페이징
- 게시물 페이징 처리
- 게시물 리스트 페이지에서 페이징 처리
부분은 다음 글에서 계속 설명하겠다.