Springboot + DWR 实现消息推送

SpringBoot 整合 dwr ,实现 js 直接调用后端 Service.

前一段时间由于工作需要接触到了dwr,使用dwr将mq接收到的消息推送到前台,最近项目改用springboot,因此又去重新回炉了一下。
1.新建springboot项目,添加下面dwr的依赖文件

       <!-- DWR -->
        <dependency>
            <groupId>org.directwebremoting</groupId>
            <artifactId>dwr</artifactId>
            <version>3.0.2-RELEASE</version>
        </dependency>

2.添加spring.xml,配置dwr扫描
spring.xml 内容:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd">

    <dwr:annotation-config/>

    <dwr:annotation-scan scanRemoteProxy="false" base-package="com.hikvision.lcc.dwr"/>

    <dwr:configuration/>
</beans>

springboot 需要加载spring.xml,在启动类中做如下配置:

@SpringBootApplication
@ImportResource("classpath*:spring/spring.xml")
public class Demo2Application {
    public static void main(String[] args) {
        SpringApplication.run(Demo2Application.class, args);
    }
}
  1. 之前项目用到的是dwr.xml进行配置,在springboot中我们需要用Java代码进行配置,配置类如下:

@Configuration
public class DwrConfig {

    /**
     *  加入 DWR servlet,相当于在xml中配置
     * @return
     */
    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
       DwrSpringServlet servlet = new DwrSpringServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(servlet, "/dwr/*");
        //设置成true使DWR能够debug和进入测试页面。
        registrationBean.addInitParameter("debug", "true");
        //pollAndCometEnabled 设置成true能增加服务器的加载能力,尽管DWR有保护服务器过载的机制。
        registrationBean.addInitParameter("pollAndCometEnabled", "true");
        
        registrationBean.addInitParameter("activeReverseAjaxEnabled", "true");
        registrationBean.addInitParameter("maxWaitAfterWrite", "60");
        return registrationBean;
    }
}

4.基本配置结束,先写个小小的demo一下。新建一个service类

@Service
@RemoteProxy  // spring 的注解,相当于暴露服务
public class DemoDwr {
    //TODO  这块可以注入服务
    @RemoteMethod
    public String hello(){
        return "hello  dada " ;
    }
    @RemoteMethod
    public String echo(String  string){
        return "hello   " + string ;
    }
}

接着写一个简单的html来个阶段性测试。
demo.html

<html>
<head>
    <title></title>
    <script type='text/javascript' src='/dwr/engine.js'></script>
    <script type='text/javascript' src='/dwr/interface/DemoDwr.js'></script>
    
</head>
hello
<script>
    DemoDwr.echo('叫我小司马', function (str) {
        alert(str);
    });
</script>
</html>

运行项目,刷新一下页面就可以感受到自己的劳动成果了。



*****************************************我是华丽的分割线******************************************
你以为这就结束了,万里长征才走了几米远.... 接着我们进入进阶测试。


5.接着我简单演示一下如何从后端推送到前端消息。
先写一个DWR工具类DwrScriptSessionManagerUtil,可以直接拷贝,一般变化不大。

public class DwrScriptSessionManagerUtil extends DwrServlet {
    private static final long serialVersionUID = -7504612622407420071L;
    public void init(final String key, final String value) throws ServletException {
        Container container = ServerContextFactory.get().getContainer();
        ScriptSessionManager manager = container.getBean(ScriptSessionManager.class);
        ScriptSessionListener listener = new ScriptSessionListener() {
            public void sessionCreated(ScriptSessionEvent ev) {
                HttpSession session = WebContextFactory.get().getSession();
                //String userId = ((User) session.getAttribute("userinfo")).getHumanid() + "";
                System.out.println("a ScriptSession is created!");
                ev.getSession().setAttribute(key, value);
            }
            public void sessionDestroyed(ScriptSessionEvent ev) {
                System.out.println("a ScriptSession is distroyed");
            }
        };
        manager.addScriptSessionListener(listener);

    }

}

