1. restful을 적용하여 게시판을 구현을 완성하시오.(URL 설계 포함)

1-1. 게시판 리스트 불러오기

// Controller 객체
@GetMapping("/board")
	public ModelAndView list(ModelAndView mav) {
		mav.setViewName("rest/rest_list");
		mav.addObject("list", boardService.getList());
		return mav;
}
// Service 인터페이스
public List<BoardVO> getList();

// 인터페이스 구현 객체
@Override
public List<BoardVO> getList() {
	log.info("getList()");
	return mapper.getList();
}
// BoardMapper 객체
public List<BoardVO> getList();
<!-- SQL 구현부 -->
<select id="getList" resultType="edu.bit.ex.board.vo.BoardVO">
	<![CDATA[
		SELECT bId, bName, bTitle, bContent, bDate, bHit, bGroup, bStep, bIndent 
         FROM mvc_board order by bGroup desc, bStep asc
	]]>
</select>
<!-- 페이지 구현부 -->
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!DOCTYPE html>
<html>
	<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Rest List</title>
	
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
	
	<script type="text/javascript">
	$(document).ready(function (){
		$('.a-delete').click(function(event){
			// 이벤트를 취소할 때 동작을 멈춘다.
			event.preventDefault();
			console.log("ajax 호출전");
			
			// <a>의 parent(<td>)의 parent 즉, <tr>를 지칭한다.(클로저)
			/*
				어떻게 제이쿼리는 this가 <a>인 것을 알고있을까?
				: a 태그내 .a-delete 클릭 이벤트가 발생 되었으므로!
				: $('.a-delete').click(function(event)
			*/
			var trObj = $(this).parent().parent(); 
 
			$.ajax({
				// AJAX의 타입(삭제)
				type : 'DELETE',
				
				// <a>의(this) 속성(href)을 가져온다.(attr)
				url : $(this).attr("href"),
				
				// 캐시를 false 설정하여 페이지가 새로 고쳐질때
				// 데이터를 남기지 않는다(?)
				cache : false,
				
				success: function(result){
					console.log(result);
					if(result=="SUCCESS"){
						// trObj 변수를 삭제한다.(게시글 삭제)
						$(trObj).remove();
						console.log("REMOVED!")
					}
				},
				error:function(e){
					console.log(e);
				}
			})
		});	
	});	
</script>
</head>
<body>
	<table width="500" cellpadding="0" cellspacing="0" border="1">
		<tr>
			<th>번호</th>
			<th>이름</th>
			<th>제목</th>
			<th>날짜</th>
			<th>조회수</th>
			<th>삭제</th>
		</tr>	
		<c:forEach items="${list}" var="dto">
        	<tr>
            	<td>${dto.bId}</td>
				<td>${dto.bName}</td>
				<td>
					<c:forEach begin="1" end="${dto.bIndent}">[Re]</c:forEach>
					<a href="${pageContext.request.contextPath}/restful/board/${dto.bId}">${dto.bTitle}</a></td>
				<td><fmt:formatDate value="${dto.bDate}" pattern="YYYY-MM-DD"/></td>
				<td>${dto.bHit}</td>
				<td><a class="a-delete" href="${pageContext.request.contextPath}/restful/board/${dto.bId}">삭제</a></td>		
       	   </tr>
       </c:forEach>  	   
	   <tr>
			<th>번호</th>
			<th>이름</th>
			<th>제목</th>
			<th>날짜</th>
			<th>조회수</th>
			<th>삭제</th>
	   </tr>	
	   <tr>
			<td colspan="6"><a href="${pageContext.request.contextPath}/restful/write">글쓰기</a></th>
	   </tr>	
	</table>
</body>
</html>

 

1-2. 작성글 삭제

// Controller 객체
@DeleteMapping("/board/{bId}")
public ResponseEntity<String> rest_delete(BoardVO boardVO, Model model) {
	ResponseEntity<String> entity = null;
	log.info("rest_delete..");

	try {
		boardService.remove(boardVO.getbId());
		// 삭제가 성공하면 상태메시지 저장
		entity = new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
	} catch (Exception e) {
		e.printStackTrace();
		// 댓글 삭제가 실패하면 BAD_REQUEST를 리턴
		entity = new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);
	}
	// 삭제 처리 HTTP 상태 메시지 리턴
	return entity;
}
// Service 인터페이스
public int remove(int bId);

