Part 11. 화면 처리
11.3 등록 입력 페이지와 등록 처리
- 게시물의 등록 작업은 POST로 처리하지만, 화면에서 입력을 받아야 하므로 GET 방식으로 입력 페이지를 볼 수 있도록 BoardController에 메서드를 추가한다.
< BoardController >
// 게시글 등록 작업
@GetMapping("/register")
public void register() {
}
- register()는 입력 페이지를 보여주는 역할만을 하기 때문에 별도의 처리가 필요하지 않다.
- views 폴더에는 includes를 적용한 입력 페이지를 작성한다.
< views/board/register.jsp >
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@include file="../includes/header.jsp" %>
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Board Register</h1>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">Board Register </div>
<div class="panel-body">
<form role="form" action="/board/register" method="post">
<div class="form-group">
<label>Title</label> <input class="form-control" name='title'>
</div>
<div class="form-group">
<label>Text area</label>
<textarea class="form-control" rows="3" name="content"></textarea>
</div>
<div class="form-group">
<label>Writer</label> <input class="form-control" name='writer'>
</div>
<button type="submit" class="btn btn-default">Submit Button</button>
<button type="reset" class="btn btn-default">Reset Button</button>
</form>
</div>
</div>
</div>
</div>
<%@include file="../includes/footer.jsp" %>
- register.jsp 페이지에서는 < form > 태그를 이용해 필요한 데이터를 전송한다.
- < input > 이나 < textarea > 태그의 name 속성은 BoardVO 클래스의 변수와 일치시켜 준다.
- 브라우저를 통해 '/board/register' 화면이 제대로 출력되는지 확인한다.
- 화면이 정상적으로 보인다면 입력 항목을 넣어 새로운 게시물이 등록되는지 확인한다.
- BoardController의 POST 방식으로 동작하는 register()는 redirect 시키는 방식을 이용하므로, 게시물의 등록 후에는 다시 '/board/list'로 이동하게 된다.
- 게시물을 등록은 정상적으로 이루어지지만 한글이 깨지는 문제가 발생한다.
11.3.1 한글 문제와 UTF-8 필터 처리
- 새로운 게시물을 등록했을 때 만일 한글 입력에 문제가 있다는 것을 발견했다면 1)브라우저에서 한글이 깨져서 전송되는지를 확인하고, 2)문제가 없다면 스프링 MVC 쪽에서 한글을 처리하는 필터를 등록해야 한다.
- 브라우저에서 전송되는 데이터는 개발자 도구를 이용해 확인할 수 있다.
- 개발자 도구에서 'Network' 탭을 열어둔 상태에서 데이터를 보내면 해당 내용을 볼 수 있으므로 이 때 POST 방식으로 제대로 전송되었는지, 한글이 깨진 상태로 전송된 것인지를 확인할 수 있다.
- 위의 화면을 보면 브라우저가 한글을 문제없이 보냈음을 알 수 있는데, 문제는 Controller 혹은 데이터베이스 쪽이라는 것을 알 수 있다.
- BoardController와 BoardServiceImpl을 개발할 때는 이미 Lombok의 로그를 이용해 필요한 기능들을 기록해 두었으므로, 이를 확인해야 한다.
INFO : org.zerock.controller.BoardController - register: BoardVO(bno=null, title=í
ì¤í¸ ê²ì물ì
ëë¤., content=í
ì¤í¸ ê²ì물ì
ëë¤., writer=user00, regdate=null, updateDate=null)
INFO : org.zerock.controller.BoardController - list
- 위의 로그를 살펴보면 BoardController에 전달될 때 이미 한글이 깨진 상태로 처리된 것을 볼 수 있다.
- 이 문제를 해결하기 위해 web.xml에 아래와 같이 필터를 추가한다.
< web.xml - 필터 추가 >
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<servlet-name>appServlet</servlet-name>
</filter-mapping>
Java 설정의 경우
- web.xml을 대신하는 WebConfig 클래스에서는 필터를 getServletFilters()를 재정의 해서 처리할 수 있다.
< org.zerock.config 내의 WebConfig 클래스 >
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter =
new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[] { characterEncodingFilter };
}
- 한글에 대한 처리가 끝난 후 다시 게시물을 작성해 보면 한글에 문제가 없이 입력되는 것을 알 수 있다.
11.3.2 재전송(redirect) 처리
- 등록 과정에서 POST 방식으로 데이터가 처리되는 과정을 그림으로 표현하면 다음과 같다.
- BoardController에서 register() 메서드는 'redirect:/board/list'를 전송하는데 브라우저는 이를 통보받은 후 '/board/list'로 이동하게 된다.
- 만일 위와 같이 재전송을 하지 않는다면 사용자는 브라우저의 '새로고침'을 통해 동일한 내용을 계속 서버에 등록할 수 있기 때문에(흔히 도배라 표현하는) 문제가 발생하게 된다.
- 브라우저에서는 이런 경우 경고창을 보여주기는 하지만 근본적으로 차단하지는 않는다.
- 따라서 등록, 수정, 삭제 작업은 처리가 완료된 후 다시 동일한 내용을 전송할 수 없도록 아예 브라우저의 URL을 이동하는 방식을 이용한다.
- 이러한 과정에서 하나 더 신경 써야 하는 것은 브라우저에 등록, 수정, 삭제의 결과를 바로 알 수 있게 피드백을 줘야 한다는 점이다.
- 경고창이나 < div > 를 이용하는 모달창을 이용해 이런 작업을 처리한다.
- BoardController에서 redirect 처리할 때 ReadirectAttributes라는 특별한 타입의 객체를 이용했다.
- addFlashAttribute()의 경우 이러한 처리에 적합한데, 그 이유는 일회성으로만 데이터를 전달하기 때문이다.
- .addFlashAttribute()로 보관된 데이터는 단 한 번만 사용할 수 있게 보관된다.(내부적으로는 HttpSession을 이용해서 처리한다.)
- list.jsp 페이지의 아래쪽에 < script > 태그를 이용해 상황에 따른 메시지를 확인할 수 있다.
< views/board/list.jsp >
<script type="text/javascript">
$(document).ready(function() {
var result = '<c:out value="${result}"/>';
});
</script>
- 만일 새로운 게시물이 등록된 직후에 위의 코드는 다음과 같이 처리된다. (아래 그림의 번호는 생성된 게시물의 번호다.)
- 새로운 게시물의 번호는 addFlashAttriube()로 저장되었기 때문에 한 번도 사용된 적이 없다면 위와 같이 값을 만들어 내지만 사용자가 '/board/list'를 호출하거나, '새로고침'을 통해 호출하는 경우는 아래와 같이 아무런 내용이 없게 된다.
11.3.3 모달(Modal)창 보여주기
- 최근에는 브라우저에서 경고창(alert)을 띄우는 방식보다 모달창(Modal)을 보여주는 방식을 많이 사용한다.
- BootStrap은 모달창을 간단하게 사용할 수 있으므로 목록 화면에서 필요한 메시지를 보여주는 방법을 사용한다.
- 모달창은 기본적으로 < div >를 화면에 특정 위치에 보여주고, 배경이 되는 < div >에 배경색을 입혀 처리한다.
- 모달창은 활성화된 < div >를 선택하지 않고는 다시 원래의 화면을 볼 수 없도록 막기 때문에 메시지를 보여주는데 효과적인 방식이다.
- 모달창에 대한 코드는 다운로드한 SBAdmin2의 pages 폴더 내 notifications.html 파일을 참고하면 된다.
- 모달창을 처리하기 위해 우선 < div >를 이용해 페이지의 코드에 추가해야 한다.
- list.jsp 내에 < table > 태그의 아래쪽에 모달창의 < div >를 추가한다.
< list.jsp - 모달창 <div> 추가 >
</table>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel" aria-hidden="true">
<div class="moda-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&items;</button>
<h4 class="modal-title" id="myModalLabel">Modal title</h4>
</div>
<div class="modal-body">처리가 완료되었습니다.</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
- 모달창을 보여주는 작업은 jQuery를 이용해 처리할 수 있다.
< list.jsp 내 jQuery 처리 >
<script type="text/javascript">
$(document).ready(function() {
var result = '<c:out value="${result}" />';
checkModal(result);
function checkModal(result) {
if (result === '') {
return;
}
if (parseInt(result) > 0) {
$(".modal-body").html("게시글 " + parseInt(result) + " 번이 등록되었습니다.");
}
$("#myModal").modal("show");
}
});
</script>
- checkModal() 함수는 파라미터에 따라 모달창을 보여주거나 내용을 수정한 뒤 보이도록 작성한다.
- checkModal()에서는 새로운 게시글이 작성되는 경우 RedirectAttributes로 게시물의 번호가 전송되므로 이를 이용해 모달창의 내용을 수정한다.
- $("#modal").mocal('show')를 호출하면 모달창이 보이게 된다.
- '/board/register'를 이용해 새로운 게시물을 작성하고 나면 자동으로 '/board/list'로 이동하면서 모달창이 보이게 된다.
11.3.4 목록에서 버튼으로 이동하기
- 게시물의 작성과 목록 페이지로 이동이 정상적으로 동작했다면, 마지막으로 목록 페이지 상단에 버튼을 추가해 등록 작업을 시작할 수 있게 처리해야 한다.
- 우선 list.jsp의 HTML 구조를 아래와 같이 수정한다.
<div class="panel panel-default">
<div class="panel-heading">
Board List Page
<button id="regBtn" type="button" class="btn btn-xs pull-right">Register New Board</button>
</div>
- list.jsp 하단의 jQuery를 이용하는 부분에서 해당 버튼을 클릭했을 때의 동작을 정의한다.
<script type="text/javascript">
$(document).ready(function() {
var result = '<c:out value="${result}"/>';
checkModal(result);
function checkModal(result) {
if (result === '') {
return;
}
if (parseInt(result) > 0) {
$(".modal-body").html("게시글 " + parseInt(result) + " 번이 등록되었습니다.");
}
$("#myModal").modal("show");
}
$("#regBtn").on("click", function() {
self.location = "/board/register";
})
});
</script>
- 화면에서 'Register New Board' 버튼을 클릭하면 게시물의 등록 페이지로 이동할 수 있다.