假如你已经有一个加收消息的类DemoConsumer,如果mq不熟悉的建议先补一补去,在这我就不细说了。我的消费者代码大概如下,牵扯到业务会自行略去。

@Service
@RemoteProxy
public class Demo2Consumer extends AbstractSpringNotifyConsumer {
   //保存scriptSession , 这个方法需要在页面刚已加载的时候调用,为了前端和后端建立连接。
    @RemoteMethod
    public void onPageLoad(String tag) {
        //获取当前的ScriptSession
        try {
            ScriptSession scriptSession =  WebContextFactory.get().getScriptSession();
            if(scriptSession != null){
                scriptSession.setAttribute("tag", tag);
            }
            DwrScriptSessionManagerUtil dwrScriptSessionManagerUtil = new DwrScriptSessionManagerUtil() ;
            dwrScriptSessionManagerUtil.init("tag",tag);
        } catch (Exception e) {

        }
        System.out.println("onPageLoad 被调用 :" + tag);
    }

  // mq接受到消息会触发这个方法
 @Override
    public void onMessage(TextNotifyMessage message) throws NotifyException {

        System.out.println(" 收到消息  " + message.getData());
        System.err.println(" 收到消息  " + message.getData());
        // 下面代码变化不大,主要是给前端推送
        Browser.withAllSessionsFiltered(new ScriptSessionFilter() {

            public boolean match(ScriptSession session) {
                /* 这块判断是否合法 ,可以在这块验证用户的合法性,为了简单我直接返回true*/
                return true;
                  /*  if (session.getAttribute("userId") == null) {
                        return false;
                    } else {
                        return (session.getAttribute("userId")).equals(userId);
                    }*/
            }

        }, new Runnable() {
            private ScriptBuffer script = new ScriptBuffer();

            public void run() {
                //设定前台接收消息的方法和参数  在前台js里定义getmessage (data) 的方法,就会自动被调用
                script.appendCall("getmessage", message.getData());
                Collection<ScriptSession> sessions = Browser.getTargetSessions();
                for (ScriptSession scriptSession : sessions) {
                    scriptSession.addScript(script);
                }
                System.out.println("dwrtool  showmessage 调用 ");
            }
        });
    }
}
  1. 现在再来改改原来的html,
<html>
<head>
    <title></title>
    <script type='text/javascript' src='/dwr/engine.js'></script>

    <script type='text/javascript' src='/dwr/interface/Demo2Consumer.js'></script>

    <script>
        function onpage(){
            // 页面加载直接调用这个函数,我这块使用点击按钮
            Demo2Consumer.onPageLoad("123456");
        }
        // 后端会调用这个函数
        function getmessage(data){
            alert(data);
        }
    </script>
</head>
hello
<input type="button" onclick="onpage()" value="onpage" >
</html>

效果展示:点击onpage 按钮后会一直对话框弹出,显示的就是mq接收到的消息。
7.补充,和前端聊了聊以后,前端给建议不需要调用onpage记载,也可以调用dwr的js函数,这块我贴上供大家参考


<script>
    //  激活ajax    
  dwr.engine.setActiveReverseAjax(true)
    // 页面未加载的时候是否发送通知
    dwr.engine.setNotifyServerOnPageUnload(true,true)
    // 出现错误后的处理方法
    dwr.engine.setErrorHandler(function(){})

    function getmessage(data){
        if (window.eventBus) {
            window.eventBus.$emit('getDwr',data);
        }
    }
</script>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,559评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,712评论 6 342
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,261评论 1 92
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,258评论 25 707
  • 我的家乡位于淮河中上游的一个小村落,古老神秘的建筑,清澈见底的小河,每每夜晚都让人魂牵梦绕。离乡数年偶尔归乡,少了...
    天上没有坑阅读 4,090评论 0 0