DWR实现扫一扫登录功能

时间:2023-03-08 16:14:25
DWR实现扫一扫登录功能

前言

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

业务场景

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

  DWR实现扫一扫登录功能    DWR实现扫一扫登录功能

主要技术

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

主要流程

  DWR实现扫一扫登录功能

备注

  • 为了达到点击登陆按钮弹出二维码窗口时即刷新二维码,所以选择用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;