作者:93年颈椎病人

blog.csdn.net/q826qq1878/article/details/91041679

最近单位又有一个新Java项目。

涉及到扫码登录。之前项目使用的是 ajax轮询的方式。感觉太low了。

所以这次用webSocket的方式进行实现

好。废话不多说!咱们开始!!

一、首先咱们需要一张表

这表是干啥的呢?就是记录一下谁扫码了。谁登录了。

User_Token表

字段如下:

  • uuid : 用于确保唯一性

  • userId :谁登录的

  • loginTime :登录时间

  • createTime :创建时间 用于判断是否过期

  • state:是否二维码失效  0有效 1失效

二、角色都有哪些

咱们还需要分析一下子。扫码登录这个业务逻辑都有哪些角色

  • android端 or 微信Web端 :扫码

  • PC端 :被扫。登录

  • 服务端:掌控全局,提供接口。

三、接口都需要哪些?

有了角色。你用大腿也能想出来接口了对不对!!

所以咱们的接口有2个!

  • 生成二维码接口:生成一个二维码。二维码中有UUID。

  • 确认身份接口:确定身份以及判断是否二维码过期等

四、步骤

那句话怎么说的来着。要把大象装冰箱一共分几步?

  • PC端打开。调用生成二维码接口 并与 服务端建立链接。链接使用uuid进行绑定

  • 微信Web端进行扫码。获取二维码中的uuid。

  • 微信Web端拿到uuid以后。显示是否登录页面。点击确定后 调用 确认身份接口。

  • 确认身份接口通过以后。服务端给PC端发送信息。完成登录。此时链接断开。

好了!分析完了这些。你们一定在想。。还有完没完啊。。不要在BB了。。赶紧贴代码吧。。

作者:观众老爷们。我这是在教给你们如何思考的方法呀?

那么开始贴代码吧!希望大家在看到的同时也可以自己进行思考。

五、疯狂贴代码

首先需要获取二维码的代码对不对!贴!

//获取登录二维码、放入Token  @RequestMapping(value = "/getLoginQr" ,method = RequestMethod.GET)  public void createCodeImg(HttpServletRequest request, HttpServletResponse response){  response.setHeader("Pragma", "No-cache");  response.setHeader("Cache-Control", "no-cache");  response.setDateHeader("Expires", 0);  response.setContentType("image/jpeg");  try {  //这里没啥操作 就是生成一个UUID插入 数据库的表里  String uuid = userService.createQrImg();  response.setHeader("uuid", uuid);  // 这里是开源工具类 hutool里的QrCodeUtil  // 网址:http://hutool.mydoc.io/  QrCodeUtil.generate(uuid, 300, 300, "jpg",response.getOutputStream());  } catch (Exception e) {  e.printStackTrace();  }  }

有了获取二维码的接口。相对的前端需要调用。

知识点:动态加载图片流并取出header中的参数

这里使用了xmlhttp进行处理。

为什么?

因为后端返回的是一个流。

那么流中。就是放置了二维码中的uuid。这个uuid作为一次会话的标识符使用。

那么前端也需要拿到。跟后端进行webSocket链接。

这样有人扫码后。服务端才可以使用webSocket的方式通知前端。有人扫码成功了。你做你的业务吧。酱紫。

所以为了拿到请求中 header中放置的uuid 所以这样通过xmlhttp进行处理

<div class="qrCodeImg-box" id="qrImgDiv"></div>

js

