2022_04_14 - oneso123456789/2022 GitHub Wiki

Other

디버깅

뒤로 가기 문제 처리부분

뒤로가기시 모달창 뜨는 문제를 처리하던중 list.jsp의 script태그 작성중 발생
history.state를 사용해야하는대 history.State를 사용해서 작동이 안됨
그냥 s를 다시 소문자로 변경함
Java Script에 대한 더 자세한 공부가 필요하다고 생각됨 TnT

11.5 게시물 수정/삭제 처리

이 부분에선 2개의 오류가 발생했음

1) modify 버튼 처리

form을 만들때 method를 post가 아닌 get으로 만들어서 게시글의 내용을 변경한후 modify버튼을 클릭해도
내용이 바뀌지 않았음 form의 동작 method를 post로 변경해서 해결함

<form role="form" action="/board/modify" method="get"> -> <form role="form" action="/board/modify" method="post">

form이나 버튼을 동작시킬땐 알맞은 method 사용해야함

2) remove후 list로 redirect 오류

1번을 해결한 후 remove 테스트중 발생한 오류임
remove 로직은 돌아가지만 단순히 redirect 경로가 이상한것이 문제가됨(/WEB-INF/views//redirect:/board/list.jsp)
해결한 방법은 BoardController.class에
PostMapping의 remove()메소드의 리턴값에 /가 포함되어서 /WEB-INF/views//redirect:이런 경로로 설정된게 문제였음

return "/redirect:/board/list"; -> return "redirect:/board/list";

변경후 해결함

두개 모두 그렇게 어려운 문제는 아니었음 버그를 발생시키지 않는게 제일 좋은방법이지만
그럴수없으니 최대한 정확하게 해결하는 능력을 길러야 한다고 생각됨

11.4.2 목록페이지와 뒤로 가기 문제

뒤로가기 문제

동일한 페이지 내에서 목록 페이지와 조회 페이지의 이동은 정상적으로 처리된 것 같아보이지만
한 가지 문제가 남아 있음 등록 -> 목록 -> 조회까지는 순조롭지만 브라우저의 뒤로가기
선택하는 순간 다시 게시물의 등록 결과를 확인하는 모달이 동작한다는것임
문제 표현그림(p256)참고

이러한 문제가 생기는 원인은 브라우저에서 뒤로 가기앞으로 가기를 하면 서버를 다시 호출하는 게 아니라
과거에 자신이 가진 모든 데이터를 활용하기 때문임
브라우저에서 조회 페이지와 목록 페이지를 여러 번 앞으로 혹은 뒤로 이동해도 서버에서는 처음에 호출을 제외하고
별다른 변화가 없는 것을 확인할 수 있음

이 문제를 해결하려면 windows의 history 객체를 이용해서 현재 페이지는 모달창을 띄울 필요가 없다고
표시를 해 두는 방식을 이용해야 함
Windows의 history 객체를 스택 구조로 동작하기 때문에 아래 그림으로 원리를 살펴보겠음
(p256 중간 그림)

그림1은 사용자가 브라우저를 열고 '/board/list'를 최초로 호출한 것임
history에 쌓으면서 현재 페이지는 모달창을 보여줄 필요가 없다고 표시(그림에서 작은상자)

그림2는 사용자가 /board/register를 호출한 경우임
스택의 상단에 /board/register가 쌓임 만일 이 상태에서 뒤로 가기를 실행하면 아래쪽의 /board/list가 보여지는데
이때 심어둔 표시를 이용해서 모달창을 띄울 필요가 없다는 것을 확인 할 수 있음

그림 3은 사용자가 등록을 완료하고 /board/list가 호출되는 상황임
브라우저에서 앞으로 가기뒤로가기로 이동한 것이 아니므로 스택의 상단에 추가됨
등록 직후에 /board/list로 이동한 경우에는 모달창이 동작함

그림 3에서 모달창을 보여준 후에는 스택의 상단에 모달창이 필요하지 않다는 표시를 해 주어야 함
이우에/board/regisger를 호출하면 그림 4와 같이 됨

windows.history 객체를 조작하는 것은 이론으로는 복잡해 보이지만,
사실은 코드는 아래와 같이 약간의 변화만 있을뿐임

list.jsp에서 JavaScript 부분

<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>

기존과 달라진 점은 맨 마지막에 추가된 history.replaceState()부분과 checkModal()에서
history.state를 체크하는 부분임
JavaScript의 처리는 우선 checkModal()을 실행하는데, 만일 등록된 후에 이동한 것이라면
위의 그림 3처럼 되기 때문에 모달창이 보이게 됨

모달창이 보이는 여부와 관계없이 javaScript의 모든 처리가 끝나게 되면 history에 쌓이는 상태는
모달창을 보여줄 필요가 없는 상태가 됨
최종적 결과는 p258그림처럼 처리됨

11.5 게시물의 수정/삭제 처리

게시물의 수정 작업은 일반적으로

  1. 조회 페이지에서 직접 처리하는 방식이나
  2. 별도의 수정/삭제 페이지를 만들어서 해당 페이지에서 수정과 삭제를 처리하는 방식을 많이 사용함
    최근에는 게시물의 조회 페이지에서 댓글 등에 대한 처리가 많아지면서
    수정과 삭제는 별개의 페이지에서 하는 것이 일반적임

조회 페이지에서는 GET 방식으로 처리되는 URL을 통해서 수정/삭제 버튼이 존재하는
화면을 볼 수 있게 제작해야 함
수정 혹은 삭제 작업은 POST방식으로 처리되고, 결과는 다시 목록 화면에서 확인할 수 있는 형태로 제작함

11.5.1 수정/삭제 페이지로 이동

BoardController에서 수정/삭제가 가능한 화면으로 이동하는 것은 조회 페이지와 같음
따라서 기존의 get() 메서드를 조금 수정해서 화면을 구성함

BoardController의 일부

    @GetMapping({"/get", "/modify"})
    public void get(@RequestParam("bno") Long bno, Model model) {

        log.info("BoardController /get or modify");
        model.addAttribute("board", service.get(bno));
    }

@GetMapping이나 @PostMapping 등에는 URL을 배열로 처리할 수 있으므로,
위와 같이 하나의 메서드로 여러 URL을 처리할 수 있음

브라우저에서는 /board/modify?bno=30과 같은 방식으로 처리하므로, views 폴더 내 modify.jsp를 작성함

modify.jsp는 get.jsp와 같지만 수정이 가능한 제목이나 내용등이 readonly 속성이 없도록 작성함
POST 방식으로 처리하는 부분을 위해서는

태그로 내용들을 감싸게 함

views/board/modify.jsp의 일부

<form role="form" action="/board/modify" method="get">

					<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>

<form> 태그는 action 속성을 /board/modify로 지정했지만, 삭제를 하면 /board/remove와 같이
action 속성의 내용을 수정해서 사용하게 됨
게시물의 제목, 내용은 수정이 가능한 형태로 사용해서 사용자가 편집할 수 있게 함
등록일과 수정일은 나중에 BoardVO로 수집되어야 하므로 날짜 포맷을 yyyy/MM/dd의 포맷으로 해야함
(만일 포맷이 맞지 않으면 파라미터 수집 부분에 문제가 생기므로 주의가 필요함)
마지막에는 수정/삭제/목록등의 버튼을 추가함

브라우저에서는 /board/modify?bno=52(존재하는 게시물의 번호)와 같이
게시물 번호를 이용해서 수정 페이지가 정상적으로 출력되는지 확인

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 list
				self.location = "/board/list";
				return;
			}
			formObj.submit();

		});
	});
