首先我們查看一下ServerEndpoint類源碼:
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
public @interface ServerEndpoint {
public String value();
public String[] subprotocols() default {};
public Class<? extends Decoder>[] decoders() default {};
public Class<? extends Encoder>[] encoders() default {};
public Class<? extends ServerEndpointConfig.Configurator> configurator() default ServerEndpointConfig.Configurator.class;
}
Encoders and Decoders(編碼器和解碼器):
WebSocket Api 提供了encoders 和 decoders用於 Websocket Messages 與傳統java 類型之間的轉換
An encoder takes a Java object and produces a representation that can be transmitted as a WebSocket message;
編碼器輸入java對象,生成一種表現形式,能夠被轉換成Websocket message
for example, encoders typically produce JSON, XML, or binary representations.
例如:編碼器通常生成json、XML、二進制三種表現形式
A decoder performs the reverse function; it reads a WebSocket message and creates a Java object.
解碼器執行相反的方法,它讀入Websocket消息,然后輸出java對象
編碼器編碼:
looks for an encoder that matches your type and uses it to convert the object to a WebSocket message.
利用RemoteEndpoint.Basic 或者RemoteEndpoint.Async的sendObject(Object data)方法將對象作為消息發送,容器尋找一個符合此對象的編碼器,
利用此編碼器將此對象轉換成Websocket message
代碼示例:可以指定為自己的一個消息對象
package com.zlxls.information;
import com.alibaba.fastjson.JSON;
import com.common.model.SocketMsg;
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
/**
* 配置WebSocket解碼器,用於發送請求的時候可以發送Object對象,實則是json數據
* sendObject()
* @ClassNmae:ServerEncoder
* @author zlx-雄雄
* @date 2017-11-3 15:47:13
*
*/
public class ServerEncoder implements Encoder.Text<SocketMsg> {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void init(EndpointConfig arg0) {
// TODO Auto-generated method stub
}
@Override
public String encode(SocketMsg socketMsg) throws EncodeException {
try {
return JSON.toJSONString(socketMsg);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "";
}
}
}
Then, add the encodersparameter to the ServerEndpointannotation as follows:
@ServerEndpoint(
value = "/myendpoint",
encoders = { ServerEncoder.class, ServerEncoder1.class }
)
解碼器解碼:
Decoder.Binary<T>for binary messages
These interfaces specify the willDecode and decode methods.
the container calls the method annotated with @OnMessage that takes your custom Java type as a parameter if this method exists.
package com.zlxls.information;
import com.common.model.SocketMsg;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
/**
* 解碼器執,它讀入Websocket消息,然后輸出java對象
* @ClassNmae:ServerDecoder
* @author zlx-雄雄
* @date 2017-11-11 9:12:09
*
*/
public class ServerDecoder implements Decoder.Text<SocketMsg>{
@Override
public void init(EndpointConfig ec){}
@Override
public void destroy(){}
@Override
public SocketMsg decode(String string) throws DecodeException{
// Read message...
return new SocketMsg();
}
@Override
public boolean willDecode(String string){
// Determine if the message can be converted into either a
// MessageA object or a MessageB object...
return false;
}
}
Then, add the decoderparameter to the ServerEndpointannotation as follows:
@ServerEndpoint(
value = "/myendpoint",
encoders = { ServerEncoder.class, ServerEncoder1.class },
decoders = {ServerDecoder.class }
)
處理錯誤:
To designate a method that handles errors in an annotated WebSocket endpoint, decorate it with @OnError:
/**
* 發生錯誤是調用方法
* @param t
* @throws Throwable
*/
@OnError
public void onError(Throwable t) throws Throwable {
System.out.println("錯誤: " + t.toString());
}
為一個注解式的端點指定一個處理error的方法,為此方法加上@OnError注解:
This method is invoked when there are connection problems, runtime errors from message handlers, or conversion errors when decoding messages.
當出現連接錯誤,運行時錯誤或者解碼時轉換錯誤,該方法才會被調用
指定端點配置類:
The Java API for WebSocket enables you to configure how the container creates server endpoint instances.
Websocket的api允許配置容器合適創建server endpoint 實例
You can provide custom endpoint configuration logic to:
Access the details of the initial HTTP request for a WebSocket connection
Perform custom checks on the OriginHTTP header
Modify the WebSocket handshake response
Choose a WebSocket subprotocol from those requested by the client
Control the instantiation and initialization of endpoint instances
To provide custom endpoint configuration logic, you extend the ServerEndpointConfig.Configurator class and override some of its methods.
繼承ServerEndpointConfig.Configurator 類並重寫一些方法,來完成custom endpoint configuration 的邏輯代碼
In the endpoint class, you specify the configurator class using the configurator parameter of the ServerEndpoint annotation.
代碼示例:
package com.zlxls.information;
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import javax.websocket.server.ServerEndpointConfig.Configurator;
/**
* 由於websocket的協議與Http協議是不同的,
* 所以造成了無法直接拿到session。
* 但是問題總是要解決的,不然這個websocket協議所用的場景也就沒了
* 重寫modifyHandshake,HandshakeRequest request可以獲取httpSession
* @ClassNmae:GetHttpSessionConfigurator
* @author zlx-雄雄
* @date 2017-11-3 15:47:13
*
*/
public class GetHttpSessionConfigurator extends Configurator{
@Override
public void modifyHandshake(ServerEndpointConfig sec,HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession=(HttpSession) request.getHttpSession();
sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
}
}
@OnOpen
public void open(Session s, EndpointConfig conf){
HandshakeRequest req = (HandshakeRequest) conf.getUserProperties().get("sessionKey");
}
@ServerEndpoint(
value = "/myendpoint",
configurator=GetHttpSessionConfigurator.class
)
不過要特別說一句:
HandshakeRequest req = (HandshakeRequest) conf.getUserProperties().get("sessionKey"); 目前獲取到的是空值。會報錯:java.lang.NullPointerException,這個錯誤信息,大家最熟悉不過了。
原因是:請求頭里面並沒有把相關的信息帶上
這里就需要實現一個監聽,作用很明顯:將所有request請求都攜帶上httpSession,這樣就可以正常訪問了
說明:注解非常簡單可以直接使用注解@WebListener,也可以再web.xml配置監聽
package com.zlxls.information;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
/**
* http://www.cnblogs.com/zhuxiaojie/p/6238826.html
* 配置監聽器,將所有request請求都攜帶上httpSession
* 用於webSocket取Session
* @ClassNmae:RequestListener
* @author zlx-雄雄
* @date 2017-11-4 11:27:33
*
*/
@WebListener
public class RequestListener implements ServletRequestListener {
@Override
public void requestInitialized(ServletRequestEvent sre) {
//將所有request請求都攜帶上httpSession
((HttpServletRequest) sre.getServletRequest()).getSession();
}
public RequestListener() {}
@Override
public void requestDestroyed(ServletRequestEvent arg0) {}
}