https://rogi221.tistory.com/151
스프링 - Part 3 - 기본적인 웹 게시물 관리 05 (화면처리-01)
화면처리 목록 페이지 작업과 includes 스프링 MVC의 JSP를 처리하는 설정은 servlet-context.xml에 아래와 같이 작성되어 있다. servlet-context.xml 의 일부 스프링 MVC의 설정에서 화면 설정은 ViewResolver라는
rogi221.tistory.com
화면처리
모달(Modal)창 보여주기
최근에는 브라우저에서 경고창(alert)을 띄우는 방식보다 모달창(Modal)을 보여주는 방식을 많이 사용한다.
BootStrap은 모달창을 간단하게 사용할 수 있으므로 목록 화면에서 필요한 메세지를 보여주는 방법을 사용해본다.
list.jsp
// list.jsp
... 생략 ...
</table>
<!-- Modal 추가 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">×</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>
<!-- end panel-body -->
</div>
<!-- end panel -->
</div>
</div>
</div>
<!-- /.row -->
<%@include file="../includes/footer.jsp" %>
모달창을 보여주는 작업 jQuery를 이용해서 처리할 수 있다.
// list.jsp
... 생략 ...
<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>
<%@include file="../includes/footer.jsp" %>
새로운 게시물을 작성하고 나면 자동으로 '/board/list로 이동하면서 모달창이 보이게 된다.
목록에서 버튼으로 이동하기
게시물의 작성과 목록 페이지로 이동이 정상적으로 동작했다면, 마지막으로 목록 페이지 상단에 버튼을 추가해서 등록 작업을 시작할 수 있게 처리하는 것이다.
// list.jsp
... 생략 ...
$("#myModal").modal("show");
}
$("#regBtn").on("click", function() { << 추가
self.location ="/board/register";
});
화면에서 Register New Board 버튼을 클릭하면 게시물의 등록 페이지로 이동할 수 있다.
조회 페이지와 이동
게시물의 등록과 리스트 처리가 끝났다면 가장 중요한 틀은 완성되었다고 볼 수 있다. 다음으로 목록 페이지에서 링크를 통해서 GET 방식으로 특정한 번호의 게시물을 조회할 수 있는 기능을 작성한다.
조회 페이지 작성
조회 페이지는 입력 페이지와 거의 유사하지만 게시물 번호(bno)가 출력된다는 점과 모든 데이터가 읽기 전용으로 처리된다는 점이 가장 큰 차이이다.
게시물의 조회는 BoardController 에서 get() 메서드로 구성되어 있다,
get.jsp
// get.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 Read</h1>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">Board Read Page</div>
<!-- /.panel-heading -->
<div class="panel-body">
<div class="form-group">
<label>Bno</label> <input class="form-control" name='bno'
value='<c:out value="${board.bno}"/>' readonly="readonly">
</div>
<div class="form-group">
<label>Title</label> <input class="form-control" name='title'
value='<c:out value="${board.title }"/>' readonly="readonly">
</div>
<div class="form-group">
<label>Text area</label>
<textarea class="form-control" rows="3" name='content'
readonly="readonly"><c:out value="${board.content}" /></textarea>
</div>
<div class="form-group">
<label>Writer</label> <input class="form-control" name='writer'
value='<c:out value="${board.writer }"/>'readonly="readonly">
</div>
<button data-oper='modify' class="btn btn-default">Modify</button>
<button data-oper='list' class="btn btn-info">List</button>
</div>
<!-- end panel-body -->
</div>
<!-- end panel-body -->
</div>
<!-- end panel -->
</div>
<!-- /.row -->
<%@ include file="../includes/footer.jsp"%>
브라우저에서는 /board/get?bno=1 과 같이 게시물의 번호를 반드시 파라미터로 전달해야한다.
파라미터로 전달하는 bno 값이 존재한다면 아래와 같은 페이지를 보게 된다.
화면 하단의 버튼은 /board/list 와 /board/modify?bno=xx 와 같이 이동하는 링크를 추가한다.
// get.jsp
... 생략 ...
<button data-oper='modify' class="btn btn-default"
onclick="location.href='/board/modify?bno=<c:out value="${board.bno}"/>'">Modify</button>
<button data-oper='list' class="btn btn-info"
onclick="location.href='/board/list'">List</button>
버튼 수정
목록 페이지와 뒤로가기 문제
목록에서 조회 페이지로의 이동
list.jsp 페이지 수정
// list.jsp
... 생략 ...
<tr>
<td><c:out value="${board.bno}" /></td>
<td><a href='/board/get?bno=<c:out value="${board.bno}"/>'>
<c:out value="${board.title}"/></a></td> << 수정 및 추가
<td><c:out value="${board.writer }" /></td>
<td><fmt:formatDate pattern="yyyy-MM-dd" value="${board.regdate }" /></td>
<td><fmt:formatDate pattern="yyyy-MM-dd" value="${board.updateDate }" /></td>
</tr>
... 생략 ...
새창으로 열고싶다면
list.jsp 부분에 <td><a href='/board/get?bno=<c:out value="${board.bno}"/>' target='_blank'><c:out value="${board.title}"/></a></td> 입력 하면된다.
뒤로 가기의 문제
동일한 페이지 내에서 목록 페이지와 조회 페이지의 이동은 정상적으로 처리된 것 같아 보이지만 한 가지 문제가 남아 있습니다. '등록 -> 목록 -> 조회' 까지는 순조롭지만 브라우저의 뒤로가기를 선택하는 순간 다시 게시물의 등록 결과를 확인하는 방식으로 동작한다는 것이다.
이러한 문제가 생기는 원인은 브라우저에서 뒤로가기나 앞으로 가기를 하면 서버를 다시 호출하는게 아니라 과거에 자신이 가진 모든데이터를 활용하기 때문이다. 브라우저에서 조회 페이지와 목록 페이지를 여러번 앞으로 혹은 뒤로 이동해도 서버에서는 처음에 호출을 제외하고 별 다른 변화가 없는 것을 확인할 수 있다.
문제를 해결하려면 window의 history 객체를 이용해서 현재 페이지는 모달창을 띄울 필요가 없다고 표시를 해 두는 방식을 이용해야한다.
window.history 객체를 조작하는 것은 이론으로 복잡해 보이지만 코드는 약간의 변화만 있다.
// list.jsp
... 생략 ...
<script type="text/javascript">
$(document).ready(function(){
var result = '<c:out value="${result}"/>';
checkModal(result);
history.replaceState({},null,null); << 추가
function checkModal(result) {
if (result === '' || history.state) { << 수정
return;
}
if (parseInt(result) > 0) {
$(".modal-body").html("게시글 " + parseInt(result) + " 번이 등록되었습니다.");
}
$("#myModal").modal("show");
}
$("#regBtn").on("click", function() {
self.location ="/board/register";
});
});
</script>
정상적으로 모달창이 보이지 않음
게시물의 수정/삭제 처리
수정/삭제 페이지로 이동
BoardController 에서 수정/삭제가 가능한 화면으로 이동하는 것은 조회 페이지와 같습니다. 기존의 get() 메서드를 조금 수정해서 화면 구성한다.
// BoardController.java
// 수정
@GetMapping({"/get", "/modify"})
public void get(@RequestParam("bno") Long bno, Model model) {
log.info("/get or modify");
model.addAttribute("board", service.get(bno));
}
@GetMapping이나 @PostMapping 등에는 URL을 배열로 처리할 수 있으므로, 위와 같이 하나의 메서드로 여러 URL을 처리할 수 있다.
브라우저에서는 /board/modify?bno=30과 같은 방식으로 처리하므로, view 폴더 내 modify.jsp를 작성한다.
modify.jsp 는 get.jsp와 같지만 수정이 가능한 제목이나 내용등이 readonly 속성이 없도록 작성한다
POST 방식으로 처리하는 부분을 위해서는 <form> 태그로 내용들을 감싸게 한다.
modify.jsp
// modify.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 Read</h1>
</div>
<!-- /.col-lg-12 -->
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">Board Read Page</div>
<!-- /.panel-heading -->
<div class="panel-body">
<form role="form" action="/board/modify" method="post">
<div class="form-group">
<label>Bno</label> <input class="form-control" name='bno'
value='<c:out value="${board.bno}"/>' readonly="readonly">
</div>
<div class="form-group">
<label>Title</label> <input class="form-control" name='title'
value='<c:out value="${board.title }"/>'>
</div>
<div class="form-group">
<label>Text area</label>
<textarea class="form-control" rows="3" name='content'>
<c:out value="${board.content}" /></textarea>
</div>
<div class="form-group">
<label>Writer</label> <input class="form-control" name='writer'
value='<c:out value="${board.writer }"/>'readonly="readonly">
</div>
<div class="form-group">
<label>RegDate</label>
<input class="form-control" name='regDate' value='<fmt:formatDate pattern = "yyyy/MM/dd" value="${board.regDate}" />' readonly="readonly">
</div>
<div class="form-group">
<label>Update Date</label>
<input class="form-control" name='updateDate' value='<fmt:formatDate pattern = "yyyy/MM/dd" value="${board.updateDate}"/>' readonly="readonly">
</div>
<button type="submit" data-oper='modify' class="btn btn-default">Modify</button>
<button type="submit" data-oper='remove' class="btn btn-danger">Remove</button>
<button type="submit" data-oper='list' class="btn btn-info">List</button>
</form>
</div>
<!-- end panel-body -->
</div>
<!-- end panel-body -->
</div>
<!-- end panel -->
</div>
<!-- /.row -->
<%@ include file="../includes/footer.jsp"%>
JavaScript에서는 위의 버튼에 따라서 다른 동작을 할 수 있도록 수정해야한다.
modify.jsp
// modify.jsp
... 생략 ...
<script type="text/javascript">
$(document).ready(function(){
var formObj = $("form");
$('button').on("click", function(e){
e.preventDefault();
var operation = $(this).data("oper");
console.log(operation);
if(operation === 'remove') {
formObj.attr("action", "/board/remove");
} else if (operation === 'list'){
// move to list
self.location= "/board/list";
return;
}
formObj.submit();
});
});
</script>
<%@ include file="../includes/footer.jsp"%>
JavaScript 에서는 <button> 태그의 'data-oper' 속성을 이용해서 원하는 기능을 동작하도록 처리한다.
<form> 태그의 모든 버튼은 기본적으로 submit으로 처리하기 때문에 e.preventDefault() 로 기본 동작을 막고 마지막에 직접 submit()을 수행한다.
게시물 수정/삭제 확인
화면에서 게시물을 수정한 후에 'modify' 버튼을 통해서 BoardController 에 수정을 요청한다.
조회 페이지에서 <form> 처리
부분 수정
// get.jsp
<button data-oper='modify' class="btn btn-default">Modify</button>
<button data-oper='list' class="btn btn-info">List</button>
<form id='operForm' action="/board/modify" method="get">
<input type='hidden' id='bno' name='bno' value='<c:out value="${board.bno}"/>'>
</form>
브라우저에서는 <form> 태그의 내용은 보이지 않고 버튼만 보이게 된다.
사용자가 버튼을 클릭하면 operForm이라는 id를 가진 <form> 태그를 전송해야하므로 추가적인 JavaScript 처리가 필요하다.
get.jsp
// get.jsp
... 생략 ...
<script type="text/javascript">
$(document).ready(function(){
var operForm = $("#operForm");
$("button[data-oper='modify']").on("click", function(e) {
operForm.attr("action", "/board/modify").submit();
});
$("button[data-oper='list']").on("click", function(e){
operForm.find("#bno").remove();
operForm.attr("action", "/board/list")
operForm.submit();
});
});
</script>
<%@ include file="../includes/footer.jsp"%>
수정 페이지에서 링크 처리
수정 페이지에서는 사용자가 다시 목록 페이지로 이동할 수 있도록 하기 위해서 JavaScript의 내용을 조금 수정한다.
// modify.jsp 스크립트 부분 수정
... 생략 ...
<script type="text/javascript">
$(document).ready(function(){
var formObj = $("form");
$('button').on("click", function(e){
e.preventDefault();
var operation = $(this).data("oper");
console.log(operation);
if(operation === 'remove') {
formObj.attr("action", "/board/remove");
} else if (operation === 'list'){
// move to list
formObj.attr("action", "/board/list").attr("method", "get");
formObj.empty();
}
formObj.submit();
});
});
</script>
수정된 내용은 클릭한 버튼이 List인 경우 action 속성과 method 속성을 변경한다.
/board/list로의 이동은 아무런 파라미터가 없기 때문에 <form> 태그의 모든 내용은 삭제한 상태에서 submit() 을 진행 한다. 이후에 코드는 실행되지 않도록 return을 통해서 제어한다.
'Spring' 카테고리의 다른 글
스프링 - Part 3 - 기본적인 웹 게시물 관리 07 (MyBatis와 스프링에서 페이징 처리) (0) | 2023.03.27 |
---|---|
스프링 - Part 3 - 기본적인 웹 게시물 관리 06 (오라클 데이터베이스 페이징 처리) (0) | 2023.03.27 |
스프링 - Part 3 - 기본적인 웹 게시물 관리 05 (화면처리-01) (0) | 2023.03.23 |
list.jsp (0) | 2023.03.23 |
스프링 - Part 3 - 기본적인 웹 게시물 관리 04 (프레젠테이션(웹) 계층의 CRUD 구현) (0) | 2023.03.22 |