前言

  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; width:360px" >
<div class="modal-content" style="width: 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="width: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; width: 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({width: 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;  

DWR实现扫一扫登录功能的更多相关文章

  1. 实现基于dotnetcore的扫一扫登录功能

    第一次写博客,前几天看到.netcore的认证,就心血来潮想实现一下基于netcore的一个扫一扫的功能,实现思路构思大概是web端通过cookie认证进行授权,手机端通过jwt授权,web端登录界面 ...

  2. 微信开放平台PC端扫码登录功能个人总结

    最近公司给我安排一个微信登录的功能,需求是这样的: 1.登录授权 点击二维码图标后,登录界面切换为如下样式(二维码),微信扫描二维码并授权,即可成功登录:    若当前账号未绑定微信账号,扫描后提示“ ...

  3. .Net微信网页开发之使用微信JS-SDK调用微信扫一扫功能

    前言: 之前有个项目需要调用微信扫描二维码的功能,通过调用微信扫码二维码功能,然后去获取到系统中生成的二维码信息.正好微信JS-SDK提供了调用微信扫一扫的功能接口,下面让我们来看看是如何实现的吧. ...

  4. C#开发微信门户及应用(15)-微信菜单增加扫一扫、发图片、发地理位置功能

    前面介绍了很多篇关于使用C#开发微信门户及应用的文章,基本上把当时微信能做的接口都封装差不多了,微信框架也积累了不少模块和用户,最近发现微信公众平台增加了不少内容,特别是在自定义菜单里面增加了扫一扫. ...

  5. 微信JSSDK使用步骤(用于在微信浏览器中自定义分享,分享到朋友圈,拍照,扫一扫等功能)

    一.使用JSSDK需要一个公众号(需要认证!): (1).把自己项目的服务器地址输入. (2).把MP_verify_m7Qp93BAuIGDWRVO.txt  文件下载下来,放到该服务器域名指向的根 ...

  6. 调用微信的扫一扫功能详解说明---(java 排坑版)

    最近碰到了这么一个需求,说是在前端页面调用手机本地的相机,扫描二维码这么一个需求,对于我一个后端来说, 这实在是难,难于上青天,但是决不能说一个不字.我说可以使用微信的扫码工具吗,这样可以方便一点,. ...

  7. vue 实现 扫二维码 功能

    前段时间一直在研究,如何通过 vue 调用 相机 实现 扫一扫的功能,但是查看文档发现,需要获取 getUserMedia 的属性值,但存在兼容性问题. 退而求其次,通过 h5plus 来实现. 1. ...

  8. 调用微信扫一扫功能,踩坑'invalid signature'

    在vue项目中,调用微信扫一扫功能,在安卓系统下完全正常,ios系统下却报错'invalid signature'的错误,这可能令许多小伙伴困惑,经过查询大量博客相关资料,才找到了解决的方法. 原因: ...

  9. 记录vue用 html5+做移动APP 用barcode做扫一扫功能时安卓 的bug(黑屏、错位等等)和解决方法

    最近做项目时,要用到扫一扫二维码的功能,在html5+里面有提供barcode功能,于是照过来用了, 写的代码如下 : 扫码页面: <style lang="less" sc ...

随机推荐

  1. [译]SSAS下玩转PowerShell

    操作SSAS数据库的方法有很多,是否有一种可以方法可以通过脚本自动去做这些事呢,比如处理分区,创建备份以及监视SSAS的运行状况. 原文地址: http://www.mssqltips.com/sql ...

  2. LCA + 树状数组 + 树上RMQ

    题目链接:http://poj.org/problem?id=2763 思路:首先求出树上dfs序列,并且标记树上每个节点开始遍历以及最后回溯遍历到的时间戳,由于需要修改树上的某两个节点之间的权值,如 ...

  3. Jmeter MySQL数据库性能测试

    1.首先准备M一SQL数据,新建一个数据库及测试用的表,插入1条数据 2.打开Jmeter,新建线程组,设置多少用户,循环几次随意 3.在线程组下新增JDBC配置元件,通过配置使得Jmeter能够连上 ...

  4. HTML5页面绘图

    canvas 标签:获取画笔: 对象.getContext("2d")制定画笔Syte: context.fillStyle = "red"; context. ...

  5. 同步、更新、下载Android Source & SDK from 国内镜像站(转载)

    同步.更新.下载Android Source & SDK from 国内镜像站 转自: 同步.更新.下载Android Source & SDK from 国内镜像站 Download ...

  6. cdn

    cdn内容分发网络: 1. 内容缓存Web cache技术,反向代理 2. 集群服务与负载均衡技术 LVS(四层) 与 nginx(七层) 3. 全局负载均衡工作原理:基于DNS解析的GSLB实现机制 ...

  7. Media Formatters in ASP.NET Web API 2

    原文:http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters 1. 网络媒体类型 媒体类型,也叫作 ...

  8. Spring任务调度之Spring-Task

    一.前言 上面两篇介绍了在Spring 中使用Timer与Quartz,本篇将介绍Spring3.0以后自主开发的定时任务工具,spring task,可以将它比作一个轻量级的Quartz,而且使用起 ...

  9. 如何用inno setup打包activex

    需要解决三个问题,运行环境检测与安装,按顺序执行安装,activex注册. 运行环境检测与安装 最开始的方法,百度之后,根据网上的搜索的结果,使用了RegQueryDWordValue(HKLM, ' ...

  10. Java直接(堆外)内存使用详解

    本篇主要讲解如何使用直接内存(堆外内存),并按照下面的步骤进行说明: 相关背景-->读写操作-->关键属性-->读写实践-->扩展-->参考说明 希望对想使用直接内存的朋 ...