1.创建一个普通的springboot-web项目,导入相关的依赖。
<!--启动 -->
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--测试-->
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--springboot-webscoket整合-->
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--保证样式版本唯一-->
<dependency>
<groupId></groupId>
<artifactId>webjars-locator-core</artifactId>
<version>0.35</version>
</dependency>
<!--引入wsockjs-->
<dependency>
<groupId></groupId>
<artifactId>sockjs-client</artifactId>
<version>1.1.2</version>
</dependency>
<!--引入websocket-->
<dependency>
<groupId></groupId>
<artifactId>stomp-websocket</artifactId>
<version>2.3.3-1</version>
</dependency>
<!--引入jquery-->
<dependency>
<groupId></groupId>
<artifactId>jquery</artifactId>
<version>3.3.1-1</version>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--springsecurity-->
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.配置thymeleaf
在添加
=classpath:/templates/
=.html
-type=text/html
=UTF-8
3.配置websocket
<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)更好的二进制支持以及更好的压缩效果
<2>.配置
1.添加主配置类
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
("/topic");
("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
("/chat").withSockJS();
}
}
1>.自定义WebSocketConfig继承自WebSocketMessageBrokerConfigurer进行WebSocket配置,然后通过@EnableWebSocketMessageBroker注解开启了WebSocket消息代理
2>.("/topic")表示设置消息代理的前缀,即如果消息的前缀是”/topic”,就会将消息转发给代理(broker),再由消息代理将消息广播给当前连接的客户端(通俗的讲就后台向前台发送消息的地址要加上/topic前缀)
3>.("/app")表示配置一个或多个前缀,通过这些前缀过滤出需要被注解方法处理的消息(通俗的讲就前台向后台发送消息的地址要加上/app前缀)
4>.("/chat").withSockJS()表示定义一个前缀为”/chat”的edPoint,并开启sockjs支持,sockjs可以解决浏览器对WebSocket的兼容性问题,客户端将通过这里配置的URL来建立WebSocket连接(确切的说就是通过/chat进行连接后台)
2.添加controller
@RestController
public class GreetingController {
@Autowired
SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/hello")
public void greeting(Message message)throws Exception{
("/topic/greetings","您好");
}
}
SimpMessagingTemplate 代理对象,服务器向前端用户发送消息。
3.前端代码
<script>
var stompClient = null;//SockJS服务器和用户连接对象
function connect() {
var socket = new SockJS('/chat');// 连接服务器
stompClient = (socket);// 初始化
({}, function(frame) {
('/topic/greetings', function(greeting) {// 获取服务器端发送过来的消息
alert(());
});
});
}
function disconnect() {// 关闭连接
if (stompClient !== null) {
();
}
}
// 前端向后端发送信息
("/app/hello", {}, ({
'name' : $("#name").val(),
'content' : $("#content").val()
}));
</script>
主要用到SockJS对象,有初始化建立连接,发送,接收消息,还有断开连接等方法。
4.配置springsecurity
1.主配置类
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Bean// 密码加密
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 密码加密过:123
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
()
.withUser("齐**")
.password("$2a$10$")
.roles("admin")
.and()
.withUser("辛**")
.password("$2a$10$")
.roles("user")
.and()
.withUser("李**")
.password("$2a$10$")
.roles("user")
.and()
.withUser("岳**")
.password("$2a$10$")
.roles("user")
.and()
.withUser("尚**")
.password("$2a$10$")
.roles("user");
}
// 任何请求毒药进行授权认证才能访问
@Override
protected void configure(HttpSecurity http) throws Exception {
()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
}
类
@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=();
(from);
((), "/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./13501268/2403079?source=dra