관리자 글쓰기

 본 내용은 혼자 공부하기 위하여 다른 포스트를 보면서 저에게 필요한 부분과 궁금했던 부분을 추가하여 게시하는 곳입니다.


궁금한 것에 대한 것은 모르는 것이 많겠지만 함께 알아보도록 노력하겠습니다.


참조 게시 포스트 : http://addio3305.tistory.com/


-------------------------------------------------------------------------------------------------------------------------------------------

1. CSS 및 공통 기능 추가
1.1 CSS 스타일
- src/main/webapp/css 경로에 ui.css라는 css파일을 하단과 같이 작성하자.
@CHARSET "UTF-8";
 
a:link, a:visited {text-decoration: none; color: #656565;}
 
.board_list {width:100%;border-top:2px solid #252525;border-bottom:1px solid #ccc}
.board_list thead th:first-child{background-image:none}
.board_list thead th {border-bottom:1px solid #ccc;padding:12px 0 13px 0;color:#3b3a3a;vertical-align:middle}
.board_list tbody td {border-top:1px solid #ccc;padding:10px 0;text-align:center;vertical-align:middle}
.board_list tbody tr:first-child td {border:none}
.board_list tbody td.title {text-align:left; padding-left:20px}
.board_list tbody td a {display:inline-block}
 
.board_view {width:50%;border-top:2px solid #252525;border-bottom:1px solid #ccc}
.board_view tbody th {text-align:left;background:#f7f7f7;color:#3b3a3a}
.board_view tbody th.list_tit {font-size:13px;color:#000;letter-spacing:0.1px}
.board_view tbody .no_line_b th, .board_view tbody .no_line_b td {border-bottom:none}
.board_view tbody th, .board_view tbody td {padding:15px 0 16px 16px;border-bottom:1px solid #ccc}
.board_view tbody td.view_text {border-top:1px solid #ccc; border-bottom:1px solid #ccc;padding:45px 18px 45px 18px}
.board_view tbody th.th_file {padding:0 0 0 15px; vertical-align:middle}
 
.wdp_90 {width:90%}
.btn {border-radius:3px;padding:5px 11px;color:#fff !important; display:inline-block; background-color:#6b9ab8; border:1px solid #56819d;vertical-align:middle}

포스트에서 그대로 가져온 디자인으로 간단한 디자인이다. 작성자는 디자인의 디자도 몰라서 이렇게 그대로 가져왔다.


1.2 자바스크립트 공통함수

- src/main/webapp/js 경로에 common.js라는 javascript 파일을 하단과 같이 작성하자


function gfn_isNull(str) {
    if (str == null) return true;
    if (str == "NaN") return true;
    if (new String(str).valueOf() == "undefined") return true;   
    var chkStr = new String(str);
    if( chkStr.valueOf() == "undefined" ) return true;
    if (chkStr == null) return true;   
    if (chkStr.toString().length == 0 ) return true;  
    return false;
}
 
function ComSubmit(opt_formId) {
    this.formId = gfn_isNull(opt_formId) == true ? "commonForm" : opt_formId;
    this.url = "";
     
    if(this.formId == "commonForm"){
        $("#commonForm")[0].reset();
    }
     
    this.setUrl = function setUrl(url){
        this.url = url;
    };
     
    this.addParam = function addParam(key, value){
        $("#"+this.formId).append($("<input type='hidden' name='"+key+"' id='"+key+"' value='"+value+"' >"));
    };
     
    this.submit = function submit(){
        var frm = $("#"+this.formId)[0];
        frm.action = this.url;
        frm.method = "post";
        frm.submit();  
    };
}

- 첫번째는 널(null) 체크하는 함수이다. 


- 두번째인 submit 기능을 하는 함수이다. 보통 전송기능인 submit은 form과 <input type="submit"> 을 많이 사용한다. 

그렇지만 이는 파라미터의 동적 추가나 공통적인 파라미터 추가, 아무것도 없을 때의 화면이동이 불편한 경우가 많다. 따라서 숨겨둔 form을 하나 만들어놓고,그 폼을 이용하여 페이지의 이동 및 입력 값 전송을 하려고 한다. 


1.3 공통 포함 파일 작성

위의 CSS파일과 js 파일은 공통으로 jsp파일들에 들어가기 때문에 한 파일에 선언하고 그 파일을 include하여 관리하기 편하게 만들 것이다.

- src/main/webapp/WEB-INF/include 경로에 include-header.jspf, include-body.jspf을 만들고 하단과 같이 작성한다.


include-header.jspf

<%@ page pageEncoding="utf-8"%> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"/> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <link rel="stylesheet" type="text/css" href="<c:url value='/css/ui.css'/>" /> <!-- jQuery --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> <script src="<c:url value='/js/common.js'/>" charset="utf-8"></script>


include-body.jspf

<%@ page pageEncoding="utf-8"%>
<form id="commonForm" name="commonForm"></form>


- header 파일에선 메타정보, 스타일 시트, 태그 라이브러리, 스크립트 등 화면 호출이 완료 되기 전 가져와야 될 것들을 선언하였다.


- body 파일에선 여기서는 위에서 작성한 common.js에 있는 submit 기능을 위한 숨김 폼 하나만 넣어뒀다.



2. 게시글 쓰기 페이지

게시글 리스트 페이지와 동일하게 Controller -> Service -> ServiceImpl -> DAO -> SQL -> jsp 순으로 작성할 것이다.

2.1 Controller

	@RequestMapping(value="/sample/openBoardWrite.do")
	public ModelAndView openBoardWrite(CommandMap commandMap) throws Exception{
		ModelAndView mv = new ModelAndView("/sample/boardWrite");
		
		return mv;			
	}
	
	@RequestMapping(value="/sample/writeBoard.do")
	public ModelAndView writeBoard(CommandMap commandMap) throws Exception{
		ModelAndView mv = new ModelAndView("redirect:/sample/openBoardList.do");
		sampleService.writeBoard(commandMap.getMap());
				
		return mv;
	}
	

SampleController.java에 위 부분을 추가한다.


- 1~6줄

이 메서드는 게시글 쓰기 페이지 자체를 매핑하여 잡아주는 메서드로 크게 특별한 점은 없고 boardWrite라는 jsp 파일로 뷰 페이지로 이동한다.


- 8~14줄

이 메서드는 게시글 쓰기 페이지에서 게시글을 작성한 뒤 등록하기 버튼을 눌렀을 경우의 클라이언트 요청을 매핑하는 메서드로 10줄의 경우는 해당 작업을 완료하고 돌아갈 위치로 게시글 보기 페이지로 돌아간다는 것을 뜻한다.

11줄은 sampleService의 writeBoard 메서드에 CommandMap 안에 있는 Map을 보내주는 데 이 Map 안에는 제목과 내용의 값들이 들어있을 예정이다. 



2.2 Service와 ServiceImpl

SampleService.java

void writeBoard(Map<String,Object> map) throws Exception;


SampleServiceImpl.java

public void writeBoard(Map<String, Object> map) throws Exception { sampleDAO.writeBoard(map); }

Service와 ServiceImpl 부분에 해당 코드들을 추가 시켜준다.


- 이 코드들은 아까 controller 부분에서 호출했던 메서드로 게시글 작성을 완료하고 등록하기 버튼을 눌렀을 때의 처리하는 부분으로 DAO의 메서드를 부르고 마찬가지로 map을 넘겨준다.


2.3 DAO

SampleDAO.java

public void writeBoard(Map<String,Object> map) { insert("sample.writeBoard", map); }

SampleDAO 부분에도 해당 코드들을 추가한다.


- 이 코드도 위와 마찬가지이며 지난번 작성하였던 상속받은 CommonDAO의 메서드인 insert를 활용하여 앞에 "SQL.ID값",파라미터를 sqlSession을 사용하여 SQL문을 DB에 보내준다.


2.4 SQL

sample_SQL.xml

     <insert id="sample.writeBoard" parameterType="hashmap">
     	<![CDATA[
     		INSERT INTO
     			TB_BOARD1(
     				TITLE,
     				CONTENTS,
     				HIT_CNT,
     				DEL_GB,
     				CREA_ID)
     			VALUES(
     				#{TITLE},
     				#{CONTENTS},
     				0,
     				'N',
     				'ADMIN')
       	]]>
     </insert>

 위에서 DB로 보내주는 SQL문으로 파라미터에 포함되어 있던 TITLE, CONTENTS가 #{TITLE}, #{CONTENTS}라고 쓰인 것이 보인다. Mybatis에서는 변수 대입을 #{변수명}으로 사용한다. 여기서 TITLE, CONTENTS는 다음에 살펴볼 jsp 페이지에서 태그에 name에 해당하는 값이다. 즉 어떤 태그에 name="TITLE"이라고 쓰였던 것이다.


2.5 JSP

마지막으로 살펴볼 JSP 페이지이다.

boardWrite.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<title>글쓰기</title>
<%@ include file="/WEB-INF/include/include-header.jspf" %>
</head>
<body>
	<form id="frm">
		<table class="board_view">
			<colgroup>
				<col width="15%" >
				<col width="*" >
			</colgroup>
			<caption>게시글 작성</caption>
			<tbody>
				<tr>
					<th scope="row">제목</th>
					<td><input type="text"  name="TITLE" class="wdp_90" /></td>
				</tr>
				<tr>
					<th scope="row">내용</th>
					<td><textarea cols="100" rows="20" id="CONTENTS" name="CONTENTS" title="내용"></textarea></td>
				</tr>
			</tbody>
		</table>
		
		<a href="#this" id="list" class="btn">목록으로</a>
		<a href="#this" id="write" class="btn">글쓰기</a>
	</form>
	<%@ include file="/WEB-INF/include/include-body.jspf" %>	
	
	<script type="text/javascript">
		$(document).ready(function(){
			$("#list").on("click",function(e){
				e.preventDefault();
				fn_openBoardList();
			})
			$("#write").on("click",function(e){
				e.preventDefault();
				fn_writeBoard();
			})
		});
		
		
		function fn_openBoardList(){
			var comSubmit = new ComSubmit();
			comSubmit.setUrl("<c:url value='/sample/openBoardList.do'/>");
			comSubmit.submit();
		}
		
		function fn_writeBoard(){
			var comSubmit = new ComSubmit("frm");
			comSubmit.setUrl("<c:url value='/sample/writeBoard.do'/>");
			comSubmit.submit();
		}
	</script>
</body>
</html>

- 특별한 것들만 꼽자면 8줄,33줄의 include의 경우 아까 공통적으로 들어가는 부분이여서 따로 작성하여 준 부분이다.


- 21,25줄을 보면 방금 전 말했듯이 태그 안에 name 속성이 TITLE, CONTENTS인 것을 볼 수 있다.   이 부분을 myBatis에서 #{변수명}으로 사용한 것이다. 이 부분이 어떻게 Controller의 파라미터를 통해서 들어갔는 지에 대해서는 밑에서 설명하겠다.


- 48~52줄

var comSubmit = new ComSubmit(); 부분은 자바스크립트 객체를 생성하는 부분이다. 

우리가 자바에서 객체를 생성할 때와 비슷한 방식임을 알 수 있다. 위에서 common.js 에 submit 기능을 하는 함수를 만들었는데, 그것이 ComSubmit 객체이다. 그 다음으로 ComSubmit 객체 내의 setUrl 함수를 이용하여 호출하고 싶은 주소를 입력하도록 하였다. 여기서 <c:url> 태그는 JSTL 태그로, 이 태그를 이용하여 ContextPath를 자동으로 붙이도록 하였다. 만약 JSTL을 이용하지 않는다면, comSubmit.setUrl("/first/sample/openBoardList.do"); 라고 작성하면 된다. 그렇지만 <c:url> 태그를 이용하기를 권장한다. 마지막으로 ComSubmit 객체의 submit 함수를 이용하여 전송(submit)을 하였다. 많은 사람들이 폼(form)을 이용하여 전송을 할때는 다음과 같이 폼을 만든다.

<form id="frm" name="frm" method="post" action="/first/sample/openBoardList.do"></form>

그 후, <input type="submit" value="전송"/>와 같은 태그를 이용하여 전송(submit)을 한다. 그렇지만 이 경우, 폼을 만들 필요가 없는 부분에서도 폼을 만들거나, 동일한 내용을 반복해서 작성해야 하는 불편함이 있다. 


- 54~58줄

"목록으로" 버튼과 비슷하다. 차이점은 ComSubmit 객체를 생성할 때 form의 아이디인 frm을 인자값으로 넘겨주었다.

ComSubmit 객체는 객체가 생성될 때, 폼의 아이디가 인자값으로 들어오면 그 폼을 전송하고, 파라미터가 없으면 숨겨둔 폼을 이용하여 데이터를 전송하도록 구현하였다. 따라서 전송할 데이터가 있는 frm이라는 id를 가진 form을 이용하도록 id를 넘겨주었다. 이 때 위에서 말했던 TITLE, CONTENTS가 전송되는 것이다.


2.6 확인하기

- 주소창에 localhost:8080/myapp/openBoardWrite.do 를 입력하여 창이 잘 열리는 지 확인하자.


- 그리고 밑과 같이 내용을 입력하고 글쓰기를 눌러보자.


- 위처럼 뜬다면 잘 따라왔다는 것이다.


- 그리고 이클립스의 콘솔창을 보자.




- SQL문과 URI등 여러 결과 값 로그들이 찍혀있는 것이 보일 것이다. 잘 살펴보면 START와 END로 구분되어진 것이 보이는데 START에서 END까지가 하나의 호출로 맨 위의 경우는 글쓰기 페이지의 호출, 그 뒤로는 작성하기 버튼을 눌렀을 때의 호출, 그리고 마지막으로는 게시글 리스트 보기 페이지에 대한 호출, 총 3개의 호출이 보인다.