2013년 7월 28일 일요일

11. (Spring게시판강좌)리스트에 본문 미리보기 기능추가(Ajax, HttpServlet 이용), Spring Board강좌

Spring 게시판 구현(게시물 본문 내용 미리보기)
 
구로디지털 오엔제이프로그래밍실무교육센터
(오라클,자바프레임워크 전문 강의)
 
 
1.     시작하기<?XML:NAMESPACE PREFIX = O />
 
 
-       이전 까지 만든 게시판 리스트 보기 기능에 추가로 본문 내용 미리 보기 기능을 구현해 보자
-       게시물 본문 내용 미리 보기 기능은 게시판 리스트에서 제목에 마우스를 이동하는 경우 Ajax 기능과 자바 웹 서블릿을 이용하여 미리 본문 내용을 읽어 오도록 구성 하였다.
-       먼저 JSP AJAX CALL을 위한 자바스크립트를 추가하고, ajax XMLHttpRequest 생성을 위한 createXMLHttpRequest.js 파일을 만들자.
-       DAO단부터 Service쪽 그리고 미리 보기용 서블릿까지 따라 하면서 만들어 보자.
(이전에 만든 BoardMuitiController는 이용하지 않고 서블릿을 통해 미리 보기 기능을 구현한다.)
 
 
2.     /js/createXMLHttpRequest.js
 
web.xml 파일은 웹 애플리케이션(Web Application)에 대한 전체 설정 파일이다. Web Application XMLHttpRequest객체는 현재 대부분의 브라우저에 내장되어 있는 객체로서 자바스크립트에 대한 HTTP 클라이언트 이므로 서버로 GET, POST 요청을 비동기 적으로 할 수 있다. AJAX에서 클라이언트와 서버간의 통신을 담당하는 객체이다.
 
아래 js 파일은 이 객체를 생성하기 위한 코드임.
 
[createXMLHttpRequest.js]
 
       function createXMLHttpRequest(){
                    var xmlHttp;
             // 익스냐 익스 아니냐???
                    if(window.ActiveXObject){
                                 try{
                                              xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
                                 } catch(e){
                                        try{
                                              xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
                                        } catch(e1){
                                              xmlHttp = null;
                                        }
                                 }
                    } else if(window.XMLHttpRequest){
                           try{
                                        xmlHttp = new XMLHttpRequest();
                           } catch(e){
                                        xmlHttp = null;
                           }
                    }
                          
                    if(xmlHttp == null) errorMessage();
                    return xmlHttp;
       }
      
       function errorMessage(){
                    alert("지원할 없는 브라우저입니다.");
             }
            
            
 
 
3.     /jsp/list.jsp 수정
 
-       게시물 본문 내용 미리보기 기능을 위한 AJAX 요청 처리를 위해 <head></head> 사이에 아래 코드를 추가하자.
 
 
 
<style type="text/css">
       #layer1{
             position:absolute;
             padding:5px;
             filter:alpha(opacity=50);
             width:250px; height:150px;
             background-color:white;
             border:2px #000000 dotted;
             visibility:hidden;
       }
</style>
<script language="javascript" type="text/javascript" src="../js/createXMLHttpRequest.js"></script>
<script type="text/javascript">
       var xmlHttp;
       var xmlDoc;
       var message;
      
       function contentprev(seq){
             var url = "preView?seq="+seq;  //미리보기 서블릿 호출
             xmlHttp = createXMLHttpRequest();
             xmlHttp.onreadystatechange = handleStateChange;
             xmlHttp.open("get" , url , true);
             xmlHttp.send(null);
       }
      
       function handleStateChange(){
             if(xmlHttp.readyState == 4){
                           if(xmlHttp.status == 200){
                                        xmlDoc = xmlHttp.responseText;
                                        document.getElementById("layer1").innerHTML = xmlDoc;
                           }
             }
       }
 
       function showlayer(id){   
             if(document.all)
                    document.all[id].style.visibility="visible";
             else if(document.layers)
                    document.layers[id].style.visibility="visible";            
       }
       function hidelayer(id){   
             if(document.all)
                    document.all[id].style.visibility="hidden";
             else if(document.layers)
                    document.layers[id].style.visibility="hidden";      
       }
    function movetip() {
        layer1.style.pixelTop=event.y+document.body.scrollTop+10;
        layer1.style.pixelLeft=event.x+document.body.scrollLeft+10;
    }
    document.onmousemove=movetip;              
