在 Spring Boot 中, SimpMessagingTemplate
已经配置好,开发者直接注入进来即可。使用 SimpMessagingTemplate
,开发者可以在任意地方发送消息到 broker ,也可以发送消息给某一个用户,这就是点对点的消息发送。
1、创建项目,添加依赖
<!--Web Socket 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>sockjs-client</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>stomp-websocket</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2、配置 Spring Security
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 功能描述:在该方法中配直两个用户,一个用户名是 admin ,密码是 123456,具备两个角色 ADMIN 和 USER,另一个用户名是 wi-gang ,密码是 123456 ,具备一个角色 USER
* @author wi-gang
* @date 2022/1/23 11:28 下午
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq").roles("ADMIN")
.and()
.withUser("wi-gang").password("$2a$10$RMuFXGQ5AtH4wOvkUqyvuecpqUSeoxZYqilXzbz50dceRsga.WYiq").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
}
3、配置 WebSocketConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* 功能描述:自定义类配置 WebSocket
* @author wi-gang
* @date 2022/2/10 11:01 上午
*/
@Configuration
//开启 WebSocket 消息代理
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//定义一个前缀为"/chat"的 endpoint,并开启sockjs支持
//sockjs可以解决浏览器对 WebSocket 的兼容性问题,客户端通过这里配置的URL来建立 WebSocket 连接
registry.addEndpoint("/chat").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
//设置消息代理的前缀,即如果消息的前缀是"/topic",就会将消息转发给消息代理(broker),再由消息代理将消息广播给当前连接的客户端。在方法的基础上又增加了 broker 前缀 "/queue",方便对群发消息和点对点消息进行管理。
registry.enableSimpleBroker("/topic","/queue");
//配置一个或者多个前缀,通过这些前缀过滤出需要被注解方法处理的消息
//例如:前缀为"/app"的 destination 可以通过@MessageMapping注解的方法处理,而其他destination(例如"topic","/queue")将被直接交给broker处理。
registry.setApplicationDestinationPrefixes("/app");
}
}
4、配置controller
@RestController
public class TestController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/chat")
public void chat(Principal principal, Chat chat) {
String from = principal.getName();
chat.setFrom(from);
simpMessagingTemplate.convertAndSendToUser(chat.getTo(), "/queue/chat", chat);
}
}
class Chat {
private String to;
private String from;
private String content;
//省略get/set方法
}
代码解释:
@MessageMapping("/chat")
表示来自/app/chat
路径的消息将被 chat 方法处理。chat 方法的第一个参数Principal
可以用来获取当前登录用户的信息,第二个参数则是客户端发送来的消息。- 在 chat 方法中首先获取当前用户的用户名, 设置给 chat 对象的 from 属性,再将消息发送出去,发送的目标用户就是 chat 对象的 to 属性值。
5、创建在线聊天页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>单聊</title>
<!--引入外部的 JS 库,这些 JS 库在 pom.xml 文件中通过依赖加入进来-->
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/sockjs-client/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/stomp.min.js"></script>
<!--自定义js-->
<script src="/chat.js"></script>
</head>
<body>
<div id="chat">
<div id="chatsContent">
<div>
请输入聊天内容:
<input type="text" id="content" placeholder="聊天内容">
目标用户:
<input type="text" id="to" placeholder="目标用户">
<button id="send" type="button">发送</button>
</div>
</div>
</div>
</body>
</html>
在/resource/static
目录下创建chat.js
var stompClient = null;
//建立一个 WebSocket 连接,在建立 WebSocket 连接时,用户必须先输入用户名,然后才能建立连接
function connect() {
//使用 SockJS 建立连接,然后创建一个 STOMP 实例发起连接请求 在连接成功的回调方法中,
// 首先调用 setConnected(true);方法进行页面的设置,然后调用 STOMP 中的 subscribe 方法订阅服务端发送回来的消息,并将服务端发送来的消息展示出来(使用 showGreeting 方法)
var socket = new SockJS('/chat');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
stompClient.subscribe('/user/queue/chat', function (chat) {
showGreeting(JSON.parse(chat.body));
});
})
}
function sendMsg() {
stompClient.send("/app/chat", {},
JSON.stringify({
'content': $("#content").val(), 'to': $("#to").val()
}));
}
function showGreeting(message) {
console.log("message--->",message)
$("#chatsContent").append("<div>" + message.from + ":" + message.content + "</div>");
}
$(function () {
connect();
$("#send").click(function () {
sendMsg();
});
})
6、测试
在浏览器地址栏中输入 http://localhost:8080/chat.html
,首先会自动跳转到 Spring Security 的默认登录页面,分别使用开始配置的两个用户 admin/123
和 wi-gang/123
登录,登录成功后,就可以开始在线聊天了。