</script>

JavaScript에서는 <button>태그의 data-oper 속성을 이용해서 원하는 기능을 동작하도록 처리함
<form> 태그의 모든 버튼은 기본적으로 submit으로 처리하기 때문에 e.preventDefault()로
기본동작을 막고 마지막에 직접 submit()을 수행함
2022_04_14 오전 4시 46분 여기까지함

11.5.2 게시물 수정/삭제 확인

화면에서 게시물을 수정한 후에 modify버튼을 통해서 BoardController에 수정을 요청함

Modify 버튼을 클릭하면 BoardController에서는 주어진 파라미터들을 BoardVO로 처리하게 되고,
수정된 값이 제대로 수집된 것을 확인할 수 있음 (p263)

게시물이 수정된 후에는 다시 /board/list 화면으로 이동하게 됨
이 경우에 대한 처리는 이미 완료되었으므로 모달창을 통해서 메시지를 확인할 수 있음

화면에서 Remove버튼을 클릭하게 되면 <form>태그의 action 값이 /board/remove가 되고
데이터들이 전송됨
물론 BoardController에서는 bno 값 하나만 필요하지만 처리에는 문제가 없음
삭제 시 BoardController에는 아래와 같은 로그가 기록되게 됨

11.5.3 조회 페이지에서

처리

게시물의 조회 페이지에서는 수정과 삭제가 필요한 페이지로 링크를 처리해야함
직접 버튼에 링크를 처리하는 방식을 사용하여 처리하였지만,
나중에 다양한 상황을 처리하기 위해서 <form> 태그를 이용해서 수정함

views/board/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의 일부

<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>

스크립트 코드는 사용자가 버튼을 누르는 경우에는 bno 값을 같이 전달하고 <form> 태그를 submit시켜서 처리함
만일 사용자가 list로 이동하는 경우에는 아직 아무런 데이터도 필요하지 않으므로
<form>태그 내의 bno 태그를 지우고 submit을 통해서 리스트 페이지로 이동함

11.5.4 수정 페이지에서 링크 처리

수정 페이지에서는 사용자가 다시 목록 페이지로 이동할 수 있도록 하기 위해서
JavaScript 내용을 조금 수정함

views/board/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 list
				formObj.attr("action", "/board/list").attr("method", "get");
				formObj.empty();
			}

			formObj.submit();

		});
	});
</script>

수정된 내용은 클릭한 버튼이 List인경우 action 속성과 method 속성을 변경함

/board/list로의 이동은 아무런 파라미터가 없기 때문에 <form>태그의 모든 내용은 삭제한 상태에서 submit()을 진행함
이후에 코드는 실행되지 않도록 return을 통해서 제어함

이 장에서 진행된 모든 내용을 도식화 시키면 p267에 그림과 같은 구조가 됨

⚠️ **GitHub.com Fallback** ⚠️