// 인터페이스 구현 객체
@Override
public int remove(int bId) {
	log.info("remove..........");
	return mapper.ajaxDelete(bId);
}
// BoardMapper 객체
public int ajaxDelete(int bId);
<!-- SQL 구현부 -->
<delete id="ajaxDelete">
	<![CDATA[
		delete from mvc_board where bId = #{bId}
	]]>
</delete>
<!-- 페이지 구현부 -->
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!DOCTYPE html>
<html>
	<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Rest List</title>
	
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
	
	<script type="text/javascript">
	$(document).ready(function (){
		$('.a-delete').click(function(event){
			// 이벤트를 취소할 때 동작을 멈춘다.
			event.preventDefault();
			console.log("ajax 호출전");
			
			// <a>의 parent(<td>)의 parent 즉, <tr>를 지칭한다.(클로저)
			/*
				어떻게 제이쿼리는 this가 <a>인 것을 알고있을까?
				: a 태그내 .a-delete 클릭 이벤트가 발생 되었으므로!
				: $('.a-delete').click(function(event)
			*/
			var trObj = $(this).parent().parent(); 
 
			$.ajax({
				// AJAX의 타입(삭제)
				type : 'DELETE',
				
				// <a>의(this) 속성(href)을 가져온다.(attr)
				url : $(this).attr("href"),
				
				// 캐시를 false 설정하여 페이지가 새로 고쳐질때
				// 데이터를 남기지 않는다(?)
				cache : false,
				
				success: function(result){
					console.log(result);
					if(result=="SUCCESS"){
						// trObj 변수를 삭제한다.(게시글 삭제)
						$(trObj).remove();
						console.log("REMOVED!")
					}
				},
				error:function(e){
					console.log(e);
				}
			})
		});	
	});	
</script>
</head>
<body>
	<table width="500" cellpadding="0" cellspacing="0" border="1">
		<tr>
			<th>번호</th>
			<th>이름</th>
			<th>제목</th>
			<th>날짜</th>
			<th>조회수</th>
			<th>삭제</th>
		</tr>	
		<c:forEach items="${list}" var="dto">
        	<tr>
            	<td>${dto.bId}</td>
				<td>${dto.bName}</td>
				<td>
					<c:forEach begin="1" end="${dto.bIndent}">[Re]</c:forEach>
					<a href="${pageContext.request.contextPath}/restful/board/${dto.bId}">${dto.bTitle}</a></td>
				<td><fmt:formatDate value="${dto.bDate}" pattern="YYYY-MM-DD"/></td>
				<td>${dto.bHit}</td>
				<td><a class="a-delete" href="${pageContext.request.contextPath}/restful/board/${dto.bId}">삭제</a></td>		
       	   </tr>
       </c:forEach>  	   
	   <tr>
			<th>번호</th>
			<th>이름</th>
			<th>제목</th>
			<th>날짜</th>
			<th>조회수</th>
			<th>삭제</th>
	   </tr>	
	   <tr>
			<td colspan="6"><a href="${pageContext.request.contextPath}/restful/write">글쓰기</a></th>
	   </tr>	
	</table>
</body>
</html>

 

1-3. 작성글 불러오기

// Controller 객체
@GetMapping("/board/{bId}")
public ModelAndView rest_content_view(BoardVO boardVO, ModelAndView mav) {
	log.info("rest_content_view");
	mav.setViewName("rest/content_view");
	mav.addObject("content_view", boardService.getBoard(boardVO.getbId()));
	return mav;
}
// Service 인터페이스
public BoardVO getBoard(int getbId);

// 인터페이스 구현 객체
@Transactional
@Override
public BoardVO getBoard(int bno) {
	mapper.upHit(bno);
	log.info("getBoard()");
	return mapper.read(bno);
}
// BoardMapper 객체
public BoardVO read(int bno);
public void upHit(int bno);
<!-- SQL 구현부 -->
<select id="read" resultType="edu.bit.ex.board.vo.BoardVO">
	<![CDATA[
		select * from mvc_board where bId = #{bno}
	]]>
