zoukankan      html  css  js  c++  java
  • DWR实现扫一扫登录功能

    前言

      DWR实现后台推送消息到Web页面》一文中已对DWR作了简介,并列出了集成步骤。本文中再一次使用到DWR,用以实现扫一扫登录功能。

    业务场景

      web端首页点击“登陆”按钮,弹出二维码,用户进入企业号应用后点击“扫一扫”按钮,扫描二维码后web端自动跳转到已登录界面。

          

    主要技术

    • DWR —— 后台调用前端JS实现comet技术
    • 微信JSSDK —— 实现扫一扫功能

    主要流程

      

    备注

    • 为了达到点击登陆按钮弹出二维码窗口时即刷新二维码,所以选择用iframe装载二维码;
    • 为了控制指定浏览器跳转页面,所以后台必须要记录浏览器与服务器之间的httpSession实例;
    • DWR自身不保存scriptSession和httpSession的关系,所以需要自己保存其对应关系;

    实现步骤

    1、导入jar包(若用maven则添加依赖关系)

      地址: http://directwebremoting.org/dwr/downloads/index.html

    2、编写ScriptSessionListener

      

    public class DWRScriptSessionListener implements ScriptSessionListener {
     
        //维护一个Map key为ScriptSession的Id, value为HttpSession对象
        public static final Map<String, Map> httpMap = new HashMap<String, Map>();
         
        /**
         * ScriptSession创建事件
         */
        public void sessionCreated(ScriptSessionEvent event) {
          WebContext webContext = WebContextFactory.get();
          HttpSession httpSession = webContext.getSession();
          ScriptSession scriptSession = event.getSession();
          Map httpMapObj = new HashMap<>();
          httpMapObj.put("HttpSession", httpSession);
          httpMapObj.put("HttpServletRequest", webContext.getHttpServletRequest());
          httpMapObj.put("HttpServletResponse", webContext.getHttpServletResponse());
          httpMap.put(scriptSession.getId(), httpMapObj);
          System.out.println("httpSession: " + httpSession.getId() + " scriptSession: "
                + scriptSession.getId() + "is created!");
           
          //创建连接后触发前端保存ScriptSessionId
          DwrUtil t = new DwrUtil();
          List args = new ArrayList();
          args.add(scriptSession.getId());
          t.invokeJavascriptFunctionBySessionId(scriptSession.getId(), "saveScriptSessionId", args);
       }
     
        /**
         * ScriptSession销毁事件
         */
        public void sessionDestroyed(ScriptSessionEvent event) {
          ScriptSession scriptSession = event.getSession();
          Map httpMapObj = httpMap.remove(scriptSession.getId()); // 移除scriptSession
          HttpSession httpSession = (HttpSession)httpMapObj.get("HttpSession");
          // httpMap.remove(scriptSession.getId()); //移除scriptSession
          System. out.println( "httpSession: " + httpSession.getId() + " scriptSession: " + scriptSession.getId() + "is destroyed!");
        }
    }

    3、编写ScriptSessionManager  

    public class DWRScriptSessionManager extends DefaultScriptSessionManager {
       public DWRScriptSessionManager() {
          // 绑定一个ScriptSession增加销毁事件的监听器
          this.addScriptSessionListener(new DWRScriptSessionListener());
          System.out.println("bind DWRScriptSessionListener");
       }
    }

    4、在web.xml中增加ScriptSessionManager 的配置

    <!-- DWR --> 
    <servlet>
        <servlet-name>dwr-invoker</servlet-name>
        <servlet-class>
            org.directwebremoting.servlet.DwrServlet
        </servlet-class>
        <init-param>
            <param-name>pollAndCometEnabled</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
             <param-name >org.directwebremoting.extend.ScriptSessionManager </param-name>
             <param-value >com.gzkit.service.dwr.DWRScriptSessionManager </param-value>
       </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dwr-invoker</servlet-name>
        <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>

    5、业务代码

    /**
     * 扫一扫登录
     * @author:LiuZhuoJun
     * @Description: 如果登录成功则触发前端页面跳转,如果不成功则返回错误信息
     * @param account 用户账号
     * @param scriptSessionId
     * @return
     * @date:2016年11月4日
     */
    @RequestMapping(value = "scanLogin")
    @ResponseBody
    public JkReturnJson scanLogin(String account, String scriptSessionId) {
       JkReturnJson jkReturnJson = new JkReturnJson();
       if(Utils.isBlank(account) || Utils.isBlank(scriptSessionId)){
          jkReturnJson.setStatusCode(ConstantsErrCode.JK_PARAM_ERR);
          jkReturnJson.setStatusMsg(ConstantsErrCode.JK_PARAM_ERR_MSG);
          jkReturnJson.setUserMsg("account、scriptSessionId字段为必需");
          return jkReturnJson;
       }
       /* 从httpMap中获取对应的httpSession */
       Map httpMapObj = DWRScriptSessionListener.httpMap.get(scriptSessionId);
       if(httpMapObj == null){
          jkReturnJson.setStatusCode(ConstantsErrCode.BUSSINESS_ERR);
          jkReturnJson.setStatusMsg("httpSession不存在");
          jkReturnJson.setUserMsg("二维码已失效,请刷新页面");
          return jkReturnJson;
       }
       HttpSession httpSession = (HttpSession)httpMapObj.get("HttpSession");
       HttpServletRequest httpServletRequest = (HttpServletRequest)httpMapObj.get("HttpServletRequest");
        
       /* 根据传入的account获取对应用户对象 */
       /* 此处代码省略 */
        
       /* 将用户对象设入httpSession中 */
       httpSession.setAttribute(ResourceUtil.LOCAL_CLINET_USER, user);
            
       /* 登录成功触发前端跳转页面 */
       DwrUtil t =  new DwrUtil();
       List args = new ArrayList();
       t.invokeJavascriptFunctionBySessionId(scriptSessionId,"loginSuccess",args);
            
       jkReturnJson.setUserMsg("登录成功");
       return jkReturnJson;
    }

    6、web首页

    6.1 首页二维码iframe结构

    <!-- 二维码模态框   -->
    <div class="modal fade" id="qrcodeModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
      <div class="modal-dialog" style="top: 100px; 360px"  >
        <div class="modal-content" style=" 360px; height:450px">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
            <h4 class="modal-title text-center " id="myModalLabel">扫码登陆</h4>
          </div>
          <div class="modal-body">
            <iframe id="qrcodeframe" width="100%" height="270px" frameborder="0"></iframe> 
            <!-- <div class="center-block" style="250px;height:250px"></div> -->
            <!--  <img   src="webpage/homePage/image/erweima.jpg" class="center-block"  alt="Responsive image">-->
          </div>
          <div class="modal-footer">
            <p class="text-center">请关注电建宝应用并使用"扫一扫"登陆电建宝管理后台</p>
          </div>
        </div>
      </div>
    </div>

    6.2 二维码页面

    注意要引入/dwr/engine.js和/dwr/util.js才能实现页面与后台的DWR连接。(js是动态生成的,无需导入js文件)

    <body>
    <div id="qrcode" style="margin: auto auto;  250px;"></div>
    <script type='text/javascript' src='/dwr/engine.js'></script>
    <script type='text/javascript' src='/dwr/util.js'></script>
    <script type="text/javascript" src="/plug-in/mobile/third/qrcode/jquery.qrcode.min.js"></script>
    <script type="text/javascript" src="/webpage/homePage/js/qrcode.js"></script>
    </body>

    6.3 二维码页面js

    $(function(){
        initDwr();
        //设置每隔5分钟刷新二维码
        setInterval("reloadPage()",5*60*1000);
    });
     
    //初始化dwr
    function initDwr(){
        dwr.engine.setActiveReverseAjax(true);
    }
     
    //保存scriptSessionId
    function saveScriptSessionId(scriptSessionId){
       $("#qrcode").html("");
       $("#qrcode").qrcode({ 250,height: 250,text: scriptSessionId});
    }
     
    //登录成功操作
    function loginSuccess(){
       window.parent.location.href = "/loginController.do?login";
    }
     
    //刷新页面
    function reloadPage(){
       location.reload();
    }

    7、企业号调用微信SDK实现扫一扫功能

       代码略

    相关链接

    DWR官网

    http://directwebremoting.org/dwr/

    DWR入门讲解(前端)

    http://directwebremoting.org/dwr/introduction/getting-started.html

    DWR入门讲解(后台)

    http://directwebremoting.org/dwr/documentation/server/javaapi.html

    DWR下载地址

    http://directwebremoting.org/dwr/downloads/index.html

    DWR JavaDoc

    http://directwebremoting.org/dwr/javadoc/

    微信JSSDK

    http://qydev.weixin.qq.com/wiki/index.php?title=%E5%BE%AE%E4%BF%A1JS-SDK%E6%8E%A5%E5%8F%A3


    附录一  DwrUtil.java

    public class DwrUtil {
       /**
        * 调用页面javascript函数
        * @param functionName
        * @param args
        */
       public void invokeJavascriptFunction (String _funcName, List _args){
          final String funcName = _funcName;
          final List args = _args;
          Browser.withAllSessions(new Runnable(){ 
                private ScriptBuffer script = new ScriptBuffer(); 
                public void run(){ 
                   //拼接javascript
                   script = script.appendScript(funcName+"(");
                   for(int i=0; i<args.size(); i++){
                      if(i != 0){
                         script = script.appendScript(",");
                      }
                      script = script.appendData(args.get(i));
                   }
                   script.appendScript(")"); 
                   //System.out.println(script.toString());   
                    
                    Collection<ScriptSession> sessions = Browser.getTargetSessions(); 
                    for (ScriptSession scriptSession : sessions){ 
                        scriptSession.addScript(script); 
                    } 
                } 
            });
       }
        
       public void invokeJavascriptFunctionBySessionId (String sessionId, String _funcName, List _args){
          final String funcName = _funcName;
          final List args = _args;
          Browser.withSession(sessionId, new Runnable(){ 
                private ScriptBuffer script = new ScriptBuffer(); 
                public void run(){ 
                   //拼接javascript
                   script = script.appendScript(funcName+"(");
                   for(int i=0; i<args.size(); i++){
                      if(i != 0){
                         script = script.appendScript(",");
                      }
                      script = script.appendData(args.get(i));
                   }
                   script.appendScript(")"); 
                   //System.out.println(script.toString());   
                   Collection<ScriptSession> sessions = Browser.getTargetSessions(); 
                    for (ScriptSession scriptSession : sessions){ 
                        scriptSession.addScript(script); 
                    } 
                } 
            });
       }
    }

    附录二 服务器使用nginx导致DWR的js无法加载的解决办法

      nginx默认是开启代理缓冲的,而DWR的js是动态生成的,无法缓冲。要解决dwr js加载问题需在nginx配置中增加以下语句

    proxy_buffering off;  
  • 相关阅读:
    mysql 分列或取子串
    Excel “20200504”文本格式转化为时间格式
    Mysql清空数据表
    python 做词云图
    Pandas操作excel
    python中zip()函数的用法
    Excel技能提升
    JS 学习笔记
    元类理解与元类编程 《Python3网络爬虫开发》中第九章代理的使用代码Crawler中代码的理解
    关于选择器注意的点
  • 原文地址:https://www.cnblogs.com/leap/p/6210896.html
Copyright © 2011-2022 走看看