轮训长连接实现扫码操作
首先是jsp页面当二维码生成后该做如何操作
jsp页面部分:
其中keepPool方法中的$.get方法可以用ajax代替(避免出现重复调用get的参数状态码为sucess,而不进入controller方法)
var flag = 'true';
//生成二维码之后,调用keeppool方法
function scanLogin(){
var uuid = $("#uuid").val();
//二维码内容
var content = "url地址?uuid="+uuid+"&type=1";
//拿到项目根路径
var contextRootPath = "${ctx}";
//在固定的的地方生生二维码,详情可见之前的二维码生成文章,通过jquery.qrcode.js生成
$('.pc_qr_code').qrcode({
render:"canvas",
width:200,
height:200,
correctLevel:0,
text:content,
background:"#ffffff",
foreground:"black"
});
setCookie("sid", 123, -1*60*60*1000);
if( 'true' == flag ){
keepPool(flag);//自动循环调用
}
};
//改为采用长连接请求方式
function keepPool(flag){
var uuid = $("#uuid").val();
//传参到pool方法下
$.get("/pool",{uuid:uuid,},function(msg){
//如果操作成功
if(msg.successFlag == '1'){
$("#result").html("<font color='green' size='2px'>请勿刷新页面,在手机端确认登录!</font>");
//保存cookie
setCookie(msg.cname, msg.cvalue, 3*60*60*1000);
//扫码成功后开始手机端确认监听,采用长连接
phoneLogin();
//如果操作失败
}else if(msg.successFlag == '0'){
$("#result").html(msg.msg);
$("#result").css({
"color":"red"
})
}
});
}
//手机端确认监听
function phoneLogin(){
//页面调整
$(".pc_qr_code").hide();
$("#phoneLoginImg").show();
var uuid = $("#uuid").val();
//跳转success方法
$.get("/success",{uuid:uuid,},function(msg){
if(msg.successFlag == '1'){
$("#result").html("<font color='red'>扫码成功,请在手机端确认登录</font>");
setCookie(msg.cname, msg.cvalue, 3*60*60*1000);
//alert("将跳转...");
window.location.href = "url扫码成功后跳转的路径";
}else if(msg.successFlag == '0'){
$("#result").html(msg.msg);
$("#result").css({
"color":"red"
})
}
});
}
jsp中跳转到controller中的方法:
/**
* 查询扫码状态,判断二维码是否被扫描的方法
* loginUserMap 是一个静态的map结构的登录池,uuid为key , 登录信息为value
* @return
*/
@RequestMapping("/pool")
@ResponseBody
public JSONObject pool(String uuid){
JSONObject jsonObj = new JSONObject();
DataResultInfo result = new DataResultInfo();
UserVo pool = null;
//采用长连接监听
long startTime=new Date().getTime();
Boolean scanPool=true;
while(scanPool){//每隔2秒循环监听
try {
Thread.sleep(2 * 1000L);//休眠2秒钟
// System.out.println("检测[" + uuid + "]是否登录");
if("".equals(uuid)||uuid==null){
scanPool=false;//没有获取到uuid则不扫描
}else{
//从redis中获取用户扫码信息
pool =(UserVo)JedisUtils.getObject(uuid);
}
if (pool == null) {
scanPool=false;//没有获取到pool则不扫描
// 扫码超时,进线程休眠
Thread.sleep(2 * 1000L);
jsonObj.put("successFlag",CodeConstant.SUCESSFLAG_0);
jsonObj.put("msg","该二维码已经失效,请重新访问登陆页面获取");
} else {
//获取扫描状态,app扫码后会在redis里边修改状态码
boolean scanFlag = pool.getScanStatus();
if (scanFlag) {//获取扫描状态
scanPool=false;//二维码已被扫描将结束长连接循环,将结果信息返回页面
// 根据uuid从redis中获取pool对象,得到对应的sessionId,返给页面,通过js存cookie中
jsonObj.put("successFlag",CodeConstant.SUCESSFLAG_1);
jsonObj.put("cname", "SESSIONKEY");
jsonObj.put("cvalue", pool.getSession());
result.setData(jsonObj);
} else {
if(new Date().getTime()-startTime>180000){//3分钟后超时不再循环
scanPool=false;
jsonObj.put("successFlag",CodeConstant.SUCESSFLAG_0);
jsonObj.put("msg","等待手机扫描超时,请重新刷新扫描!");
}
}
}
} catch (InterruptedException e) {
logger.error("查询扫码状态异常", e);
Thread.currentThread().interrupt();
}
}
return jsonObj;
}
/**
* 二维码扫描手机确认登录监听扫描类
* @param uuid
* @return
*/
@RequestMapping("/success")
@ResponseBody
public JSONObject success(String uuid){
JSONObject jsonObj = new JSONObject();
String flag="false";
//采用长连接监听
long startTime=new Date().getTime();
Boolean bool=true;
while(bool){//每隔一秒循环监听
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
logger.error("扫码登录监听异常", e);
Thread.currentThread().interrupt();
}
//从redis中获取用户信息
UserVo user =null;
user =(UserVo)JedisUtils.getObject(uuid);
if(user!=null){
flag = user.getIsFlag();//是否确认登录标志
}
if(CodeConstant.TRUE.equals(flag)){//已在手机确认登录
bool=false;//手机确认登录后将结束长连接循环,将结果信息返回页面
//根据用户名查询用户信息,以获取可用的登录信息用于系统登录
PhoneLog phoneLog=new PhoneLog();
phoneLog.setYWLX("扫码登录-查找用户信息");
JSONObject resultObj =UserUtils.findbackPassword2(user,phoneLog);
if(CodeConstant.SUCCESS.equals(resultObj.get("msg"))) {//成功
logger.info(user.getUserName()+"的登录信息------------>"+resultObj.toJSONString());
List<UserInfoEntity> list=JSONArray.parseArray(resultObj.get("result").toString(), UserInfoEntity.class);
if(list.size()==1) {//正常数据
UserVo userVo = new UserVo();//重新创建对象,以清空原有值
UserInfoEntity userInfoEntity=list.get(0);
userVo.setUserName(userInfoEntity.getAA006());//用户名
userVo.setPassword(userInfoEntity.getAA002());//密码
//调用拦截的登录方法
UserUtils.getUserByName(userVo);
jsonObj.put("msg","手机已确认,可以登录!");
jsonObj.put("successFlag",CodeConstant.SUCESSFLAG_1);
//JedisUtils.delObject(uuid);删除缓存
}else {
jsonObj.put("successFlag",CodeConstant.SUCESSFLAG_0);
jsonObj.put("msg","等待超时,请重新登录!");
}
}else {//失败
jsonObj.put("successFlag",CodeConstant.SUCESSFLAG_0);
jsonObj.put("msg","调用二维码登录接口服务失败,请稍后重试!");
}
}else{
if(new Date().getTime()-startTime>180000){//3分钟后超时不再循环
bool=false;
jsonObj.put("successFlag",CodeConstant.SUCESSFLAG_0);
jsonObj.put("msg","等待手机确认登录超时,请重新登录!");
}
}
}
return jsonObj;
}
其次,如果需要通过接口取得某些参数,可以使用如下方法
//controller中调用接口获取参数
Map<String, String> map1 = new HashMap<>();
map1.put("参数名1","参数1");
map1.put("参数名2","参数2");
String result = SSLSendUtil.sendHttpPost(map1, "http://x.xx.xx.xxx:xxxx/aaa/bbb/ccc/ddd/eee");
//SSLSendUtil中的sedHttpPost方法
public static String sendHttpPost(Map<String,String> map, String url) throws Exception {
List<NameValuePair> paramList = new ArrayList<>();
// 请求参数填充
for(Map.Entry<String, String> entry : map.entrySet()){
String key = entry.getKey();
String value = entry.getValue();
paramList.add(new BasicNameValuePair(key,value));
}
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader(HTTP.CONTENT_TYPE, "application/x-www-form-urlencoded;charset=utf-8");
UrlEncodedFormEntity postEntity = new UrlEncodedFormEntity(paramList, "UTF-8");
httpPost.setEntity(postEntity);
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
String responseContent = EntityUtils.toString(entity, "UTF-8");
response.close();
httpClient.close();
return responseContent;
}
以上方法仅供参考,如果有什么不对的地方还请指教.