일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- CSS
- 자바 기초
- 스프링 Ioc
- 스프링
- 오라클통계
- 스프링 에러
- 스프링 제어역전
- 스프링 Ioc Container
- 오라클주별데이터
- 자바
- 스프링 구글차트
- 오라클
- 스프링 구글차트로 기간별 현황 조회하기
- 오라클일별데이터
- 스프링 부트가 해결하려고 했던 문제
- 자바 왕기초
- 제이쿼리
- 스프링과 스프링부트 차이점
- 자바왕초보
- java
- HTML
- 자바기초
- Spring Boot가 해결하려고 했던 문제
- 오라클클라우드에 젠킨스 설치하기
- maven
- 세션
- 오라클월별데이터
- jsp
- 자바왕기초
- 썸머노트
- Today
- Total
Just Do it
Part 3) 기본적인 웹 게시물 관리 (Ch 11) 본문
Part 3) 기본적인 웹 게시물 관리 (Ch 11)
Seojoo21 2022. 2. 17. 19:20* 이 카테고리의 글은 <코드로 배우는 스프링 웹 프로젝트> 에서 각 파트별로 진행하는 프로젝트의 흐름을 보기 위해 각 장의 내용을 간단히 요약한 것이다.
* 출처: 코드로 배우는 스프링 웹 프로젝트 개정판, 구멍가게 코딩단, 남가람북스
Ch11. 화면 처리
- 화면에는 JSP, JavaScript(jQuery), CSS, HTML을 이용해서 작성한다.
- 화면을 개발하기 전에는 반드시 화면의 전체 레이아웃이나 디자인이 반영된 상태에서 개발하는 것을 추천한다.
- Bootstrap : 무료 디자인 이용 가능
Free Bootstrap Themes, Templates, Snippets, and Guides - Start Bootstrap
Landing Page A clean, functional landing page theme
startbootstrap.com
11.1) 목록 페이지 작업과 includes
- 게시물 리스트의 URL은 '/board/list'이므로 src/main/webapp/WEB-INF/views에 board 폴더를 만들고 그 안에 list.jsp 파일을 추가한다.
- 톰캣 경로는 편리하게 '/'로 조정한다.
11.1.1) SB Admin2 페이지 적용하기
- Bootstrap에서 다운받은 무료 템플릿 파일의 tables.html의 내용을 list.jsp의 내용으로 그대로 복사해서 수정하고 실행한다.
- 브라우저에서는 CSS 등이 완전히 깨진 상태이므로 텍스트만 출력되는 것을 볼 수 있다.
- CSS와 JS파일들의 경로를 수정하는 작업은 브라우저의 개발자 도구를 통해서 확인하며 진행한다. 개발자 도구를 통해서 현재 브라우저의 Network 부분을 확인하고, 페이지를 '새로고침'하면 잘못된 URL의 정보를 확인할 수 있다.
- SB Admin2의 CSS의 경로는 현재 프로젝트에서는 제대로 서비스 될 수 없다.
- SB Admin2의 압축을 풀어둔 모든 폴더를 프로젝트 내 src/main/webapp/resources 폴더로 복사해 넣는다.
- 파일들을 resources 경로로 넣어도 아직은 페이지에서 경로를 수정하지 않았기 때문에 문제가 생기는 것은 동일하다. list.jsp 파일에서 CSS와 JS 파일의 경로를 '/resources'로 시작하도록 수정한다.
11.1.2) includes 적용
- JSP를 작성할 때마다 많은 양의 HTML 코드를 이용하는 것을 피하기 위해 JSP의 include 지시자를 활용해서 페이지 제작 시에 필요한 내용만을 작성할 수 있게 사전에 작업을 해야한다.
- 프로젝트 views 폴더에 includes 폴더를 작성하고, header.jsp와 footer.jsp를 선언한다.
<header.jsp 적용>
- header.jsp는 페이지에서 핵심적인 부분이 아닌 영역 중에서 위쪽의 HTML 내용을 처리하기 위해서 작성한다.
- 브라우저에서 '검사' 기능을 활용하면 특정안 <div>가 어떤 부분을 의미하는지 확인할 수 있다.
- 게시판이 들어갈 핵심적인 페이지의 내용 부분 위까지를 잘라서 header.jsp의 내용으로 처리한다.
- header.jsp로 처리하는 부분을 list.jsp 파일 내에 아래 코드로 처리하여 다시 브라우저에서 화면이 깨지지 않는지 확인한다.
<%@include file="../includes/header.jsp" %>
<footer.jsp 적용>
- header.jsp 적용 처리를 했던 것과 마찬가지로 게시판이 들어갈 핵심적인 페이지의 내용의 아래 부분을 잘라서 footer.jsp의 내용으로 처리한다.
- footer.jsp로 처리하는 부분을 list.jsp 파일 내에 아래 코드로 처리하여 다시 브라우저에서 화면이 깨지지 않는지 확인한다.
<%@include file="../includes/footer.jsp" %>
11.1.3) jQuery 라이브러리 변경
- JSP 페이지를 작성하다보면 JavaScript로 브라우저 내에서의 조작이 필요한 경우가 많다. 예제는 jQuery를 이용할 것인데 이때 jQuery를 header.jsp에 선언해두면 작성하는 JSP에서 자유롭게 사용할 수 있다.
- jQuery 최신 버전 사용할 수 있는 태그: (이 태그를 header.jsp의 마지막 부분에 입력해준다.)
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
- 해당 프로젝트에서 사용하는 jQuery 태그: (위의 최신 버전 사용 태그는 모달창이 출력되지 않는 에러가 발생한다.)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
11.2) 목록 화면 처리
- list.jsp에 JSTL의 출력과 포맷을 적용할 수 있는 태그 라이브러리를 추가한다.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- Oracle SQL Developer에서 만들었던 테이블의 칼럼을 떠올리며 <table class=> 태그를 이용해 게시판 틀을 만든다.
11.2.1) Model에 담긴 데이터 출력
- '/board/list'를 실행했을 때 이미 BoardController는 Model을 이용해서 게시물의 목록을 'list'라는 이름으로 담아서 전달했으므로 list.jsp에서는 이를 출력한다.
- 출력은 JSTL을 이용해서 처리한다. (<c:forEach> 태그 사용)
- list.jsp 내 <tbody> 태그와 각 <tr>을 작성한다.
...
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-table me-1"></i>
Board List Page
</div>
<div class="card-body">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>#번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
<th>수정일</th>
</tr>
</thead>
<c:forEach items="${list}" var="board">
<tr>
<td><c:out value="${board.bno }"/></td>
<td><c:out value="${board.title }"/></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>
</c:forEach>
</table>
</div>
</div>
11.3) 등록 입력 페이지와 등록 처리
- 게시물의 등록 작업은 POST 방식으로 처리하지만, 화면에서 입력을 받아야 하므로 GET 방식으로 입력 페이지를 볼 수 있도록 BoardController에 메서드를 추가한다.
- GET방식으로 연결한 register()는 입력 페이지를 보여주는 역할만을 하기 때문에 별도의 처리가 필요하지 않다.
- views 폴더에는 includes를 적용한 입력 페이지 register.jsp 를 작성한다.
- register.jsp 페이지에서는 <form> 태그를 이용해서 필요한 데이터를 전송한다.
- <input>이나 <textarea> 태그의 name 속성은 BoardVO 클래스의 변수와 일치시켜준다.
- 브라우저를 통해 '/board/register' 화면이 제대로 출력되는지 확인한다.
11.3.1) 한글 문제와 UTF-8 필터 처리
- web.xml에 한글 변환 필터를 추가해준다. (아래 포스팅 참고)
https://seojoo21.tistory.com/46?category=995432
스프링 웹 출력시 한글 깨짐 방지를 위해 web.xml 파일에 입력하면 되는 <filter> 태그
** src/main/webapp/WEB-INF에 위치한 web.xml 파일에 아래 코드를 추가하여 저장해준다. encodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 forceEncoding true encodingFi..
seojoo21.tistory.com
11.3.2) 재전송(redirect) 처리
- BoardController에서 register() 메서드(등록 작업을 위한 POST 방식)는 return "redirect:/board/list"; 를 전송하는데 브라우저는 이를 통보받은 후 '/board/list'로 이동하게 된다.
- 만일 이와 같은 재전송을 하지 않는다면 사용자는 브라우저의 '새로고침'을 통해서 동일한 내용을 계속 서버에 등록할 수 있기 때문에 흔히 도배라고 표현하는 문제가 발생하게 된다.
- 따라서 등록, 수정, 삭제 작업은 처리가 완료된 후 다시 동일한 내용을 전송할 수 없도록 아예 브라우저의 URL을 이동하는 방식을 이용한다.
- 이러한 과정에서 하나 더 신경 써야 하는 것은 브라우저에 등록, 수정, 삭제의 결과를 바로 알 수 있게 피드백을 줘야 한다는 것이다.
- 이러한 피드백 작업은 경고창이나 <div>를 이용하는 모달창을 이용해서 처리한다.
- BoardController에서 redirect 처리를 할 때 RedirectAttributes라는 특별한 타입의 객체를 이용했다.
- addFlashAttribute()의 경우 이러한 피드백 작업 처리에 적합한데, 그 이유는 일회성으로만 데이터를 전달하기 때문이다.
- list.jsp 페이지의 아래쪽에 <script> 태그를 이용해서 상황에 따른 메세지를 확인할 수 있다.
<script type="text/javascript">
$(document).ready(function(){
var result = '<c:out value="${result}"/>';
});
</script>
11.3.3) 모달(Modal)창 보여주기
- BootStrap은 모달창을 간단하게 사용할 수 있으므로 목록 화면에서 필요한 메세지를 보여주는 방법을 사용해보자
- 모달창은 기본적으로 <div>를 화면에 특정 위치에 보여주고, 배경이 되는 <div>에 배경색을 입혀서 처리한다. 모달창은 활성화된 <div>를 선택하지 않고는 다시 원래의 화면을 볼 수 없도록 막기 때문에 메세지를 보여주는데 효과적인 방식이다.
- 모달창을 처리하기 위해서는 우선 <div>를 이용해서 페이지의 코드에 추가해야한다.
- list.jsp 내에 <table>태그의 아래쪽에 모달창의 <div>를 추가한다.
* 코드는 깃헙에 올려놨으니 깃헙 내 list.jsp 를 확인할 것.
11.3.4) 목록에서 버튼으로 이동하기
- 게시물의 작성과 목록 페이지로 이동이 정상적으로 동작했다면, 마지막으로 목록 페이지 상단에 버튼을 추가해서 등록 작업을 시작할 수 있게 처리해야 한다.
- list.jsp의 HTML 구조에 버튼을 만들어주는 태그를 넣어주고, 하단의 jQuery를 이용하는 부분에서 해당 버튼을 클릭했을 때의 동작을 정의한다.
11.4) 조회 페이지와 이동
- 게시물의 등록과 리스트 처리가 끝났다면 가장 중요한 틀은 완성되었다고 볼 수 있다.
- 다음으로는 목록 페이지에서 링크를 통해 GET 방식으로 특정한 번호의 게시물을 조회할 수 있는 기능을 작성한다.
11.4.1) 조회 페이지 작성
- 조회 페이지는 입력 페이지와 거의 유사하지만 게시물 번호(bno)가 출력된다는 점과 모든 데이터가 읽기 전용으로 처리된다는 점이 가장 큰 차이이다.
- views/board 폴더 내 get.jsp를 register.jsp를 복사해서 작성한다.
- get.jsp는 게시물 번호를 보여줄 수 있는 필드를 추가하고, 모든 데이터는 readonly를 지정해서 작성한다.
- register.jsp에 있던 <form> 태그는 조회 페이지에서 필요하지 않으므로 제거하는 대신 마지막에는 수정/삭제 페이지로 이동하거나 원래의 목록 페이지로 이동할 수 있는 버튼을 추가한다.
- 브라우저에는 'board/get?bno=1'과 같이 게시물의 번호를 반드시 파라미터로 전달해서 테스트 해본다.
- 테스트 후 화면 하단의 버튼에 '/board/list'와 '/board/modify?bno=xx'와 같이 이동하는 링크를 추가한다.
11.4.2) 목록 페이지와 뒤로 가기 문제
- 목록 페이지에서 각 게시물 제목에 <a> 태그를 적용해서 조회 페이지로 이동하게 처리한다.
- 최근 웹페이지들은 사용자들의 트래픽을 고려해 목록 페이지에서 새창을 띄워 조회 페이지로 이동하는 방식을 선호하지만, 전통적인 방식에서는 현재창 내에서 이동하는 방식을 사용한다.
- '뒤로 가기'의 해결은 조금 어려운 내용들이 나올 수 있으므로 학습에 어려움이 있다면 건너뛰는 선택도 나쁘지 않다.
(하지만 나는 해볼거다! 파이팅)
<목록에서 조회 페이지로의 이동>
- 제목을 클릭하면 조회 페이지로 넘어갈 수 있도록 list.jsp 페이지의 제목(title) 코드에 <a href=""> 링크 코드를 추가해서 list.jsp 페이지를 조금 수정한다.
- 그럼 브라우저를 통해 화면을 확인해보면 각 게시물의 제목에 링크가 걸리는 것을 확인할 수 있고, 제목을 클릭하면 정상적으로 조회 페이지로 이동하는 것을 볼수 있다.
- 조회 페이지로의 이동은 JavaScript를 이용할 수도 있고, 위와 같이 직접 <a> 태그를 이용해서도 처리가 가능하다.
- 만일 조회 페이지를 이동하는 방식이 아니라 '새창'을 통해 보고 싶다면 <a> 태그의 속성으로 target='_blank'를 지정하면 된다.
*<a> 태그와 <form> 태그에는 target 속성을 지정할 수 있는데 '_blank'는 새로운 창에서 처리 된다.
<뒤로 가기의 문제> * 특히나 이 부분은 나중에 다시 꼭 교재를 읽어봐야한다.
- 게시물 '등록-> 목록 -> 조회' 까지는 순조롭지만 브라우저의 '뒤로 가기'를 선택하는 순간, 다시 게시물의 등록 결과를 확인하는 모달창이 나오는 문제가 있다.
- 이러한 문제가 생기는 원인은 브라우저에서 '뒤로 가기'나 '앞으로 가기'를 하면 서버를 다시 호출 하는 것이 아니라 과거에 자신이 가진 모든 데이터를 활용하기 때문이다.
- 브라우저에서 조회 페이지와 목록 페이지를 여러 번 앞으로 혹은 뒤로 이동해도 서버에서는 처음에 호출을 제외하고 별다른 변화가 없는 것을 확인할 수 있다.
- 이 문제를 해결하려면 window의 history 객체를 이용해서 현재 페이지는 모달창을 띄울 필요가 없다고 표시를 해 두는 방식을 이용해야 한다.
- window의 history 객체는 스택 구조로 동작한다. (교재 256쪽 참고하기)
- window.history 객체를 이용하여 list.jsp 하단에 있는 모달창의 JavaScript를 수정한다.
* 코드는 깃헙에 올려놨으니 깃헙 내 list.jsp 를 확인할 것.
- 모달창이 보이는 여부와 관계없이 JavaScript의 모든 처리가 끝나게 되면 history에 쌓이는 상태는 모달창을 보여줄 필요가 없는 상태가 된다.
11.5) 게시물의 수정/삭제 처리
- 게시물의 수정 작업은 일반적으로 다음과 같다.
1) 조회 페이지에서 직접 처리하는 방식
2) 별도의 수정/삭제 페이지를 만들어서 해당 페이지에서 수정과 삭제를 처리하는 방식
- 최근에는 게시물의 조회 페이지에서 댓글 등에 대한 처리가 많아지면서 수정과 삭제는 별개의 페이지에서 하는 것이 일반적이다.
- 조회 페이지에서는 GET 방식으로 처리되는 URL을 통해서 수정/삭제 버튼이 존재하는 화면을 볼 수 있게 제작해야한다.
- 수정 혹은 삭제 작업은 POST 방식으로 처리되고, 결과는 다시 목록 화면에서 확인할 수 있는 형태로 제작한다.
11.5.1) 수정/삭제 페이지로 이동
- BoardController에서 수정/삭제가 가능한 화면으로 이동하는 것은 조회 페이지와 같다.
- BoardController에 기존의 get() 메서드를 조금 수정하여 화면을 구성한다.
- 브라우저에서는 '/board/modify?bno=30'과 같은 방식으로 처리하므로, views 폴더 내에 modify.jsp를 작성한다.
- modify.jsp는 get.jsp와 같지만 수정이 가능한 제목이나 내용등이 readonly 속성이 없도록 작성한다.
- POST방식으로 처리하기 위해 <form> 태그로 내용들을 감싸게 한다.
- 등록일과 수정일이 나중에 BoardVO로 수집되어야 하므로 날짜 포맷을 'yyyy/MM/dd'로 하여 추가한다. (날짜 포맷 일치 해야함)
- 수정,삭제,목록으로 돌아가기 버튼을 추가한다.
- 브라우저에서 'http://localhost:8080/board/modify?bno=19'와 같이 게시물 번호를 이용해서 수정 페이지가 정상적으로 출력되는지 확인한다.
- JavaScript에서는 위의 버튼에 따라서 다른 동작을 할 수 있도록 수정해야 한다.
* 코드는 깃헙에 올려놨으니 깃헙 내 modify.jsp 를 확인할 것.
11.5.2) 게시물 수정/삭제 확인
- 브라우저에서 잘 작동하는지 확인한다.
11.5.3) 조회 페이지에서 <form> 처리
- 게시물의 조회 페이지에서는 수정과 삭제가 필요한 페이지로 링크를 처리해야한다. 앞에서 list.jsp의 경우 직접 제목 버튼에 링크를 처리하는 방식을 사용하여 처리했지만, 나중에 다양한 상황을 처리하기 위해 get.jsp 에서 <form> 태그를 이용해서 수정해보자.
- 사용자가 버튼을 클릭하면 operForm이라는 id를 가진 <form> 태그를 전송해야 하므로 get.jsp 페이지 하단에 추가적인 JavaScript 처리가 필요하다.
11.5.4) 수정 페이지에서 링크 처리
- modify.jsp 페이지에서는 사용자가 다시 목록 페이지로 이동할 수 있도록 하기 위해서 JavaScript 내용을 조금 수정한다.
- 수정된 내용: 클릭한 버튼이 List인 경우 action 속성과 method 속성을 변경한다.
수정 전:
<!-- 수정, 삭제, 목록으로 돌아가기 버튼별 동작을 자바스크립트로 설정 -->
<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') {
self.location ="/board/list";
return;
}
formObj.submit();
});
});
</script>
수정 후:
<!-- 수정, 삭제, 목록으로 돌아가기 버튼별 동작을 자바스크립트로 설정 -->
<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') {
formObj.attr("action", "/board/list").attr("method","get");
formObj.empty(); // 'board/list'로의 이동은 아무런 파라미터가 없기 때문에 <form>태그의 모든 내용은 삭제한 상태에서 submit()을 진행한다.
}
formObj.submit();
});
});
</script>
'신입 개발자가 되기 위해 공부했던 독학 자료들 > 코드로 배우는 스프링 웹프로젝트' 카테고리의 다른 글
Part 3) 기본적인 웹 게시물 관리 (Ch 15) (0) | 2022.02.24 |
---|---|
Part 3) 기본적인 웹 게시물 관리 (Ch 13 & 14) (0) | 2022.02.20 |
Part 3) 기본적인 웹 게시물 관리 (Ch. 12) (0) | 2022.02.18 |
Part 3) 기본적인 웹 게시물 관리 (Ch 9 & 10) (0) | 2022.02.16 |
Part 3) 기본적인 웹 게시물 관리 (Ch7 & 8) (0) | 2022.02.16 |