</select>
<update id="upHit">
	<![CDATA[
		update mvc_board set bHit = bHit+1 where bId = #{bId}
	]]>
</update>
<!-- 페이지 구현부 -->
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Content View</title>
	
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
	
	<script type="text/javascript">
   	$(document).ready(function(){
      $("#updateForm").submit(function(event){         
           event.preventDefault();     
           var bId = $("#bId").val();
           var bName = $("#bName").val();
           var bTitle = $("#bTitle").val();
           var bContent = $("#bContent").val();              
           
           console.log(bName);
           console.log(bTitle);
           console.log(bContent);
           console.log($(this).attr("action"));    
           
           var form = {
                 bId: bId,
                 bName: bName,
                 bContent: bContent,
                 bTitle: bTitle
           };

           $.ajax({
             type : "PUT",
             url : $(this).attr("action"),
             cache : false,
             contentType:'application/json; charset=utf-8', // 인코딩 데이터 변환
             data: JSON.stringify(form), // 보안 문제 해결을 위해 stringify 메소드를 사용
             success: function (result) {       
               if(result == "SUCCESS"){
                  // update가 완료되었으면 리스트 페이지로 이동        
                  $(location).attr('href', '${pageContext.request.contextPath}/restful/board/')                            
               }                       
             },
             error: function (e) {
                 console.log(e);
             }
         })            
       }); // end submit()       
   }); // end ready()
</script>
</head>
<body>
   <table width="500" cellpadding="0" cellspacing="0" border="1">
      <form id="updateForm" action="${pageContext.request.contextPath}/restful/board/${content_view.bId}" method="post">
         <input type="hidden" id="bId" value="${content_view.bId}">
         <tr>
            <td> 번호 </td>
            <td> ${content_view.bId} </td>
         </tr>
         <tr>
            <td> 조회수 </td>
            <td> ${content_view.bHit} </td>
         </tr>
         <tr>
            <td> 이름 </td>
            <td> <input type="text" id="bName" value="${content_view.bName}"></td>
         </tr>
         <tr>
            <td> 제목 </td>
            <td> <input type="text" id="bTitle" value="${content_view.bTitle}"></td>
         </tr>
         <tr>
            <td> 내용 </td>
            <td> <textarea rows="10" id="bContent" >${content_view.bContent}</textarea></td>
         </tr>
         <tr >
            <td colspan="2">
	            <input type="submit" value="수정">&nbsp;&nbsp;
	            <a href="${pageContext.request.contextPath}/restful/board">목록보기</a>&nbsp;&nbsp;
	            <a href="#">삭제</a>&nbsp;&nbsp;
	            <a href="${pageContext.request.contextPath}/restful/board/reply/${content_view.bId}">답변</a>
            </td>
         </tr>
      </form>
   </table>
</body>
</html>

 

1-4. 작성글 수정하기

 

// Controller 객체
@PutMapping("/board/{bId}")
public ResponseEntity<String> rest_update(@RequestBody BoardVO boardVO, ModelAndView modelAndView) {
	ResponseEntity<String> entity = null;

	log.info("rest_update..");
	try {
		boardService.modifyBoard(boardVO);
		entity = new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
	} catch (Exception e) {
		e.printStackTrace();
		entity = new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);
	}

	return entity;
}
// Service 인터페이스
public void modifyBoard(BoardVO boardVO);

// 인터페이스 구현 객체
@Override
public void modifyBoard(BoardVO boardVO) {
	mapper.modify(boardVO);
	log.info("modifyBoard()");
}
// BoardMapper 객체
public void modify(BoardVO boardVO);
<!-- SQL 구현부 -->
<update id="modify">
	<![CDATA[
		update mvc_board set bName = #{bName}, bTitle = #{bTitle}, bContent = #{bContent} where bId = #{bId}
	]]>
