博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Boot系列20 Spring Websocket实现向指定的用户发送消息
阅读量:5941 次
发布时间:2019-06-19

本文共 6037 字,大约阅读时间需要 20 分钟。

概述

不同上文,本文我们介绍通过Spring websocket实现向特定的用户发送消息。 本文的内容如下: 1. 首先实现简单的登录功能,这里向特定用户发送消息的必要条件 2. 用户登录系统后,才可以登录websocket,并重写MyPrincipal 3. 实现向特定用户发送消息的功能 4. 测试

首先实现简单的登录功能,这是向特定用户发送消息的必要条件

TestMQCtl:控制类 提供模拟登录,登录成功后转到websocket页面

/**     * 模拟登录     */    @RequestMapping(value = "loginIn", method = RequestMethod.POST)    public String login(HttpServletRequest request, @RequestParam(required=true) String name, String pwd){        HttpSession httpSession = request.getSession();        // 如果登录成功,则保存到会话中        httpSession.setAttribute("loginName", name);        return "websocket/sendtouser/ws-sendtouser-rabbitmq";    }    /**     * 转到登录页面     */    @RequestMapping(value = "login", method = RequestMethod.GET)    public String loginPage(){        // 转到登录页面        return "websocket/sendtouser/login";    }    /**     * websocket页面     * @return     */    @RequestMapping(value="/broadcast-rabbitmq/index")    public String broadcastIndex(){        return "websocket/sendtouser/ws-sendtouser-rabbitmq";    }复制代码

login.jsp 简单的form表单,将请求提到loginIn,并转到ws-sendtouser-rabbitmq.jsp页面

用户名:

密码:

复制代码

ws-sendtouser-rabbitmq.jsp 连接websocket并订阅消息,这个jsp之前的文章已经介绍过了这里不详细描述。页面通过向/ws/icc/websocket启动websocket,然后订阅/user/topic/demo消息

复制代码

用户登录系统后,才可以登录websocket,并重写MyPrincipal

AuthHandshakeInterceptor AuthHandshakeInterceptor是HandshakeInterceptor 的子类。在websocket握手前判断,判断当前用户是否已经登录。如果未登录,则不允许登录websocket

@Componentpublic class AuthHandshakeInterceptor implements HandshakeInterceptor {    private static final Logger log = LoggerFactory.getLogger(AuthHandshakeInterceptor.class);    @Override    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map
attributes) throws Exception { HttpSession httpSession = getSession(request); String user = (String)httpSession.getAttribute("loginName"); if(StringUtils.isEmpty(user)){ log.error("未登录系统,禁止登录websocket!"); return false; } log.info("login = " + user); return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { } // 参考 HttpSessionHandshakeInterceptor private HttpSession getSession(ServerHttpRequest request) { if (request instanceof ServletServerHttpRequest) { ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request; return serverRequest.getServletRequest().getSession(false); } return null; }}复制代码

MyPrincipalHandshakeHandler MyPrincipalHandshakeHandler是DefaultHandshakeHandler 的子类,处理websocket请求,这里我们只重写determineUser方法,生成我们自己的Principal ,这里我们使用loginName标记登录用户,而不是默认值

@Componentpublic class MyPrincipalHandshakeHandler extends DefaultHandshakeHandler {    private static final Logger log = LoggerFactory.getLogger(MyPrincipalHandshakeHandler.class);    @Override    protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map
attributes) { HttpSession httpSession = getSession(request); String user = (String)httpSession.getAttribute("loginName"); if(StringUtils.isEmpty(user)){ log.error("未登录系统,禁止登录websocket!"); return null; } log.info(" MyDefaultHandshakeHandler login = " + user); return new MyPrincipal(user); } private HttpSession getSession(ServerHttpRequest request) { if (request instanceof ServletServerHttpRequest) { ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request; return serverRequest.getServletRequest().getSession(false); } return null; }}复制代码

MyPrincipal 定义自己的Principal

public class MyPrincipal implements Principal {    private String loginName;    public MyPrincipal(String loginName){        this.loginName = loginName;    }    @Override    public String getName() {        return loginName;    }}复制代码

配置websocket 在registerStompEndpoints中将我们MyPrincipalHandshakeHandler 和AuthHandshakeInterceptor 配置到服务中 configureMessageBroker方法配置rabbitmq信息,这里略

@Configuration// 此注解开使用STOMP协议来传输基于消息代理的消息,此时可以在@Controller类中使用@MessageMapping@EnableWebSocketMessageBrokerpublic class WebSocketRabbitMQMessageBrokerConfigurer extends AbstractWebSocketMessageBrokerConfigurer {    @Autowired    private MyPrincipalHandshakeHandler myDefaultHandshakeHandler;    @Autowired    private AuthHandshakeInterceptor sessionAuthHandshakeInterceptor;    @Override    public void registerStompEndpoints(StompEndpointRegistry registry) {             registry.addEndpoint("/ws/icc/websocket")                .addInterceptors(sessionAuthHandshakeInterceptor)                .setHandshakeHandler(myDefaultHandshakeHandler)                .withSockJS();    }	…. }复制代码

实现向特定用户发送消息的功能

TestMQCtl: 登录到模拟发送页面:send.jsp 我们使用SimpMessagingTemplate 对象的convertAndSendToUser向指定用户的/topic/demo发送消息

@Autowired    private SimpMessagingTemplate template;    /**     * 发送页面     */    @RequestMapping(value = "send")    public String sendMq2UserPage(String msg, String userName){        return "websocket/sendtouser/send";    }    /**     * 向执行用户发送请求     */    @RequestMapping(value = "send2user")    @ResponseBody    public int sendMq2User(String msg, String name){        System.out.println("===========" + msg + "=======" + name);        RequestMessage demoMQ = new RequestMessage();        demoMQ.setName(msg);        template.convertAndSendToUser(name, "/topic/demo", JSON.toJSONString(demoMQ));        return 0;    }复制代码

send.jsp 模拟发送页面

接收者用户:
" />

消息内容:

复制代码

测试

测试一:

登录 http://127.0.0.1:8080/ws/login,使用xiaoming登录,并提交

点击连接,如果连接变灰色,则登录websocket成功

登录模拟发送页面http://127.0.0.1:8080/ws/send,向xiaoming发送test-msg

此时页面收到信息:

在模拟界面,如果我们向其它用户发送信息,则此界面不会收到信息

测试二:

打开两个不同的浏览器,分别使用xiaoming1,xiaoming2登录系统, 使用模拟界面向xiaoming1发送消息,则只有xiaoming1收到 使用模拟界面向xiaoming2发送消息,则只有xiaoming2收到

###结论: 我们已经实现向特定的用户发送消息的功能

代码

所有的详细代码见github代码,请尽量使用

转载地址:http://ifqtx.baihongyu.com/

你可能感兴趣的文章
Android 2D游戏引擎AndEngine配置环境
查看>>
nova resize代码调用部分分析
查看>>
磁盘修复工具TestDisk
查看>>
XamarinAndroid组件教程RecylerView适配器设置动画
查看>>
一个简单的路由映射,让你的树莓派通过SSH外网可访问
查看>>
如何在awk中引用外部变量
查看>>
jQuery简介
查看>>
运维工程师该干什么学些什么
查看>>
我的友情链接
查看>>
vim编辑器基础知识总结
查看>>
重做日志和控制文件的多路复用
查看>>
eclipse提交项目到github
查看>>
Linux下mysql ERROR 1045,Mysql无法执行批处理
查看>>
MyEclipse修改jsp模板文件
查看>>
MSSQL 2000 错误823恢复数据案例
查看>>
javascript,继承,封装
查看>>
scala入门--快学scala第一章练习题
查看>>
RHCS集群理论暨 最佳实践
查看>>
phpstrom快捷键
查看>>
shell脚本中echo显示内容带颜色
查看>>