spring boot 使用websocket推送消息

1、导入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

2、配置

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }

    @Autowired
    private RequestListener requestListener;

    @Bean
    public ServletListenerRegistrationBean<RequestListener> servletListenerRegistrationBean() {
        ServletListenerRegistrationBean<RequestListener> servletListenerRegistrationBean = new ServletListenerRegistrationBean<>();
        servletListenerRegistrationBean.setListener(requestListener);
        return servletListenerRegistrationBean;
    }
}

@Controller
@ServerEndpoint(value = "/websocket", configurator = HttpSessionConfigurator.class)
@Slf4j
public class ScocketHandler {

    /*websocket 客户端会话 通过Session 向客户端发送数据*/
    private Session session;

    /*存活的session集合(使用线程安全的map保存)*/
    private static Map<Long, ScocketHandler> sessionManger = new ConcurrentHashMap<Long, ScocketHandler>();

    /*websocket 连接建立成功后进行调用*/
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        this.session = session;
        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        Long userId = (Long) httpSession.getAttribute("userId");
        sessionManger.put(userId, this);
        System.out.println("websocket有新的链接" + sessionManger.size());
    }

    /*websocket 链接关闭调用的方法*/
    @OnClose
    public void onClose() {
        sessionManger.remove(this);
    }

    /*收到客户端消息后调用的方法*/
    @OnMessage
    public void onMessage(String message) throws IOException {
    }

    /*websocket 发生错误时进行调用*/
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * @Description: 推送给所有的用户
     * @Param: [message]
     * @return: void
     * @Author: cherish
     * @Date: 2019/9/13
     */
    public static void sendAll(String message) throws IOException {
        for (Map.Entry<Long, ScocketHandler> entry : sessionManger.entrySet()) {
            Session session = entry.getValue().session;
            session.getBasicRemote().sendText("" + message);
        }
    }

    /**
     * @Description: 发送信息给指定ID用户,如果用户不在线则返回不在线信息给自己
     * @Param: [message, toUserId]
     * @return: void
     * @Author: cherish
     * @Date: 2019/9/13
     */
    public static void sendtoUser(TransResult result, Long toUserId) throws IOException {
        Session session = sessionManger.get(toUserId).session;
        if (session != null) {
            ObjectMapper mapper = new ObjectMapper();
            session.getBasicRemote().sendText(mapper.writeValueAsString(result));
        } else {
            log.info("用户不在线,推送到用户的代办导出任务");
        }
    }

    public Session getSession() {
        return session;
    }

    public void setSession(Session session) {
        this.session = session;
    }
}
@Component
public class RequestListener implements ServletRequestListener {

    @Override
    public void requestInitialized(ServletRequestEvent sre)  {
        //将所有request请求都携带上httpSession
        ((HttpServletRequest) sre.getServletRequest()).getSession();
    }
    public RequestListener() {
    }

    @Override
    public void requestDestroyed(ServletRequestEvent arg0)  {
    }
}
public class HttpSessionConfigurator extends ServerEndpointConfig.Configurator {
    /* 修改握手,就是在握手协议建立之前修改其中携带的内容 */
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        sec.getUserProperties().put(HttpSession.class.getName(), httpSession);
        super.modifyHandshake(sec, request, response);
    }

}
@Controller
@RequestMapping("/smart/etl")
public class TestSocketController {

    //页面请求
    @GetMapping("/socket/{cid}")
    public ModelAndView socket(@PathVariable String cid,HttpServletRequest request) {
        ModelAndView mav = new ModelAndView("/socket");
        HttpSession session = request.getSession();
        session.setAttribute("userId",1L);
        mav.addObject("cid", cid);
        return mav;
    }

    //推送数据接口
    @ResponseBody
    @RequestMapping("/socket/push/{cid}")
    public Object pushToWeb(@PathVariable Long cid, String message, HttpServletRequest request) {
        try {
            TransResult transResult = new TransResult();
            transResult.setMessage("您好呀");
            //启动线程实现消息发送
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("开始大文件导入");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("导入结束");
                    // 发送通知
                    try {
                        ScocketHandler.sendtoUser(transResult, 1L);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cid;
    }
    @ResponseBody
    @RequestMapping("/socket/sendAll/{cid}")
    public Object sendAll(@PathVariable Long cid, String message, HttpServletRequest request) {
        try {
            ScocketHandler.sendAll("您好呀");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return cid;
    }

}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"></meta>
    <title>Title</title>
</head>
<body>
hello world!

</body>
<script>
    var socket;
    if(typeof(WebSocket) == "undefined") {
        console.log("您的浏览器不支持WebSocket");
    }else{
        console.log("您的浏览器支持WebSocket");
        //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
        //等同于
        index = new WebSocket("ws://localhost:9999/websocket");
        //socket = new WebSocket("${basePath}websocket/${cid}".replace("http","ws"));
        //打开事件
        index.onopen = function() {
            console.log("Socket 已打开");
            //socket.send("这是来自客户端的消息" + location.href + new Date());
        };
        //获得消息事件
        index.onmessage = function(msg) {
            // alert("dd")
            console.log(msg.data);
            //发现消息进入    开始处理前端触发逻辑
        };
        //关闭事件
        index.onclose = function() {
            console.log("Socket已关闭");
        };
        //发生了错误事件
        index.onerror = function() {
            alert("Socket发生了错误");
            //此时可以尝试刷新页面
        }
        //离开页面时,关闭socket
        //jquery1.8中已经被废弃,3.0中已经移除
        // $(window).unload(function(){
        //     socket.close();
        //});
    }
</script>
</html>

通过

private static Map<Long, ScocketHandler> sessionManger = new ConcurrentHashMap<Long, ScocketHandler>();

维护用户与session的对应关系,在websocket中可以获取到HttpSession中的用户,从而将信息发送给指定的用户,从而实现推送,实现获取session则需要配置如上所述的RequestListener和HttpSessionConfiguratitor及使用

ServletListenerRegistrationBean注册该监听器。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值