微人事第十一天:WebSocket实现单聊

上一篇博客我们介绍了在Spring Boot框架下使用WebSocket实现消息推送,消息推送是一对多,服务器发消息发送给所有的浏览器,这次我们来看看如何使用WebSocket实现消息的一对一发送,模拟的场景就是利用网页来实现两个人在线聊天。OK,那我们来看看这个要怎么实现。

#引入Spring Security并配置
由于这里涉及到多个用户之间互相传递消息的问题,涉及到的权限管理问题我使用Spring Security来处理,关于Spring Security的更多详细资料小伙伴们可以参考下面几个资料:

1.SpringMVC4零配置–SpringSecurity相关配置【SpringSecurityConfig】
2.spring security的原理及教程
3.spring security教程

OK ,关于Spring Security的更多话题这里不再多说,这里仅仅来说一下在我们自己的项目中如何使用Spring Security。
##引入Spring Security
引入方式很简单,直接在Maven中添加如下依赖:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
			<version>1.4.2.RELEASE</version>
		</dependency>

##配置Spring Security
配置方式也简单,新建类WebSecurityConfig,代码如下:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                //设置拦截规则
                .antMatchers("/")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                //开启默认登录页面
                .formLogin()
                //默认登录页面
                .loginPage("/login")
                //默认登录成功跳转页面
                .defaultSuccessUrl("/chat")
                .permitAll()
                .and()
                //设置注销
                .logout()
                .permitAll();
    }
	@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("lenve").password("111").roles("USER")
                .and()
                .withUser("sang").password("222").roles("USER");
    }
	@Override
    public void configure(WebSecurity web) throws Exception {
        //设置不拦截规则
        web.ignoring().antMatchers("/resources/static/**");
    }

关于这里的代码我做如下几点说明,

1.在configure(HttpSecurity http)方法中,我们首先设置拦截规则,设置默认登录页面以及登录成功后的跳转页面
2.在configure(AuthenticationManagerBuilder auth)方法中,我们定义两个用户,设置用户名、用户密码、用户角色等信息。
3.在configure(WebSecurity web)方法中设置静态资源不被拦截。

#配置WebSocket
WebSocket的配置和我们上篇博客中WebSocket的配置方式一致,如下:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
  	@Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        stompEndpointRegistry.addEndpoint("/endpointChat").withSockJS();
    }
	@Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/queue");
    }

 
 

    和上篇文章的WebSocket配置比起来,这里有两个变化:

    1.endpoint的名字变了,当然这个无所谓,取啥名字都行,关键是要和html文件中的对应上。
    2.消息代理换了

    其他都一模一样,小伙伴对这里有疑问可以查看上篇博客

    #配置控制器
    由于我这里只有两个用户,所以我在控制器里的处理尽可能简单一些,假如这条消息是由A用户发来的,那么毫无疑问这条消息要转发给B用户,如果这条消息是由B用户发来的,那么毫无疑问这条消息要转发给A,小伙伴们在使用的过程中可以根据具体的业务逻辑来灵活配置,我这里就直接硬编码,OK,我们来看看控制器的代码:

    @Controller
    public class WsController {
        @Autowired
        private SimpMessagingTemplate messagingTemplate;
    	@MessageMapping("/chat")
        public void handleChat(Principal principal, String msg) {
            if (principal.getName().equals("sang")) {
                messagingTemplate.convertAndSendToUser("lenve", "/queue/notifications", principal.getName() + "给您发来了消息:" + msg);
            }else{
                messagingTemplate.convertAndSendToUser("sang", "/queue/notifications", principal.getName() + "给您发来了消息:" + msg);
            }
        }
    }
    
     
     

    关于这一段代码,我说如下几点:

    1.SimpMessagingTemplate这个类主要是实现向浏览器发送消息的功能。
    2.在Spring MVC中,可以直接在参数中获取Principal,Principal中包含有当前用户的用户名。
    3.convertAndSendToUser方法是向用户发送一条消息,第一个参数是目标用户用户名,第二个参数是浏览器中订阅消息的地址,第三个参数是消息本身。

    #登录页面

    在src/main/resources/templates目录下新建login.html文件,内容如下:

    <!DOCTYPE html>
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
        <meta charset="UTF-8" />
        <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>
    
     
     

    这个一个非常普通的html页面,我就不再赘述了,注意form表单的提交位置。

    #聊天页面

    在src/main/resources/templates文件夹下新建文件chat.html文件,内容如下:

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8" />
        <title>聊天室</title>
        <script th:src="@{js/sockjs.min.js}"></script>
        <script th:src="@{js/stomp.js}"></script>
        <script th:src="@{js/jquery-3.1.1.js}"></script>
    </head>
    <body>
    <p>聊天室</p>
    <form id="sangForm">
        <textarea rows="4" cols="60" name="text"></textarea>
        <input type="submit" value="发送"/>
    </form>
    <script th:inline="javascript">
        $("#sangForm").submit(function (e) {
            e.preventDefault();
            var textArea = $("#sangForm").find('textarea[name="text"]');
            var text = textArea.val();
            sendSpittle(text);
            textArea.val('');
        });
        var sock = new SockJS("/endpointChat");
        var stomp = Stomp.over(sock);
        stomp.connect('guest','guest',function (frame) {
            stomp.subscribe("/user/queue/notifications", handleNotification);
        });
        function handleNotification(message) {
            $("#output").append("<b>Received: "+message.body+"</b><br/>")
        }
        function sendSpittle(text) {
            stomp.send("/chat", {}, text);
        }
        $("#stop").click(function () {
            sock.close();
        });
    </script>
    <div id="output"></div>
    </body>
    </html>
    

    这个页面也没有太多的难点,大部分知识点都和上文说的一样,有不懂的小伙伴可以查看上文,还是有几个小的知识点我再来说一下:

    1.stomp中的connect方法用来连接服务端,连接成功之后注册监听,在注册监听的时候,注册的地址/user/queue/notifications比WebSocket配置文件中的多了一个/user,这个/user是必不可少的,使用了它消息才会点对点传送。
    2.收到消息后在handleNotification方法中处理,实际上就是把收到的内容添加到id为output的div中

    OK,这里其他的知识点都比较简单,我就不再赘述了。

    • 1
      点赞
    • 2
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值