学习背景
第一步:配置Spring
<properties>
<spring.version>4.0.0.RELEASE</spring.version>
</properties>
<dependencies>
<!--spring MVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--spring测试框架-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!--spring数据库操作库-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<!--spring websocket库-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<!--jackson用于json操作-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.2</version>
</dependency>
<!--使用阿里的连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.4</version>
</dependency>
<!--mysql connector-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
</dependencies>
Spring的配置我就不一一贴出来了,可以去github看,地址我会贴在下面。
第二步:配置WebSocket
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer{
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//添加这个Endpoint,这样在网页中就可以通过websocket连接上服务了
registry.addEndpoint("/coordination").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
System.out.println("服务器启动成功");
//这里设置的simple broker是指可以订阅的地址,也就是服务器可以发送的地址
/**
* userChat 用于用户聊天
*/
config.enableSimpleBroker("/userChat");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void configureClientInboundChannel(ChannelRegistration channelRegistration) {
}
@Override
public void configureClientOutboundChannel(ChannelRegistration channelRegistration) {
}
}
可以看到,在类中必须实现这四个方法。暂且只需要用到前两个,所以我来介绍一下,前两个方法中代码的意义。
registry.addEndpoint("/coordination").withSockJS();
我们加了一个叫coordination的连接点,在网页上我们就可以通过这个链接来和服务 器的WebSocket连接了。但是后面还有一句withSockJs,这是什么呢?SockJs是一个WebSocket的通信js库,Spring对 这个js库进行了后台的自动支持,也就是说,我们如果使用SockJs,那么我们就不需要对后台进行更多的配置,只需要加上这一句就可以了。
config.enableSimpleBroker("/userChat");
config.setApplicationDestinationPrefixes("/app");
首先,定义了一个连接点叫userChat,从名字可以看的出,最后我会做一个聊天的例子。然后,设置了一个应用程序访问地址的前缀,目的估计是为了和其他的普通请求区分开吧。也就是说,网页上要发送消息到服务器上的地址是/app/userChat。
第三步:配置Browser端
var socket = new SockJS('/coordination');
var stompClient = Stomp.over(socket);
stompClient.connect('', '', function (frame) {});
但是连接上了服务器,却没有进行任何的操作,所以下一步,我们要在服务器端撰写响应和数据处理代码
实现目标
第一步:聊天实现原理
public class UserChatCommand {
private String name;
private String chatContent;
private String coordinationId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getChatContent() {
return chatContent;
}
public void setChatContent(String chatContent) {
this.chatContent = chatContent;
}
public String getCoordinationId() {
return coordinationId;
}
public void setCoordinationId(String coordinationId) {
this.coordinationId = coordinationId;
}
@Override
public String toString() {
return "UserChatCommand{" +
"name='" + name + '\'' +
", chatContent='" + chatContent + '\'' +
", coordinationId='" + coordinationId + '\'' +
'}';
}
}
通过这个bean来接收到web端发送的消息,然后在服务端转发,接下来就是转发的逻辑了,不过首先需要介绍一下Spring WebSocket的一个annotation。
/**
* WebSocket聊天的相应接收方法和转发方法
*
* @param userChat 关于用户聊天的各个信息
*/
@MessageMapping("/userChat")
public void userChat(UserChatCommand userChat) {
//找到需要发送的地址
String dest = "/userChat/chat" + userChat.getCoordinationId();
//发送用户的聊天记录
this.template.convertAndSend(dest, userChat);
}
怎么这么简单?呵呵,能够这么简单的实现后台代码,全是Spring的功劳。首先,我们约定好发送地址的规则,就是chat后面跟上之前发送过来的id, 然后通过这个“template”来进行转发,这个“template”是Spring实现的一个发送模板 类:SimpMessagingTemplate,在我们定义controller的时候,可以在构造方法中进行注入:
@Controller
public class CoordinationController {
......
//用于转发数据(sendTo)
private SimpMessagingTemplate template;
<pre name="code" class="java"> @Autowired
public CoordinationController(SimpMessagingTemplate t) {
template = t;
}
.....
}
现在就已经将用户发送过来的聊天信息转发到了一个约定的空间内,只要web端的用户订阅的是这个空间的地址,那么就会收到转发过来的json。现在来看看web端需要做什么吧。

//发送聊天信息
function sendName() {
var input = $('#chat_input');
var inputValue = input.val();
input.val("");
stompClient.send("/app/userChat", {}, JSON.stringify({
'name': encodeURIComponent(name),
'chatContent': encodeURIComponent(inputValue),
'coordinationId': coordinationId
}));
}
其中,name和coordinationId是相应的用户信息,可以通过ajax或者jsp获取,这里就不多说了。
根据之前的约定,可以得到订阅的地址是'/coordination /coordination' + coordinationId,所以我们订阅这个地址就可以了,当订阅成功后,只要后台有转发消息,就会调用第二个方法,并且,将后台传过来的消息体作为 参数。所以订阅的方法如下
//用户聊天订阅
stompClient.subscribe('/userChat/chat' + coordinationId, function (chat) {
showChat(JSON.parse(chat.body));
});
将消息体转为json,再写一个显示聊天信息的方法就可以了,显示聊天信息的方法不再解释,如下:
//显示聊天信息
function showChat(message) {
var response = document.getElementById('chat_content');
response.value += decodeURIComponent(message.name) + ':' + decodeURIComponent(message.chatContent) + '\n';
}
因为之前处理中文问题,所以发到后台的数据是转码了的,从后台发回来之后,也需要将编码转回来。