SpringBoot 搭建簡單聊天室(queue 點對點)javascript
一、引用 SpringBoot 搭建 WebSocket 連接html
http://www.javashuo.com/article/p-gyrgklmr-hh.htmljava
二、整合Spring Securityjquery
package com.example.demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { /** * 簡單解釋一下 * 頁面(login、ws)不設置攔截 * 登陸頁面login * 登錄成功頁面chat * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/","/login","/ws").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/chat") .permitAll() .and() .logout() .permitAll(); } /** * 添加兩個用戶 * 帳號:wfy 密碼:wfy * 帳號:wisely 密碼:wisely * 角色:USER * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .passwordEncoder(new MyPasswordEncoder()) .withUser("wfy").password("wfy").roles("USER") .and() .withUser("wisely").password("wisely").roles("USER"); } /** * 靜態資源路徑不設置攔截 * @param web * @throws Exception */ @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/resources/static/**"); } }
三、配置WebSocketweb
package com.example.demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { /** * 配置連接端點 * @param registry */ @Override public void registerStompEndpoints(StompEndpointRegistry registry){ registry.addEndpoint("/endpointWisely").withSockJS(); registry.addEndpoint("/endpointChat").withSockJS(); } /** * 配置消息代理 * @param registry */ @Override public void configureMessageBroker(MessageBrokerRegistry registry){ registry.enableSimpleBroker("/topic","/queue"); } }
四、書寫控制器spring
package com.example.demo.controller; import com.example.demo.PoJo.WiselyMessage; import com.example.demo.PoJo.WiselyResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Controller; import java.security.Principal; @Controller public class WsController { /** * 服務器 推送數據 */ @Autowired private SimpMessagingTemplate messagingTemplate; /** * MessageMapping 相似於 RequestMapping * SendTo 訂閱地址 相似於 訂閱一個URL (個人理解就是 調用了這個方法 在返回的時候會給訂閱該url的地址發送數據) * @param message * @return * @throws Exception */ @MessageMapping("/welcome") @SendTo("/topic/getResponse") public WiselyResponse say(WiselyMessage message) throws Exception { Thread.sleep(3000); return new WiselyResponse("Welcome," + message.getName() + "!"); } /** * 經過convertAndSendToUser 向指定用戶發送消息 * @param principal * @param msg */ @MessageMapping("/chat") public void handleChat(Principal principal,String msg){ if("wfy".equals(principal.getName())){ messagingTemplate.convertAndSendToUser("wisely","queue/notifications",principal.getName() + "-send : "+ msg ); }else{ messagingTemplate.convertAndSendToUser("wfy","queue/notifications",principal.getName() + "-send : "+ msg ); } } }
五、書寫頁面(chat)服務器
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <meta charset="UTF-8" /> <head> <title>Home</title> <script th:src="@{sockjs.min.js}"></script> <script th:src="@{stomp.min.js}"></script> <script th:src="@{jquery.js}"></script> </head> <body> <p> 聊天室 </p> <form id="wiselyForm"> <textarea rows="4" cols="60" name="text"></textarea> <input type="submit"/> </form> <script th:inline="javascript"> $('#wiselyForm').submit(function(e){ e.preventDefault(); var text = $('#wiselyForm').find('textarea[name="text"]').val(); sendSpittle(text); }); var sock = new SockJS("/endpointChat"); //1 var stomp = Stomp.over(sock); stomp.connect('guest', 'guest', function(frame) { stomp.subscribe("/user/queue/notifications", handleNotification);//2 }); function handleNotification(message) { $('#output').append("<b>Received: " + message.body + "</b><br/>") } function sendSpittle(text) { stomp.send("/chat", {}, text);//3 } $('#stop').click(function() {sock.close()}); </script> <div id="output"></div> </body> </html>
頁面(login)app
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> <meta charset="UTF-8" /> <head> <title>登錄頁面</title> </head> <body> <div th:if="${param.error}"> 無效的帳號和密碼 </div> <div th:if="${param.logout}"> 你已註銷 </div> <form th:action="@{/login}" method="post"> <div><label> 帳號 : <input type="text" name="username"/> </label></div> <div><label> 密碼: <input type="password" name="password"/> </label></div> <div><input type="submit" value="登錄"/></div> </form> </body> </html>
六、編寫視圖解析器socket
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry){
registry.addViewController("/ws").setViewName("/ws");
registry.addViewController("/login").setViewName("/login");
registry.addViewController("/chat").setViewName("/chat");
}
}
七、記錄一個坑ide
1)、若是使用的是 Security5.0 以上會報錯 java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
解決辦法:
package com.example.demo.config; import org.springframework.security.crypto.password.PasswordEncoder; public class MyPasswordEncoder implements PasswordEncoder { @Override public String encode(CharSequence charSequence) { return charSequence.toString(); } @Override public boolean matches(CharSequence charSequence, String s) { return s.equals(charSequence.toString()); } }