</update>
<!-- 페이지 구현부 -->
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Content View</title>
	
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
	
	<script type="text/javascript">
   	$(document).ready(function(){
      $("#updateForm").submit(function(event){         
           event.preventDefault();     
           var bId = $("#bId").val();
           var bName = $("#bName").val();
           var bTitle = $("#bTitle").val();
           var bContent = $("#bContent").val();              
           
           console.log(bName);
           console.log(bTitle);
           console.log(bContent);
           console.log($(this).attr("action"));    
           
           var form = {
                 bId: bId,
                 bName: bName,
                 bContent: bContent,
                 bTitle: bTitle
           };

           $.ajax({
             type : "PUT",
             url : $(this).attr("action"),
             cache : false,
             contentType:'application/json; charset=utf-8', // 인코딩 데이터 변환
             data: JSON.stringify(form), // 보안 문제 해결을 위해 stringify 메소드를 사용
             success: function (result) {       
               if(result == "SUCCESS"){
                  // update가 완료되었으면 리스트 페이지로 이동        
                  $(location).attr('href', '${pageContext.request.contextPath}/restful/board/')                            
               }                       
             },
             error: function (e) {
                 console.log(e);
             }
         })            
       }); // end submit()       
   }); // end ready()
</script>
</head>
<body>
   <table width="500" cellpadding="0" cellspacing="0" border="1">
      <form id="updateForm" action="${pageContext.request.contextPath}/restful/board/${content_view.bId}" method="post">
         <input type="hidden" id="bId" value="${content_view.bId}">
         <tr>
            <td> 번호 </td>
            <td> ${content_view.bId} </td>
         </tr>
         <tr>
            <td> 조회수 </td>
            <td> ${content_view.bHit} </td>
         </tr>
         <tr>
            <td> 이름 </td>
            <td> <input type="text" id="bName" value="${content_view.bName}"></td>
         </tr>
         <tr>
            <td> 제목 </td>
            <td> <input type="text" id="bTitle" value="${content_view.bTitle}"></td>
         </tr>
         <tr>
            <td> 내용 </td>
            <td> <textarea rows="10" id="bContent" >${content_view.bContent}</textarea></td>
         </tr>
         <tr >
            <td colspan="2">
	            <input type="submit" value="수정">&nbsp;&nbsp;
	            <a href="${pageContext.request.contextPath}/restful/board">목록보기</a>&nbsp;&nbsp;
	            <a href="#">삭제</a>&nbsp;&nbsp;
	            <a href="${pageContext.request.contextPath}/restful/board/reply/${content_view.bId}">답변</a>
            </td>
         </tr>
      </form>
   </table>
</body>
</html>

 

1-5. 작성글 답변하기

// Controller 객체
@GetMapping("/board/reply/{bId}")
public ModelAndView rest_reply_view(BoardVO boardVO, ModelAndView mav) {
	log.info("rest_reply_view");
	mav.setViewName("rest/reply_view");
	mav.addObject("reply_view", boardService.getReply(boardVO.getbId()));
	return mav;
}
@PutMapping("/board/reply/{bId}")
public ResponseEntity<String> rest_reply(@RequestBody BoardVO boardVO, ModelAndView modelAndView) {
	ResponseEntity<String> entity = null;

	log.info("rest_reply..");
	try {
		boardService.replyBoard(boardVO);
		entity = new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
	} catch (Exception e) {
		e.printStackTrace();
		entity = new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);
	}

	return entity;
}
// Service 인터페이스
public BoardVO getReply(int getbId);
public void replyBoard(BoardVO boardVO);

// 인터페이스 구현 객체
@Override
public BoardVO getReply(int bno) {
	log.info("getBoard()");
	return mapper.readReply(bno);
}
@Transactional
@Override
public void replyBoard(BoardVO boardVO) {
	mapper.reply(boardVO);
	mapper.replyShape(boardVO);
	log.info("replyBoard()");
}
// BoardMapper 객체
public BoardVO readReply(int bno);
public void reply(BoardVO boardVO);
public void replyShape(BoardVO boardVO);
<!-- SQL 구현부 -->
<select id="readReply" resultType="edu.bit.ex.board.vo.BoardVO">
	<![CDATA[
		select * from mvc_board where bId = #{bno}
	]]>
