LoginSignup
5

PrimeFaces WebSocket Ajaxタグを使用した簡易チャットプログラミング

Last updated at Posted at 2015-10-17

#最初に
PrimeFacesのタグを使用して簡易チャットを作成してみました。
NetBeansインストール方法はこちらを参照ください。
Projectの作成、PrimeFaces設定方法はこちらを参照下さい。
#環境
NetBeans 8.0.2
JavaSDK 1.8.0.25
PrimeFaces 5.0
GlassFish 4.1
#プログラムの作成
非同期表示が可能なチャットプログラムです。

  • チャットメッセージはBeanで保持し、ArrayListに追加します。
  • ページはDataTableタグでArrayListの内容を表示します。
  • メッセージの投稿を契機にWebSocketによるPush通知でDataTable表示を更新します。

WebSocketではメッセージの送受信は行わず、画面の更新契機通知のみに使用しています。これによりメッセージの規定やハンドリングは不要となり、シンプルなコードとなっています。

今回作成したコードは、JSFページが1ページとJavaクラスが4つになります。Javaクラスは以下の構成です。

クラス名 内容 Scope
Bb jsfページとのインターフェイス RequestScoped
ChatText 1回の投稿情報を格納する
ChatApp 投稿情報をArrayListに保存する AplicationScoped
ChatEndPoint Pushのエンドポイント

JSFページのコードです。

index.xhtml
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui">
    
    <h:head>
        <title>Chat</title>
    </h:head>
    <h:body>
        <h:form id="form">
            <h:panelGrid columns="3">
                <h:outputLabel value="お名前" />
                <h:inputText id="inputName" value="#{bb.mname}" />
                <h:outputLabel value="" />
                <h:outputLabel value="メッセージ" />
                <h:inputText id="inputMessage" value="#{bb.mtext}" />
                <h:commandButton value="Send" action="#{bb.sendText}" />
                
            </h:panelGrid>
            
            <h:dataTable id="dttable" value="#{chatApp.MChat}" var="row">
                <h:column>
                    <h:outputText value="#{row.MCal}" />
                </h:column>
                 <h:column>
                     <h:outputText value="#{row.MName}" />
                </h:column>
                 <h:column>
                     <h:outputText value="#{row.MText}" />
                </h:column>                
            </h:dataTable>
           
        </h:form>

        <p:socket channel="/chat">
            <p:ajax event="message" update=":form:dttable" />
        </p:socket>

    </h:body>
</html>

入力欄はPanelタグにまとめています。
socketタブでWebSocketのチャネルを指定しています。チャネルはEndpointBeanと一致させる必要が有ります。ajaxタグでメッセージ受信時にdatatableのみ再描画する定義をしています。

以下はJavaのコードです。

Bb.java
package beans;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.primefaces.push.EventBus;
import org.primefaces.push.EventBusFactory; 

@Named
@RequestScoped
public class Bb {

    private String Mtext;    

    public String getMtext() {
        return Mtext;
    }

    public void setMtext(String Mtext) {
        this.Mtext = Mtext;
    }
    
    private String Mname;

    public String getMname() {
        return Mname;
    }

    public void setMname(String Mname) {
        this.Mname = Mname;
    }
    
    @Inject
    private ChatApp cha; //ApricationScoped bean にアクセスするためDIします。 

    public void sendText(){
        
        cha.setChat(Mtext, Mname);

        EventBus eventBus = EventBusFactory.getDefault().eventBus();
        eventBus.publish("/chat", "Notify");
        Mtext="";
    }
    
}

actionメソッドのsendTextでは入力データをAplicationScopeのChatAppに設定した後、WebSocket通信を行います。具体的にはFactoryからeventBusを取得してpublishメソッドを使用します。

ChatText.java
package beans;

import java.text.SimpleDateFormat;
import java.util.Calendar;

public class ChatText {

    String MText;
    String MCal;
    String MName;

    public ChatText(String MText, String MName) {
        this.MText = MText;
        this.MName = MName;
        
        Calendar cal;
        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd hh:mm:ss SSS");        
        cal=Calendar.getInstance();
        
        this.MCal=sdf.format(cal.getTime());
        
    }

    public String getMText() {
        return MText;
    }


    public String getMCal() {
        return MCal;
    }


    public String getMName() {
        return MName;
    }

    
} 

1メッセージを格納するBeanです。メッセージ発信時刻をコンストラクタで設定しています。

ChatApp.java
package beans;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;

@Named
@ApplicationScoped
public class ChatApp implements Serializable{
   
    private final List<ChatText> MChat = new ArrayList();
    
    public List<ChatText> getMChat() {
        return MChat;
    }  
    
    public void setChat(String pText,String pName){        
        MChat.add(0,new ChatText( pText,pName ));
    }
       
}

AplicationScopeのbeanですが、ArrayListを保持しているだけです。
ArrayListのゲッターと、メッセージをセットするメソッドのみです。

ChatEndPoint.java
package beans;

import org.primefaces.push.annotation.OnMessage;
import org.primefaces.push.annotation.PushEndpoint;
import org.primefaces.push.impl.JSONEncoder;

@PushEndpoint("/chat")
public class ChatEndPoint {
    
    @OnMessage(encoders = {JSONEncoder.class})
    public String onMessage(String data) {
        return data;
    }
    
}

EndPointのbeanです。ここでWebSocketの終端で起こるイベントハンドラを実装します。
アノテーションでチャネル名を指定しており、OnMessageをオーバーライドしてencodersを指定しています。今回はWebSocket電文はダミーなのでencodersは省略できるかと思いましたが、OnMessageイベントが発火しませんでした。エラーにはなりませんでしたが必須のようです。

#実行画面
image

2枚のブラウザで相互表示が確認できます。

#おしまい
プログラムとしてはすっきりしたコードに仕上がりましたがJSF(CDIも含めですが)には未だ慣れず、製造には3日程度かかってしまいました。コンパイル、デプロイができた後に引っかかることが結構あります。時間の有る今のうちに慣れておきたいと思ってきます。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5