org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-websocket
org.webjars
webjars-locator-core
0.35
org.webjars
sockjs-client
1.1.2
org.webjars
stomp-websocket
2.3.3-1
org.webjars
jquery
3.3.1-1
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-security
在application.properties添加
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.encoding=UTF-8
<1>.WebSocket简介
WebSocket是一种在单个TCP连接上进行双全工通信的协议,已被W3C定为标准,使用WebSocket可以使得客户端和服务器之间的数据交换变得更加简单,他允许服务端主动向客户端推送数据,在WebSocket协议中,浏览器和服务端只需要完成一次握手,两者之间就可以建立持久性的连接,并进行双向数据传输
WebSocket使用了HTTP/1.1的协议升级特性,一个WebSocket请求首先使用非正常的HTTP请求以特定的模式访问一个URL,这个URL有两种模式,分别是ws和wss,对应HTTP协议中的HTTP以及HTTPS,在请求头有一个Connection:Upgrade字段,表示客户端想要对协议进行升级,另外还有一个Upgrade:websocket字段,表示客户端想要将请求协议升级为WebSocket协议,这两个字段共同告诉服务器要将连接升级为WebSocket这样一个双全工协议,如果服务端同意协议升级,那么在握手完成之后,文本消息或者其他二进制的消息就可以同时在两个方向上进行发送,而不需要关闭和重新连接,此时的客户端可服务端的关系是对等的,他们可以互相向对方主动发送消息,和传统的解决方案相比,WebSocket具有如下特点:
(1)WebSocket使用时需要先创建连接,这使得WebSocket成为一种有状态的协议,在之后的通行过程中可以省略部分状态信息(例如身份认证等)
(2)WebSocket连接在端口80(ws)或者443(wss)上连接,与HTTP使用的端口相同,这样基本所有的防火墙都不会阻止WebSocket的连接
(3)WebSocket使用HTTP协议进行握手,因此可以直接集成到网络浏览器和HTTP服务器中,不需要额外的成本
(4)心跳消息(ping和pong)将被反复推送,保持WebSocket一致处于活跃状态
(5)使用该协议,当消息启动或者到达时,服务端和客户端都可以知道
(6)Websocket连接关闭时将发送一个特殊的关闭消息
(7)WebSocket支持跨域,可以避免Ajax的限制
(8)HTTP规范要求浏览器将并发连接限制为每个主机名两个连接,但是当我们使用WebSocket的时候,当握手完成后,该限制就不存在了,因为此时的连接已经不再是HTTP连接了
(9)WebSocket协议支持扩展,用户可以扩展协议,实现部分自定义的子协议
(10)更好的二进制支持以及更好的压缩效果
1.添加主配置类
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").withSockJS();
}
}
2.添加controller
@RestController
public class GreetingController {
@Autowired
SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/hello")
public void greeting(Message message)throws Exception{
simpMessagingTemplate.convertAndSend("/topic/greetings","您好");
}
}
SimpMessagingTemplate 代理对象,服务器向前端用户发送消息。
3.前端代码
主要用到SockJS对象,有初始化建立连接,发送,接收消息,还有断开连接等方法。
1.主配置类
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Bean// 密码加密
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 密码加密过:123
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("齐**")
.password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq")
.roles("admin")
.and()
.withUser("辛**")
.password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq")
.roles("user")
.and()
.withUser("李**")
.password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq")
.roles("user")
.and()
.withUser("岳**")
.password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq")
.roles("user")
.and()
.withUser("尚**")
.password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq")
.roles("user");
}
// 任何请求毒药进行授权认证才能访问
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
}
2.controller类
@RestController
public class GreetingController {
@Autowired
SimpMessagingTemplate simpMessagingTemplate;
/**
* 消息群发
* @param message
* @return
* @throws Exception
*/
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Message greeting(Message message) throws Exception {
return message;
}
/**
* 点对点发送
* @param principal
* @param chat
* @throws Exception
*/
@MessageMapping("/chat")
public void chat(Principal principal, Chat chat) throws Exception {
String from=principal.getName();
chat.setFrom(from);
simpMessagingTemplate.convertAndSendToUser(chat.getTo(), "/queue/chat", chat);;
}
}
1)群发消息依然使用@SendTo来实现,点对点则用SimpMessagingTemplate(单发消息)来实现
2)@MessageMapping("/chat")表示来自”/app/chat”路径的消息将被chat方法处理,chat方法的第一个参数Principal可以用来获取当前登录用户的信息,第二个参数则是客户端发送来的消息
3)在chat方法中,首先获取当前登录用户的用户名,设置给chat对象的from属性,再将消息发送出去,发送的目标就是chat的to属性
4)消息发送使用的方法是convertAndSendToUser,该方法内部调用了convertAndSend方法,并对消息路径做了处理(单发消息),chat可以换成任意的object对象,用于存储消息。
参考文章:https://blog.51cto.com/13501268/2403079?source=dra