</select>
<insert id="reply" >
	<![CDATA[
		insert into mvc_board (bId, bName, bTitle, bContent, bGroup, bStep, bIndent) values (mvc_board_seq.nextval, #{bName}, #{bTitle}, #{bContent}, #{bGroup}, #{bStep}+1, #{bIndent}+1)
	]]>
</insert>
<update id="replyShape" >
	<![CDATA[
		update mvc_board set bStep = bStep + 1 where bGroup = #{bGroup}
	]]>
</update>
<!-- 페이지 구현부 -->
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Reply View</title>
	
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
	
	<script type="text/javascript">
   	$(document).ready(function(){
      $("#modifyForm").submit(function(event){         
           event.preventDefault();
           var bId = $("#bId").val();
           var bGroup = $("#bGroup").val();
           var bStep = $("#bStep").val();
           var bIndent = $("#bIndent").val();
           var bName = $("#bName").val();
           var bTitle = $("#bTitle").val();
           var bContent = $("#bContent").val();           
           
           console.log(bId);
           console.log(bGroup);
           console.log(bStep);
           console.log(bIndent);
           console.log(bName);
           console.log(bTitle);
           console.log(bContent);
           console.log($(this).attr("action"));    
           
           var form = {
                 bId: bId,
                 bGroup: bGroup,
                 bStep: bStep,
                 bIndent: bIndent,
                 bName: bName,
                 bTitle: bTitle,
                 bContent: bContent
           };

           $.ajax({
             type : "PUT",
             url : $(this).attr("action"),
             cache : false,
             contentType:'application/json; charset=utf-8',
             data: JSON.stringify(form),
             success: function (result) {       
               if(result == "SUCCESS"){     
                  $(location).attr('href', '${pageContext.request.contextPath}/restful/board/')                            
               }                       
             },
             error: function (e) {
                 console.log(e);
             }
         })            
       });       
   	});
	</script>
</head>
<body>
	<table width="500" cellpadding="0" cellspacing="0" border="1">
		<form id="modifyForm" action="${pageContext.request.contextPath}/restful/board/reply/${reply_view.bId}" method="post">
			<input type="hidden" id="bId" name="bId" value="${reply_view.bId}">
			<input type="hidden" id="bGroup" name="bGroup" value="${reply_view.bGroup}">
			<input type="hidden" id="bStep" name="bStep" value="${reply_view.bStep}">
			<input type="hidden" id="bIndent" name="bIndent" value="${reply_view.bIndent}">
			<tr>
				<td>번호</td>
				<td>${reply_view.bId}</td>
			</tr>
			<tr>
				<td>조회수</td>
				<td>${reply_view.bHit}</td>
			</tr>
			<tr>
				<td>이름</td>
				<td><input type="text" id="bName" name="bName" value="${reply_view.bName}"></td>
			</tr>
			<tr>
				<td>제목</td>
				<td><input type="text" id="bTitle" name="bTitle" value="${reply_view.bTitle}"></td>
			</tr>
			<tr>
				<td>내용</td>
				<td><textarea cols="20" id="bContent" rows="10" name="bContent">${reply_view.bContent}</textarea></td>
			</tr>
			<tr>
				<td colspan="2">
					<input type="submit" value="답변">&nbsp;&nbsp;
					<a href="${pageContext.request.contextPath}/restful/board">목록</a>
				</td>
			</tr>
		</form>
	</table>
</body>
</html>

 

1-6. 글 작성하기

// Controller 객체
@GetMapping("/board/write")
public ModelAndView rest_write_view(BoardVO boardVO, ModelAndView mav) {
	log.info("rest_write_view");
	mav.setViewName("rest/write_view");
	return mav;
}
@PutMapping("/board/write")
public ResponseEntity<String> write_view(@RequestBody BoardVO boardVO, ModelAndView modelAndView) {
	ResponseEntity<String> entity = null;

	log.info("write_view..");
	try {
		boardService.writeBoard(boardVO);
		entity = new ResponseEntity<String>("SUCCESS", HttpStatus.OK);
	} catch (Exception e) {
		e.printStackTrace();
		entity = new ResponseEntity<String>(e.getMessage(), HttpStatus.BAD_REQUEST);
	}

	return entity;
}
// Service 인터페이스
public void writeBoard(BoardVO boardVO);

// 인터페이스 구현 객체
@Override
public void writeBoard(BoardVO boardVO) {
	mapper.insert(boardVO);
	log.info("writeBoard()");
}
// BoardMapper 객체
public void insert(BoardVO boardVO);
<!-- SQL 구현부 -->
<insert id="insert">
	<![CDATA[
		insert into mvc_board (bId, bName, bTitle, bContent, bHit, bGroup, bStep, bIndent) values (mvc_board_seq.nextval, #{bName}, #{bTitle}, #{bContent}, 0, mvc_board_seq.currval, 0, 0)
	]]>
</insert>
<!-- 페이지 구현부 -->
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Write View</title>

	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
	
	<script type="text/javascript">
   	$(document).ready(function(){
      $("#writeForm").submit(function(event){         
           event.preventDefault();
           var bName = $("#bName").val();
           var bTitle = $("#bTitle").val();
           var bContent = $("#bContent").val();           
           
           console.log(bName);
           console.log(bTitle);
           console.log(bContent);
           console.log($(this).attr("action"));    
           
           var form = {
                 bName: bName,
                 bTitle: bTitle,
                 bContent: bContent
           };

           $.ajax({
             type : "PUT",
             url : $(this).attr("action"),
             cache : false,
             contentType:'application/json; charset=utf-8',
             data: JSON.stringify(form),
             success: function (result) {       
               if(result == "SUCCESS"){     
                  $(location).attr('href', '${pageContext.request.contextPath}/restful/board/')                            
               }                       
             },
             error: function (e) {
                 console.log(e);
             }
         })            
       });       
   	});
	</script>	
</head>
<body>
<table width="500" cellpadding="0" cellspacing="0" border="1">
      <form id="writeForm" action="${pageContext.request.contextPath}/restful/board/write" method="post">
         <tr>
            <td>이름</td>
            <td><input type="text" id="bName" name="bName" size="50"></td>
         </tr>
         <tr>
            <td>제목</td>
            <td><input type="text" id="bTitle" name="bTitle" size="50"></td>
         </tr>
         <tr>
            <td>내용</td>
            <td><textarea cols="20" rows="10" id="bContent" name="bContent"></textarea></td>
         </tr>
         <tr>
            <td colspan="2">
	            <input type="submit" value="입력"> &nbsp;&nbsp;
	            <a href="${pageContext.request.contextPath}/restful/board">목록</a>
            </td>
         </tr>
      </form>
   </table>
</body>
</html>

 

 

2. 부트스트랩으로 로그인 화면구현후 interceptor 적용하여 로그인한 유저에게만 게시판이 보이도록 하시오.

2-1. 소스코드(Controller 객체)

package edu.bit.ex.board.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import edu.bit.ex.board.service.LoginService;
import edu.bit.ex.board.vo.UserVO;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Log4j
@AllArgsConstructor
@Controller
public class LoginController {
	private LoginService loginService;

	// 루트 페이지 매핑(home 컨트롤러 매핑 구현 주석처리 할 것
	@GetMapping("/")
	public String home() {
		log.info("home...");
		return "log/login";
	}

	// 로그인 페이지
	@PostMapping("/login")
	public String login(HttpServletRequest req, RedirectAttributes rttr) {

		log.info("post login..");
		String id = req.getParameter("id");
		String pw = req.getParameter("pw");

		// Session 처리를 위한 Session 객체 HttpServletRequest 안에 있음.
		HttpSession session = req.getSession();

		UserVO user = loginService.loginUser(id, pw);

		if (user == null) {
			session.setAttribute("user", null);
			/*
			 * Spring3 에서 제공하는 RedirectAttributes를 사용하면 redirect post 구현이 가능하다.
              * 하지만 일회성이라 새로고침하면 날라가는 데이터이므로 사용목적에 따라서 판단 후 사용한다.
			 */
			rttr.addFlashAttribute("msg", false);
		} else {
			session.setAttribute("user", user);
		}

		return "redirect:/";
	}

	// 로그아웃
	@RequestMapping(value = "/logout")
	public String logout(HttpSession session) throws Exception {
		log.info("/member/logout");
		session.invalidate();

		return "redirect:/";
	}
}

 

2-2. 소스코드(Interceptor 객체)

package edu.bit.ex.board.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import edu.bit.ex.board.vo.UserVO;
import lombok.extern.log4j.Log4j;

@Log4j
public class BoardInterceptor extends HandlerInterceptorAdapter {
	// preHandle() : 컨트롤러보다 먼저 수행되는 메서드
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		System.out.println("preHandle 실행");
		// session 객체를 가져옴
		HttpSession session = request.getSession();

		// login처리를 담당하는 사용자 정보를 담고 있는 객체를 가져옴
		UserVO user = (UserVO) session.getAttribute("user");

		if (user == null) {
			log.info("user가 null");
			// 로그인이 안되어 있는 상태이므로 로그인 폼으로 다시 돌려보냄(redirect)
			response.sendRedirect(request.getContextPath());

			return false; // 더이상 컨트롤러 요청으로 가지 않도록 false로 반환함
		}

		// preHandle의 return은 컨트롤러 요청 uri로 가도 되냐 안되냐를 허가하는 의미임
		// 따라서 true로하면 컨트롤러 uri로 가게 됨.
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		super.postHandle(request, response, handler, modelAndView);
		System.out.println("postHandle 실행");
	}
}

 

2-3. 소스코드(LoginService 인터페이스 및 객체)

// 로그인 인터페이스
package edu.bit.ex.board.service;

import edu.bit.ex.board.vo.UserVO;

public interface LoginService {
	public UserVO loginUser(String id, String pw);
}

// 로그인 서비스 객체
package edu.bit.ex.board.service;

import org.springframework.stereotype.Service;

import edu.bit.ex.board.mapper.LoginMapper;
import edu.bit.ex.board.vo.UserVO;
import lombok.AllArgsConstructor;

@Service
@AllArgsConstructor
public class LoginServiceImpl implements LoginService {
	LoginMapper loginMapper;

	@Override
	public UserVO loginUser(String id, String pw) {
		return loginMapper.logInUser(id, pw);
	}
}

 

2-4. 소스코드(LoginMapper 객체)

package edu.bit.ex.board.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import edu.bit.ex.board.vo.UserVO;

//@Mapper // root-context내 my-batis 매퍼 경로 지정이 없을시 사용
@Mapper
public interface LoginMapper {
	// 지정할 변수가 2개 이상인 경우 파라미터를 설정한다.
	@Select("select * from users where username = #{username} and password = #{password}")
	public UserVO logInUser(@Param("username") String username, @Param("password") String password);
}

 

2-5. 소스코드(login 페이지)

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<html>
<head>
	<meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="/docs/4.0/assets/img/favicons/favicon.ico">
    
	<title>Login Page</title>
	
	<link rel="canonical" href="https://getbootstrap.com/docs/4.0/examples/sign-in/">
    <!-- Bootstrap core CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
          integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <!-- Custom styles for this template -->
    
    <link href="<c:url value="/resources/css/signin.css"/>" rel="stylesheet">
</head>
<body>
	<c:if test="${user == null}">
		<form class="form-signin" role="form" method="post" autocomplete="off" action="${pageContext.request.contextPath}/login">
		   <a href="https://github.com/roqhdehd502">
		   	  <center>
		   	  	  <img class="mb-4" src="https://avatars.githubusercontent.com/u/47406388?s=460&u=be5c94a9effdfe887c56be3dec5ca29e224e83ce&v=4" alt="" width="72" height="72">
		   	  </center>
		   </a>
		   
		   <h1 class="h3 mb-3 font-weight-normal"><center>아이디와 비밀번호를<br>입력해주세요.</center></h1>
		   <!--<p>
		   	   <label for="userId">아이디</label>
		   	  <input type="text" id="userId" name="id" /> 	  
		   </p>-->  
		   <label for="inputEmail" class="sr-only">아이디</label>
		   <input type="text" id="inputId" class="form-control" placeholder="아이디" name="id" required autofocus>
		   
		   <!--<p>
		      <label for="userPass">패스워드</label> 
		      <input type="password" id="userPass" name="pw"/>
		   </p>--> 
		   <label for="inputPassword" class="sr-only">패스워드</label>
      	   <input type="password" id="inputPassword" class="form-control" placeholder="패스워드" name="pw" required>
		   
		   <div class="checkbox mb-3">
	          <label>
	             <input type="checkbox" value="remember-me"> 입력사항 기억
	          </label>
      	   </div>
      	   
      	   <!--<p><button type="submit">로그인</button></p>
		   <p><a href="/member/register">회원가입</a></p> -->
      	   <button class="btn btn-lg btn-primary btn-block" type="submit">로그인</button>	   
		   <p class="mt-5 mb-3 text-muted"><center>2021&copy;All rights reserved by <a href="https://getbootstrap.com/">getbootstrap</a>.<br><br>
		   Designed and built with all the love in the world by the Bootstrap team with the help of our contributors.<br>
		   Currently v5.0.0-beta1. Code licensed MIT, docs CC BY 3.0.<br>
		   </center></p>
		</form>
	</c:if>
	
	<c:if test="${msg == false}">
	   <p style="color:#f00;">로그인에 실패했습니다. 아이디 또는 패스워드를 다시 입력해주십시오.</p>
	</c:if>
	
	<c:if test="${user != null}">
	   <p>${user.username}님 환영합니다.</p>
	   
	   <!-- <a href="member/modify">회원정보 수정</a>, <a href="member/withdrawal">회원탈퇴</a><br/> -->
	   <a href="${pageContext.request.contextPath}/board/list">게시판 리스트</a><br>
	   <a href="${pageContext.request.contextPath}/logout">로그아웃</a>   
	</c:if>
</body>
</html>

 

2-6. 구현화면

 

 

3. interceptor의 개념에 대하여 설명하시오.

: 단어상 ‘가로채다(intercept)‘의 의미를 가진 인터셉터는 서버 페이지에서 입력 데이터 정보를 보내 클라이언트에게 응답을 하기 전, 서버 측 세션 내용을 중간에 가져와 유효성 검증을 하는 기능이다. Spring에서는 HandlerInterceptorAdapter 객체를 상속하여 구현한다.

public class BoardInterceptor extends HandlerInterceptorAdapter {
	// preHandle() : 컨트롤러보다 먼저 수행되는 메서드
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		System.out.println("preHandle 실행");
		// session 객체를 가져옴
		HttpSession session = request.getSession();

		// login처리를 담당하는 사용자 정보를 담고 있는 객체를 가져옴
		UserVO user = (UserVO) session.getAttribute("user");

		if (user == null) {
			log.info("user가 null");
			// 로그인이 안되어 있는 상태이므로 로그인 폼으로 다시 돌려보냄(redirect)
			response.sendRedirect(request.getContextPath());

			return false; // 더이상 컨트롤러 요청으로 가지 않도록 false로 반환함
		}

		// preHandle의 return은 컨트롤러 요청 uri로 가도 되냐 안되냐를 허가하는 의미임
		// 따라서 true로하면 컨트롤러 uri로 가게 됨.
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		super.postHandle(request, response, handler, modelAndView);
		System.out.println("postHandle 실행");
	}
}

 

 

4. 부트스트랩이란?

: HTML, CSS, JS 태그 및 스크립트의 성능 향상 및 기능 확장성을 둔 프론트엔드 프레임워크(Front-End Framework)이다. 부트스트랩이 가진 특성은 동적 웹 페이지(Dynamic Web Page)를 구축할 수 있어 PC외에도 스마트폰 및 태블릿 등 다양한 플랫폼에 디자인을 적용할 수 있다.

'WebDev > 본과정' 카테고리의 다른 글

Spring Security  (0) 2021.05.17
목표 지향 프로그래밍  (0) 2021.05.17
Spring의 트랜잭션과 rollback 및 commit  (0) 2021.05.17
RESTful  (0) 2021.05.17
AJAX와 JSON  (0) 2021.05.17