</script>
 
 
코드의 핵심은 생성된 XMLHttpRequest를 이용하여 게시물 미리 보기를 위한 preView라는 이름의 자바 서블릿을 호출하는 부분이다. XMLHttpRequest open() 메소드를 통해 요청을 초기화 하고 요청을 위한 URL, 요청의 종류(GET or POST)를 결정하고 비동기 요청을 위해 “true”라는 옵션을 이용했다.  실제 요청은 send() 메소드를 통해 전송되며 GET 방식의 호출이므로 send(null) 이라고 했다.
 
-       <body>바로 아래에 게시물 미리보기용 <div> 추가!
 
<div id="layer1">
             게시물 본문 미리 보기
-       </div>
 
 
아래는 수정된 /jsp/list.jsp 전체 소스 코드이다.
 
[list.jsp]

 
 
<%@ page contentType="text/html; charset=euc-kr" language="java" import="java.sql.*" errorPage="" %>
<%@ page import = "javax.rmi.* , javax.naming.* , java.util.* , onj.board.model.*" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>오엔제이 프로그래밍 실무학원</title>
<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
<style type="text/css">
       #layer1{
             position:absolute;
             padding:5px;
             filter:alpha(opacity=50);
             width:250px; height:150px;
             background-color:white;
             border:2px #000000 dotted;
             visibility:hidden;
       }
</style>
<script language="javascript" type="text/javascript" src="/onjboard1/js/createXMLHttpRequest.js"></script>
<script type="text/javascript">
       var xmlHttp;
       var xmlDoc;
       var message;
      
       function contentprev(seq){
            
             var url = "preView?seq="+seq;  //미리보기 서블릿 호출
             xmlHttp = createXMLHttpRequest();
             xmlHttp.onreadystatechange = handleStateChange;
             xmlHttp.open("get" , url , true);
             xmlHttp.send(null);
       }
      
       function handleStateChange(){
             if(xmlHttp.readyState == 4){
                           if(xmlHttp.status == 200){
                                        xmlDoc = xmlHttp.responseText;
                                        document.getElementById("layer1").innerHTML = xmlDoc;
                           }
             }
       }
 
       function showlayer(id){   
             if(document.all)
                    document.all[id].style.visibility="visible";
             else if(document.layers)
                    document.layers[id].style.visibility="visible";            
       }
       function hidelayer(id){   
             if(document.all)
                    document.all[id].style.visibility="hidden";
             else if(document.layers)
                    document.layers[id].style.visibility="hidden";      
       }
    function movetip() {
        layer1.style.pixelTop=event.y+document.body.scrollTop+10;
        layer1.style.pixelLeft=event.x+document.body.scrollLeft+10;
    }
    document.onmousemove=movetip;              
</script>
</head>
<body>
<div id="layer1">
             게시물 본문 미리 보기
</div>
<div style="width:500px;">
<div style="float:right;">
<H3>오엔제이 프로그래밍 실무교육센터 스프링 게시판</H3>
<h5> ${list.size()}</h5>
<table width="600" border="1" align="left">
  <tr align="left">
    <td width="10%" align="center">번호</td>
    <td width="40%" align="center">제목</td>
    <td width="20%" align="center">이름</td>
    <td width="20%" align="center">날짜</td>
    <td width="10%" align="center">조회</td>
  </tr>
              <!-- list 가져와서 board 명명 만큼 반복 -->
             <c:forEach var="board" items="${list}">      
  <tr>
    <td align="center">
                    <c:if test="${board.reply_step == 0}">
                                 ${board.seq}
                    </c:if>
                    <c:if test="${board.reply_step != 0}">
                                  
                    </c:if>                   
    </td>
    <td>      <!-- 게시물은 덧글에 따른 번호와 덧글 존재 유무로 정렬됨 -->
                    <c:choose>                
                           <c:when test="${board.reply_step != 0}"><!-- 게시글이 덧글일 경우 -->
                                 <c:forEach var="i" begin="1" end="${board.reply_level}" step="1"><!-- 레벨의 수만큼 글을 뒤로 민다 -->
                                          
                                 </c:forEach>
                                        <a href="read.html?seq=${board.seq}" onmouseover="contentprev('${board.seq}');showlayer('layer1');" onmouseout="hidelayer('layer1');">${board.title}</a>
                                        <!-- 마우스를 올리면 게시물 번호에 따른 showlayer(게시물 미리보기 ) 실행됨 -->
                           </c:when>
                           <c:when test="${board.reply_step == 0}">
                                        <a href="read.html?seq=${board.seq}" onmouseover="contentprev('${board.seq}');showlayer('layer1');" onmouseout="hidelayer('layer1');">${board.title}</a>                    
                           </c:when>
                    </c:choose>
   </td>
    <td align="center">${board.name}</td>
    <td align="center">${board.regdate}</td>
    <td align="center">${board.readCount}</td>
  </tr>
             </c:forEach>
 
  <tr>
    <td align="center"><input type="button" value="쓰기" onclick="location.href='write.html';"></td>
    <td> </td>
    <td> </td>
    <td> </td>
    <td> </td>
  </tr>
