2017년 7월 14일 금요일

WebSocket을 이용하여 실시간 답글 달기


실시간 업테이트를 위한 라이브러리 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    <properties>
        <java-version>1.6</java-version>
        <org.springframework-version>4.1.1.RELEASE</org.springframework-version>
        <org.aspectj-version>1.6.10</org.aspectj-version>
    </properties>
// 현재 스피링은 4.1.1.RELEASE 버전을 확인 하고 spring web-socket 버전과 일치하게
// jason은 스프링과 관련 된것이 아니라서 의존성이 없다. 
// 하지만 ${org.springframework-version} 라고 붙은것은 스프링과 버전을 맞춰서 넣어야된다.
//----------------------------중략-------------------------------
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>${org.springframework-version}</version>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20160212</version>
        </dependency>
        
cs


WebSocket을 사용하기 위해 webINF - appservlet - servletcontext XML 추가 설정

1. beans:bean 태그 안에
    <websocket:handlers>
        <websocket:mapping path="/wsserver" handler="serverHandler"/>
    </websocket:handlers>
추가 해주고 id랑 class도 밑에와 같이 추가
2. xml은 자동 import가 안되기 때문에 제일 위 1라인 쪽에 가서
xmlns:websocket="http://www.springframework.org/schema/websocket" 추가후
밑에 schemaLocation 에도
http://www.springframework.org/schema/websocket 
http://www.springframework.org/schema/websocket/spring-websocket.xsd

추가해준다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    
    xmlns:websocket="http://www.springframework.org/schema/websocket"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd">
//-----------------중략-------------------
    <websocket:handlers>
        <websocket:mapping path="/wsserver" handler="serverHandler"/>
    </websocket:handlers>
    <beans:bean id="serverHandler" class="com.ds.webSocket.WEBSocketServer" />
cs


환경설정을 마쳤으면 새로운 패키지를 만들고 새 클래스를 작성 해주자

1
2
3
4
5
6
//WEBSocketServlet 
public class WEBSocketServer extends TextWebSocketHandler{
    private List<WebSocketSession> clientList // clientList.size가 되면 현재 접속된 사람의 숫자
         = new ArrayList<WebSocketSession>();
cs

새클래스를 만들고  TextWebSocketHandler를 상속한다
ArrayList로 생성자를 만들어 주고 WebSocketSession 타입인 List를 만든다.

상속한 클래스를 보면 여러 클래스가 존재하는데 필요한 클래스들을 불러
오버라이딩 한다.


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
    @Override
    // 접속할때 마다 추가
    public void afterConnectionEstablished(WebSocketSession session)
throws Exception {
        
        super.afterConnectionEstablished(session);
        clientList.remove(session);
    }
    
    @Override
    //나갈때 마다 삭제
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status)
throws Exception {
        
        super.afterConnectionClosed(session, status);
        clientList.add(session);
    }
    @Override
//웹 소켓으로부터 메시지가 오면 호출되는 이벤트
    public void handleMessage(WebSocketSession session,
WebSocketMessage<?> message) throws Exception {        
        super.handleMessage(session, message);
        
        String msg = message.getPayload().toString();
        
        for(int i=0; i<clientList.size(); i++){
            WebSocketSession tmp = clientList.get(i);
            if(tmp != null){
            tmp.sendMessage(new TextMessage(msg));
            }
        }
        
    }
cs




해당 화면과 같이 폼 태그를 해준다.

1
2
3
4
5
6
7
8
9
10
11
//JSP 
<form action="p2_boardreply?no=${board.board_no}" method="post">
    <input type="hidden" name="no" value="${board.board_no}"/>
        <textarea rows="6" id="txt_reply" name="content></textarea>
        
    <input type="submit" id = "btn_reply" class="btn btn-success" value="답글"/>
</form>    
cs

자바스크립트 작성 하기

스크립트 안 onmessage 의 두 구문 중 하나만 써도 똑같은 결과가 나온다.

$('#reply_list').prepend('<tr><td>'+msg.data+'</td></tr>');

location.reload();



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
32
//자바 스크립트 
<script src="resources/js/jquery.js" type="text/javascript"></script>
    <script src="resources/js/bootstrap.min.js" type="text/javascript"></script>
    <script>
    $(document).ready(function(){
        var host="ws://192.168.0.163:8080/hss1/wsserver";
        var socket = new WebSocket(host);
        
        socket.onopen= function(){
            //alert('서버 접속 성공');
        };
        
        socket.onmessage = function(msg){
        //    alert('받은 메시지:'+ msg.data);
        };
        
        socket.onclose = function(){
            alert('접속종료');
        };
        
        socket.onmessage = function(msg){
            //$('#reply_list').prepend('<tr><td>'+msg.data+'</td></tr>');
            location.reload();  //F5
        }
        
        $('#btn_reply').click(function(){
            var txt = $('#txt_reply').val();
            socket.send(txt);
        });
    });
    </script>
cs

지금까지 했다면  답글이라는 버튼을 눌렀을때 글이 작성됨
하지만 아직 DB에 입력시켜 놓지 않았기에 소캣종료시 다시 글이 다 사라진다.
작성된 글을 DB로 보내어 영구 보존 하도록 하게 하자

1
2
3
4
5
6
7
8
    //XML
    
    <insert id ="addreply" parameterType="Board">
        INSERT INTO  p2_reply
            (reply_no, board_no, reply_content, reply_date) 
        VALUES
            (#{reply_no},#{board_no},#{reply_content}, NOW())
    </insert>
cs

1
2
3
4
    //DAO

    public int addReply(Board b){
        return sqlSession.insert("P2.addreply",b);
    }
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
   //BoardController
@RequestMapping(value = "/p2_boardreply", method=RequestMethod.POST)
public String p2_reply(Model model,
                    @RequestParam("no")int no,
                    @RequestParam("content")String co){
    System.out.println(no);
    Board b = new Board();
    b.setBoard_no(no);            
    b.setReply_content(co);    
    
    p2DAO.addReply(b);
                
    return "redirect:p2_boardcontent?no="+no;
}
cs


해당 작업이 끝나면 답글 내용이 데이터 베이스에 입력 된다.
이제 입력한 값을 가져와 boardcontent.jsp에 띄우자

1
2
3
4
5
    //XML
    
    <select id="getreplydALL" parameterType= "int" resultType="Board">
        SELECT * FROM p2_reply WHERE board_no = #{board_no} ORDER BY reply_no DESC; 
    </select>
cs

이번에는 귀찮아서 그냥 새로운 VO를 만들지 않고 기존에 있는 Board vo에 필요한 부분만 새로 추가 해서 넣었다.


1
2
3
4
5
6
7
8
9
10
11
12
package com.ds.vo;
public class Board {
    
    private int board_no = 0;
    private String board_type = null;
    private String board_title = null;
    private String board_content = null;
    private String board_date = null;
    private int reply_no = 0;
    private String reply_content = null;
    private String reply_date = null;
cs

컨트롤러에
List<Board> list = p2DAO.getReply(no); 

model.addAttribute("list", list); 까지 추가 시켜주면 끝.

1
2
3
4
5
6
7
8
9
10
//Controller
@RequestMapping(value = "/p2_boardcontent", method = RequestMethod.GET)
public String p2_board(Model model, @RequestParam("no"int no) {
    Board board = p2DAO.getBoardContent(no);
    List<Board> list = p2DAO.getReply(no);
    model.addAttribute("board",board);
    model.addAttribute("list", list);
    return "p2/boardcontent";
}
cs


마지막 실행화면



















댓글 없음:

댓글 쓰기