$(document).ready(function(){  initQrImg();
});  function initQrImg(){  $("#qrImgDiv").empty();  var xmlhttp;  xmlhttp=new XMLHttpRequest();  xmlhttp.open("GET",getQrPath,true);  xmlhttp.responseType = "blob";  xmlhttp.onload = function(){  console.log(this);  uuid = this.getResponseHeader("uuid");  if (this.status == 200) {  var blob = this.response;  var img = document.createElement("img");  img.className = 'qrCodeBox-img';  img.onload = function(e) {  window.URL.revokeObjectURL(img.src);  };  img.src = window.URL.createObjectURL(blob);  document.getElementById("qrImgDiv").appendChild(img);  initWebSocket();  }  }  xmlhttp.send();  }  var path = "://localhost:8085";  var getQrPath =  "http" + path + "/user/getLoginQr";  var wsPath =     "ws" + path + "/websocket/";  function initWebSocket(){  if(typeof(WebSocket) == "undefined") {  console.log("您的浏览器不支持WebSocket");  }else{  console.log("您的浏览器支持WebSocket");  //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接  //等同于socket = new WebSocket("ws://localhost:8083/checkcentersys/websocket/20");  var wsPathStr = wsPath+uuid;  socket = new WebSocket(wsPathStr);  //打开事件  socket.onopen = function() {  console.log("Socket 已打开");  //socket.send("这是来自客户端的消息" + location.href + new Date());  };  //获得消息事件  socket.onmessage = function(msg) {  console.log(msg.data);  var data = JSON.parse(msg.data);  if(data.code == 200){  alert("登录成功!");  //这里存放自己业务需要的数据。怎么放自己看  window.sessionStorage.uuid = uuid;  window.sessionStorage.userId = data.userId;  window.sessionStorage.projId = data.projId;  window.location.href = "pages/upload.html"  }else{  //如果过期了,关闭连接、重置连接、刷新二维码  socket.close();  initQrImg();  }  //发现消息进入    开始处理前端触发逻辑  };  //关闭事件  socket.onclose = function() {  console.log("Socket已关闭");  };  //发生了错误事件  socket.onerror = function() {  alert("Socket发生了错误");  //此时可以尝试刷新页面  }  }  }

好了。上面已经提到了前端如何配置webSocket。

下面说一下

springBoot中如何操作webSocket

1、增加pom.xml

<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2、增加一个Bean

/**  * WebSocket的支持  * @return  */
@Bean
public ServerEndpointExporter serverEndpointExporter() {  return new ServerEndpointExporter();
}

3、定义WebSocketServer

package com.stylefeng.guns.rest.modular.inve.websocket;  /**  * Created by jiangjiacheng on 2019/6/4.  */
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;  import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Component;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;  @ServerEndpoint("/websocket/{sid}")
@Component
public class WebSocketServer {  static Log log=LogFactory.get(WebSocketServer.class);  //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。  private static int onlineCount = 0;  //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。  private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();  //与某个客户端的连接会话,需要通过它来给客户端发送数据  private Session session;  //接收sid  private String sid="";  /**  * 连接建立成功调用的方法*/  @OnOpen  public void onOpen(Session session,@PathParam("sid") String sid) {  this.session = session;  webSocketSet.add(this);     //加入set中  addOnlineCount();           //在线数加1  log.info("有新窗口开始监听:"+sid+",当前在线人数为" + getOnlineCount());  this.sid=sid;  /*try {  sendMessage("连接成功");  } catch (IOException e) {  log.error("websocket IO异常");  }*/  }  /**  * 连接关闭调用的方法  */  @OnClose  public void onClose() {  webSocketSet.remove(this);  //从set中删除  subOnlineCount();           //在线数减1  log.info("有一连接关闭!当前在线人数为" + getOnlineCount());  }  /**  * 收到客户端消息后调用的方法  *  * @param message 客户端发送过来的消息*/  @OnMessage  public void onMessage(String message, Session session) {  log.info("收到来自窗口"+sid+"的信息:"+message);  //群发消息  for (WebSocketServer item : webSocketSet) {  try {  item.sendMessage(message);  } catch (IOException e) {  e.printStackTrace();  }  }  }  /**  *  * @param session  * @param error  */  @OnError  public void onError(Session session, Throwable error) {  log.error("发生错误");  error.printStackTrace();  }  /**  * 实现服务器主动推送  */  public void sendMessage(String message) throws IOException {  this.session.getBasicRemote().sendText(message);  }  /**  * 群发自定义消息  * */  public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException {  log.info("推送消息到窗口"+sid+",推送内容:"+message);  for (WebSocketServer item : webSocketSet) {  try {  //这里可以设定只推送给这个sid的,为null则全部推送  if(sid == null) {  item.sendMessage(message);  }else if(item.sid.equals(sid)){  item.sendMessage(message);  }  } catch (IOException e) {  continue;  }  }  }  public static synchronized int getOnlineCount() {  return onlineCount;  }  public static synchronized void addOnlineCount() {  WebSocketServer.onlineCount++;  }  public static synchronized void subOnlineCount() {  WebSocketServer.onlineCount--;  }
}

这样就增加了webSocket的支持啦。

那么回到刚才的步骤。

1、首先PC端调用接口展示出来了二维码。

2、请求二维码中的http请求。就有uuid在 header中。直接取到uuid 作为webSocket的标识sid进行连接。

3、然后手机端使用相机拿到二维码中的uuid。使用uuid + userid 请求 扫码成功接口。

贴扫码成功接口

Controller代码:

  /**  * 确认身份接口:确定身份以及判断是否二维码过期等  * @param token  * @param userId  * @return  */  @RequestMapping(value = "/bindUserIdAndToken" ,method = RequestMethod.GET)  @ResponseBody  public Object bindUserIdAndToken(@RequestParam("token") String token ,  @RequestParam("userId") Integer userId,  @RequestParam(required = false,value = "projId") Integer projId){  try {  return new SuccessTip(userService.bindUserIdAndToken(userId,token,projId));  } catch (Exception e) {  e.printStackTrace();  return new ErrorTip(500,e.getMessage());  }  }

Service代码

@Override  public String bindUserIdAndToken(Integer userId, String token,Integer projId) throws Exception {  QrLoginToken qrLoginToken = new QrLoginToken();  qrLoginToken.setToken(token);  qrLoginToken = qrLoginTokenMapper.selectOne(qrLoginToken);  if(null == qrLoginToken){  throw  new Exception("错误的请求!");  }  Date createDate = new Date(qrLoginToken.getCreateTime().getTime() + (1000 * 60 * Constant.LOGIN_VALIDATION_TIME));  Date nowDate = new Date();  if(nowDate.getTime() > createDate.getTime()){//当前时间大于校验时间  JSONObject jsonObject = new JSONObject();  jsonObject.put("code",500);  jsonObject.put("msg","二维码失效!");  WebSocketServer.sendInfo(jsonObject.toJSONString(),token);  throw  new Exception("二维码失效!");  }  qrLoginToken.setLoginTime(new Date());  qrLoginToken.setUserId(userId);  int i = qrLoginTokenMapper.updateById(qrLoginToken);  JSONObject jsonObject = new JSONObject();  jsonObject.put("code",200);  jsonObject.put("msg","ok");  jsonObject.put("userId",userId);  if(ToolUtil.isNotEmpty(projId)){  jsonObject.put("projId",projId);  }  WebSocketServer.sendInfo(jsonObject.toJSONString(),token);  if(i > 0 ){  return null;  }else{  throw  new Exception("服务器异常!");  }  }

逻辑大概就是判断一下 token对不对

如果对的话。时间是否过期。如果没有过期进行业务逻辑操作

//这句话比较关键
WebSocketServer.sendInfo(jsonObject.toJSONString(),token);

就是通知前端 已经登录成功了。并且给他业务所需要的内容。

然后前端代码接收到了。就进行业务逻辑操作就可以啦。

推荐好文

>>【练手项目】基于SpringBoot的ERP系统,自带进销存+财务+生产功能>>分享一套基于SpringBoot和Vue的企业级中后台开源项目,代码很规范!
>>能挣钱的,开源 SpringBoot 商城系统,功能超全,超漂亮!

基于SpringBoot+webSocket实现扫码登录功能相关推荐

  1. SpringBoot+webSocket实现扫码登录功能

    今日推荐强制双休!腾讯调整加班机制,21 点前必须离开工位 使用雪花id或uuid作为Mysql主键,被老板怼了一顿! 盘点 12 个 GitHub 上的高仿项目 CTO 说了,用错 @Autowir ...

  2. SpringBoot+webSocket 实现扫码登录功能

    最近单位又有一个新Java项目. 涉及到扫码登录.之前项目使用的是 ajax轮询的方式.感觉太low了. 所以这次用webSocket的方式进行实现 好.废话不多说!咱们开始!! 一.首先咱们需要一张 ...

  3. IM要做手机扫码登录?先看看微信的扫码登录功能技术原理

    本文原文由作者Amazing10原创发布于公众号业余码农,收录时有改动,感谢原作者的技术分享. 1.引言 某天中午,吃完午饭,摊在自己的躺椅上,想趁吃饱喝足的午后时间静静享受独自的静谧. 干点什么好呢 ...

  4. IM的扫码登录功能如何实现?一文搞懂主流的扫码登录技术原理

    本文引用了3位作者"精品唯居"."  Yangfan2016"." MrYun"的部分文章内容,一并感谢. 1.引言 扫码登录这个功能,最早 ...

  5. 手把手教程用Java实现微信公众号扫码登录功能

    文章目录 前言 一.环境准备 二.使用步骤 1. 使用微信工具包 2. 创建数据表 3. 登录页面代码逻辑 4. 验证微信公众号登录 总结 前言 微信现今是我们必不可少的社交工具了,围绕微信这个生态实 ...

  6. IM扫码登录技术专题(三):通俗易懂,IM扫码登录功能详细原理一篇就够

    本文引用了作者"大古同学"的"二维码扫码登录是什么原理"一文的主要内容,为了更好的理解和阅读,即时通讯网收录时有修订和改动,感谢原作者的分享. 1.引言 自从微 ...

  7. SpringBoot整合微信扫码登录

    SpringBoot整合微信扫码登录 准备工作 基本思路流程 搭建SpringBoot 引入依赖 加入配置文件 代码实现 工具类 controller层 结果 准备工作 1.登录官网了解到,学习者想本 ...

  8. 项目整合微信扫码登录功能

    项目整合微信登录功能 一.准备工作 https://open.weixin.qq.com 1.注册 2.邮箱激活 3.完善开发者资料 4.开发者资质认证 准备营业执照,1-2个工作日审批.300元 5 ...

  9. 微信扫码登录功能实现

    原因:很简单,公司的账号登录需要用到微信扫码登录与QQ的登录功能,所以,在做好了微信的扫码登录之后,本人就写这篇微信扫码登录功能实现的教程 教程开始 需要用到的网站: https://open.wei ...

最新文章

  1. 国外论坛BCH关注度暴涨
  2. [译]React Component最佳实践
  3. 【正一专栏】俄罗斯世界杯来了——抽签概述
  4. Linux学习之遇到的小问题---查看系统版本,虚拟机创建共享文件夹,用到的命令记录。
  5. Django报错:ConnectionAbortedError: [WinError 10053] 你的主机中的软件中止了一个已建立的连接。...
  6. 北邮 复习 软件工程_软件工程期末复习北邮
  7. python编程(数据库操作)
  8. Python实战从入门到精通第四讲——数据结构与算法2之实现一个优先级队列
  9. myeclipse10破解补丁激活方法
  10. vue-router 定义三级路由,路由跳转了,页面没出来
  11. 高斯滤波的理解与学习
  12. MVP2006成都聚会图片
  13. Wordpress最强大的主题-2019最新The7.7主题
  14. secret学习笔记
  15. c语言编程TLC2543AD采集,TLC2543单片机程序 带Proteus仿真 电路原理图 AD转换实验
  16. 简述EMD分解、希尔伯特变换、谱方法
  17. Linux网络配置和常用命令
  18. 超详细KNIME二次开发的环境配置安装过程
  19. 创业者如何打动投资者——创业态度决定一切
  20. KDD Cup 2020多模态召回比赛季军方案与广告业务应用

热门文章

  1. 你手中的iPhone 7已过时!被苹果列为清仓产品,或为iPhone SE2让路
  2. 10月23日见?疑似魅族16T预热海报曝光:定位大屏娱乐旗舰
  3. 余承东:华为P40或是鸿蒙系统首款手机,新机明年3月发布
  4. 华硕ROG游戏手机2跑分曝光:骁龙855 Plus加持 性能难逢对手
  5. 这首致喷子杠精的“键盘侠之歌” 唱出了多少人的心声
  6. 苏宁买买买!将收购家乐福80%股份 成为家乐福中国控股股东
  7. 红米K20 Pro拍照样张出炉:后置4800万像素高清三摄
  8. 好快!京东推出全新快递服务: 最快30分钟送达
  9. 滴滴试行“选择路线”功能 乘客可自主选择行驶路线
  10. Facebook合并WhatsApp和Instagram?德国:展开反垄断调查!