</table>
</div>
</div>
</body>
</html>
 
 
4.     /WEB-INF/web.xml
 
 
web.xml에 아래 서블릿 매핑은 이미 정의했었다. 다시 한번 보자.
 
 
<!--  게시물 미리 보기 기능을 위한 ajax 처리용 서블릿 정의 -->
       <servlet>
             <servlet-name>preView</servlet-name>
             <servlet-class>onj.board.ajaxpreview.ContentPreview</servlet-class>
       </servlet>  
 
       <servlet-mapping>
             <servlet-name>preView</servlet-name>
             <url-pattern>/preView</url-pattern>
       </servlet-mapping>        
 
 
onj.board.ajaxpreview.ContentPreview 서블릿의 이름을 preView라고 매핑하고 URL 요청에서 /preView라는 요청이 올 때 이를 실행하라는 의미이다. 물론 서블릿 매핑은 자바 애노테이션(Annotation)을 이용하여 처리하는 것도 가능한데 서블릿 클래스를 작성시 Tomcat7 이상, Servlet3.0 이상 이라면 @WebServlet(urlPatterns = "/preView") 라고 기술하면 된다. XML과 애노테이션 둘 다 동시에 기술하면 XML쪽 매핑이 우선 한다.
 
 
 
5.     게시물 미리보기 기능을 위한 DAO쪽의 클래스를 만들어 보자.
 
[BoardDAO.java]
 
소스 코드 빨강색 부분이 미리 보기 기능을 위해 추가된 부분
 
 
package onj.board.dao;
 
import java.util.List;
 
import onj.board.model.BoardDTO;
 
import org.springframework.dao.DataAccessException;
 
 
public interface BoardDAO {
       //게시물 리스트 보기
       public List<BoardDTO> boardList() throws DataAccessException;
      
       //게시물 본문 미리보기
       public String preView(String seq) throws DataAccessException;
}
 
 
[SpringBoardDAO.java]
 
소스 코드 빨강색 부분이 미리 보기 기능을 위해 추가된 부분
 
 
package onj.board.dao;
 
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
 
import javax.sql.DataSource;
 
import onj.board.model.BoardDTO;
 
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
 
public class SpringBoardDAO implements BoardDAO {
       private JdbcTemplate jdbcTemplate;
 
       public void setDataSource(DataSource dataSource) {
             this.jdbcTemplate = new JdbcTemplate(dataSource);
       }
 
       // /게시판 전체 리스트 보기(list.html)
       public List<BoardDTO> boardList() throws DataAccessException {
             List<BoardDTO> boardList = null;
 
             String sql = "select * from board";
 
             boardList = jdbcTemplate.query(sql, new RowMapper() {
                    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                           BoardDTO board = new BoardDTO();
 
                           board.setSeq(rs.getInt("seq"));
                           board.setName(rs.getString("name"));
                           board.setPasswd(rs.getString("passwd"));
                           board.setTitle(rs.getString("title"));
                           board.setContent(rs.getString("content"));
                           board.setFileName(rs.getString("filename"));
                           board.setDate(rs.getString("regdate"));
                           board.setReadCount(rs.getInt("readcount"));
                           board.setReply(rs.getInt("reply"));
                           board.setReply_step(rs.getInt("reply_step"));
                           board.setReply_level(rs.getInt("reply_level"));
 
                           return board;
                    }
             });
 
             return boardList;
       }
 
       // 게시물 본문내용 미리보기(/preView) ß 추가된 부분
       public String preView(String seq) throws DataAccessException {
             String sql = "select * from board where seq = ?";
 
             String preContent = (String) jdbcTemplate.queryForObject(sql,
                           new Object[] { seq }, new RowMapper() {
                                 public Object mapRow(ResultSet rs, int rowNum)
                                              throws SQLException {
                                        return rs.getString("content");
                                 }
                           });
             return preContent;
       }
}
 
 
 
 
6.  service 클래스를 만들어 보자.
 
새로 추가되는 클래스가 BoardServiceHelper인데 ㅅ블릿에서 스프링의 boardService 인스턴스를 취하기 위해 클래스를 이용하는데 BoardServiceHelper 내에는 간단히 web.xml에서 정의 boardService 자바 빈을 취득해 자신을 CALL 서블릿으로 BoardService  타입의 BoardServiceImple 객체를 리턴한다.
 
 
[BoardServiceHelper.java]
 
package onj.board.service;
 
import javax.servlet.ServletContext;
 
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
 
public class BoardServiceHelper {
       public static BoardService getBoardService(ServletContext ctx) {
             WebApplicationContext wac = WebApplicationContextUtils
                                               .getRequiredWebApplicationContext(ctx);
             //boardConfig.xml 정의된 boardService 빈을 리턴
             // 부분은 게시물 미리보기 서블릿(ContentPreview)에서 스프링의 인스턴스를 얻을 이용
             return (BoardService) wac.getBean("boardService");
       }
}
 
 
 
[BoardService.java]
 
 
소스 코드 빨강색 부분이 미리 보기 기능을 위해 추가된 부분
 
 
package onj.board.service;
 
import java.util.List;
import onj.board.model.BoardDTO;
 
/*
 * 게시판에서 구현할 기능을 인터페이스로 정의
 */
public interface BoardService {
       //게시판 리스트 보기
       public List<BoardDTO> boardList();     
      
       //게시물 미리보기
       public String preView(String seq);
}
 
 
 
 
[SpringServiceImpl.java]
 
소스 코드 빨강색 부분이 미리 보기 기능을 위해 추가된 부분
 
 
 
package onj.board.service;
 
import java.util.List;
import onj.board.dao.BoardDAO;
import onj.board.model.BoardDTO;
 
public class BoardServiceImpl implements BoardService {
    private BoardDAO boardDAO;
   
    public void setBoardDAO(BoardDAO boardDAO) {
        this.boardDAO = boardDAO;
    }
   
    //게시물 리스트 보기
    public List<BoardDTO> boardList() {
        return boardDAO.boardList();
    }
   
    //게시물 본문 내용 미리보기
    public String preView(String seq) {
        return boardDAO.preView(seq);
    }
   
   
}
 
 
7.     이번에는 미리 보기 기능의 핵심기능을 구현하는 서블릿을 만들자.
 
이 서블릿에서는 스프링 프레임워크의 자바 빈, web.xml에서 boardService로 정의된 BoardService 타입의 BoardServiceImple 객체를 취하기 위해 BoardServiceHelper를 이용했다.
 
 [ContentPreview.java]
 
package onj.board.ajaxpreview;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import onj.board.service.BoardService;
import onj.board.service.BoardServiceHelper;
 
//Servlet3.0이상, Tomcat7 이상에서는 애노테이션으로 서블릿 정의가 가능하다.
//@WebServlet(urlPatterns = "/preView")
public class ContentPreview extends HttpServlet {
       protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
             String seq = req.getParameter("seq");
            
             req.setCharacterEncoding("utf-8");
             res.setContentType("text/html; charset=utf-8");
             res.setHeader("Cache-Control""no-cache");
                   
             BoardService boardService = BoardServiceHelper.getBoardService(getServletContext());
                   
             PrintWriter out = res.getWriter();     
             out.println("<pre>" + boardService.preView(seq) + "<pre>");
       }     
}
 
8.     작성된 기능 확인 및 이클립스 구조확인
 
 
 
:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?XML:NAMESPACE PREFIX = V /><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f><o:lock v:ext="edit" aspectratio="t"></o:lock>
 
 







현재까지 만들어진 이클립스 구조
(게시판 리스트보기 + 게시물 본문내용 미리 보기)
 

댓글 없음:

댓글 쓰기