需求:用户进入后台个人中心,可扫码绑定微信小程序,后续不再需要输入密码,可直接扫码登录后台
扫码登录:用户微信扫码进入小程序,选择已绑定的账号登录

进入正题
——————————————————————————————

所有需要的参数因为公司业务需求都放在数据库,所以就出现了这一行代码

Map<String, Object> map = this.getSysConfig(“wxMiniprogram”);

redis有的话就用,没有就删了

这里特别提示一下,下面两个方法是放在一个公共的Utils包里面,由于该类没有注入到spring管理,导致后台查询失效,于是在公共类里面添加了需要的bean

protected RedisService redisService = SpringContextHolder.getBean(RedisService.class);
private ConfigService configService = SpringContextHolder.getBean(ConfigService.class);

公共类方法-1:获取生成小程序码的access_token

固定值:

授权类型
grant_type:client_credential
Token获取地址
accessTokenUrl:https://api.weixin.qq.com/cgi-bin/token

appid和appSecret在微信小程序自行查看

public String getAccessToken() {String access_token = null;try {access_token = (String) redisService.get("wxUserBindCodeAccesstoken");if (StringUtils.isBlank(access_token)) {Map<String, Object> map = this.getSysConfig("wxMiniprogram");Map<String, String> requestParam = new HashMap<String, String>();requestParam.put("grant_type", (String) map.get("grant_type"));requestParam.put("appid", (String) map.get("appid"));requestParam.put("secret", (String) map.get("appSecret"));String accessTokenUrl = (String) map.get("accessTokenUrl");Map<String, Object> extraParam = new HashMap<String, Object>();extraParam.put("type", "getToken");// 发起连接 sendPost 为一个请求各种接口而封装的函数,并转换JSON字符串为JSONObjectJSONObject jsonObject = JSON.parseObject(this.sendPost(accessTokenUrl, requestParam, extraParam));access_token = jsonObject.getString("access_token");// 缓存wxCodeAccesstokenredisService.set("wxUserBindCodeAccesstoken", access_token, RedisConstants.WX_CODE_TOKEN_TIMEOUT);}} catch (Exception e) {log.error("获取WXToken失败", e);return null;}return access_token;}

公共类方法-2:向指定 URL 发送POST方法的请求

/*** 向指定 URL 发送POST方法的请求* * @param url   发送请求的 URL* @param param 请求参数* @Param extraParam 额外参数* @return 所代表远程资源的响应结果*/
public String sendPost(String url, Map<String, ?> paramMap, Map<String, Object> extraParam) {// sendPost额外参数 判断用户是发起获取小程序码还是其他的连接String type = (String) extraParam.get("type");// 默认返回 HTTPS// URLConnection conn = null;// 默认返回HTTP,用接收返回数据HttpURLConnection conn = null;PrintWriter out = null;InputStream in = null;BufferedReader bufferedReader = null;String result = "";ByteArrayOutputStream bos = null;String param = "";if (type.equals("getQrCode")) {param = JSON.toJSONString(paramMap);} else {param = "";Iterator<String> it = paramMap.keySet().iterator();while (it.hasNext()) {String key = it.next();param += key + "=" + paramMap.get(key) + "&";}}try {URL realUrl = new URL(url);// 打开和URL之间的连接conn = (HttpURLConnection) realUrl.openConnection(); // 返回对象为 HttpsURLConnection// 设置通用的请求属性conn.setRequestProperty("accept", "*/*");conn.setRequestProperty("connection", "Keep-Alive");conn.setRequestProperty("Accept-Charset", "utf-8");conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");// 超时设置,防止网络异常的情况下,可能会导致程序僵死而不继续往下执行conn.setConnectTimeout(3000);conn.setReadTimeout(3000);// 发送POST请求必须设置如下两行conn.setDoOutput(true);conn.setDoInput(true);// 获取URLConnection对象对应的输出流out = new PrintWriter(conn.getOutputStream());// 发送请求参数out.print(param);// flush输出流的缓冲out.flush();// 定义BufferedReader输入流来读取URL的响应if (type.equals("getQrCode")) {Integer width = (Integer) paramMap.get("width");in = conn.getInputStream(); // 得到图片的二进制内容int leng = in.available();if (leng < 1000) { // 出现错误时,获取字符长度就一百不到,图片的话有几万的长度// 定义BufferedReader输入流来读取URL的响应bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));String line;while ((line = bufferedReader.readLine()) != null) {result += line;}log.error("调用微信小程序小程序码接口出错:" + result);// 清空 access_token 缓存redisService.del("wxUserBindCodeAccesstoken");return null;}// 修改图片的分辨率,分辨率太大打印纸不够大// BufferedInputStream in2 = new BufferedInputStream(conn.getInputStream());// 将文件二进制流修改为图片流Image srcImg = ImageIO.read(in);// 构建图片流BufferedImage buffImg = new BufferedImage(width, width, BufferedImage.TYPE_INT_RGB);// 绘制改变尺寸后的图buffImg.getGraphics().drawImage(srcImg.getScaledInstance(width, width, Image.SCALE_SMOOTH), 0, 0, null);// 将图片流修改为文件二进制流ByteArrayOutputStream os = new ByteArrayOutputStream();ImageIO.write(buffImg, "png", os);in = new ByteArrayInputStream(os.toByteArray());// 刷新,将重置为类似于首次创建时的状态buffImg.flush();srcImg.flush();// 设null是告诉jvm此资源可以回收buffImg = null; // 该io流不存在关闭函数srcImg = null; // 该io流不存在关闭函数os.close();bos = new ByteArrayOutputStream();byte[] b1 = new byte[1024];int len = -1;while ((len = in.read(b1)) != -1) {bos.write(b1, 0, len);}byte[] fileByte = bos.toByteArray(); // 转换为字节数组,方便转换成base64编码// 对字节数组转换成Base64字符串result = Base64.encodeBase64String(fileByte); // import org.apache.commons.codec.binary.Base64;return result;}bufferedReader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));String line;while ((line = bufferedReader.readLine()) != null) {result += line;}} catch (Exception e) {log.error(e.getMessage(), e);}// 使用finally块来关闭输出流、输入流finally {try {if (bufferedReader != null) {bufferedReader.close();}if (out != null) {out.close();}if (in != null) {in.close();}if (bos != null) {bos.close();}if (conn != null) {conn.disconnect();conn = null;}// 让系统回收资源,但不一定是回收刚才设成null的资源,可能是回收其他没用的资源。System.gc();} catch (IOException ex) {ex.printStackTrace();}}return result; // 返回的为JSON字符串}

获取绑定小程序码

  • page为扫码后进入的小程序页面地址,小程序必须已发布
  • WxUtils就是上面我说的自己写的公共类
  • 这里返回的小程序码是base64String格式的,前端解码需要this.qrcode = ‘data:image/png;base64,’ + response.data,response.data就是后台返回过去的数据,qrCode才是完整的小程序码

this.qrcode = ‘data:image/png;base64,’ + response.data

固定值:

小程序码生成地址
qrCodeUrl:https://api.weixin.qq.com/wxa/getwxacodeunlimit

这里涉及绑定逻辑,生成一个随机字符串作为小程序码的参数scene,并将该参数与当前登录用户绑定,存入redis;
生成小程序码之后,这时候用户在后台使用微信扫码,进入小程序;
用户授权之后,后台通过code换取openId,将接收到的scene与openId一同传回到后台;
后台在缓存中通过该scene查找user,存在则将绑定关系插入数据库,绑定由于有业务逻辑就不放上来了,需要判断是否已绑定,redis中scene和user绑定的有效期

// 获取16位随机字符串
String scene = UUID.randomUUID().toString().replaceAll("-", “”).substring(0, 16);
// 获取当前登录用户
User user = (User) this.getUser();
// 在缓存中将scene与user绑定 有效时间两分钟
redisService.set(scene, user, RedisConstants.WX_BIND_SCENE_USER_TIMEOUT);

获取微信绑定小程序码

/*** 获取微信绑定小程序码*/@Overridepublic Response<String> getBindQrcode() {WxUtils wxUtils = new WxUtils();// 从系统配置里获取小程序配置参数Map<String, Object> map = wxUtils.getSysConfig("wxMiniprogram");// sendPost方法的额外参数Map<String, Object> extraParam = new HashMap<String, Object>();// 小程序码宽度Integer width = Integer.valueOf((String) map.get("bindQrCodeWidth"));String access_token = wxUtils.getAccessToken();if (access_token == null) {return new Response<String>().fail("access_token为空!");}String qrCodeUrl = (String) map.get("qrCodeUrl");// qrCodeUrl 获取小程序码的接口头部 拼接完整的URlString url = qrCodeUrl + "?access_token=" + access_token;// 小程序的参数可查看官方文档Map<String, Object> requestParam = new HashMap<String, Object>();// 扫码后需要跳转的页面requestParam.put("page", (String) map.get("bindPage"));// 获取16位随机字符串String scene = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);// 获取当前登录用户User user = (User) this.getUser();// 在缓存中将scene与user绑定 有效时间两分钟redisService.set(scene, user, RedisConstants.WX_BIND_SCENE_USER_TIMEOUT);// 携带的参数requestParam.put("scene", scene);// 小程序码的宽度requestParam.put("width", width);log.info("绑定小程序小程序码scene:{}", scene);// sendPost额外参数 判断用户是发起获取小程序码还是其他的连接extraParam.put("type", "getQrCode");// 发起连接String base64String = wxUtils.sendPost(url, requestParam, extraParam);return new Response<String>().success(base64String);}

通过code换取openid

/*** 通过code换取openid*/@Overridepublic Response<Object> getOpenidByCode(String code) {WxUtils wxUtils = new WxUtils();// 获取系统小程序配置Map<String, Object> map = wxUtils.getSysConfig("wxMiniprogram");RestTemplate restTemplate = new RestTemplate();String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + map.get("appid") + "&secret="+ map.get("appSecret") + "&js_code=" + code + "&grant_type=authorization_code";String res = restTemplate.getForEntity(url, String.class).getBody();logger.info("获取openid请求:{}, 返回结果:{}", url, res);JSONObject resJson = JSONObject.parseObject(res);// 判断请求结果String errcode = resJson.getString("errcode");if (StringUtils.isBlank(errcode) || "0".equals(errcode)) {return new Response<Object>().success(resJson.getString("openid"));} else {return new Response<Object>().fail(resJson.getString("errcode") + ":" + resJson.getString("errmsg"));}}
扫码登录

这里登录的逻辑是生成一个随机字符串,同时作为二维码参数、后续的websocketId,将scene单独存入缓存;
此时生成小程序码base64字符串,用户扫码后进入小程序,通过code换取openId,再通过openId获取已绑定的用户列表(openId在绑定的时候已经跟用户一起存入数据库了),选择其中一个进行登录,将选中用户的userId与从后台获取的scene再传回后台,调用接口实现登录;
流程中所有的定时任务请自行编写

获取扫码登录小程序码

@Overridepublic Response<Object> getLoginQrcode() {WxUtils wxUtils = new WxUtils();// 从系统配置里获取小程序配置参数Map<String, Object> map = wxUtils.getSysConfig("wxMiniprogram");// sendPost方法的额外参数Map<String, Object> extraParam = new HashMap<String, Object>();// 二维码宽度Integer width = Integer.valueOf((String) map.get("loginQrCodeWidth"));String access_token = wxUtils.getAccessToken();if (access_token == null) {return new Response<Object>().fail("access_token为空!");}Map<String, Object> resultMap = new HashMap<String, Object>();String qrCodeUrl = (String) map.get("qrCodeUrl");// qrCodeUrl 获取小程序码的接口头部 拼接完整的URlString url = qrCodeUrl + "?access_token=" + access_token;// 小程序的参数可查看官方文档Map<String, Object> requestParam = new HashMap<String, Object>();// 扫码后需要跳转的页面requestParam.put("page", map.get("loginPage"));// 获取16位随机字符串String scene = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);// 登录二维码场景值,后续作为websocketIdresultMap.put("scene", scene);// 将随机参数存入缓存 有效时间两分钟redisService.set(scene, "", RedisConstants.WX_LOGIN_TIMEOUT);// 携带的参数requestParam.put("scene", scene);// 二维码的宽度requestParam.put("width", width);// sendPost额外参数 判断用户是发起获取二维码还是其他的连接extraParam.put("type", "getQrCode");// 发起连接String base64String = wxUtils.sendPost(url, requestParam, extraParam);resultMap.put("imgBase64", base64String);return new Response<Object>().success(resultMap);}

点击登录

/*** 用户扫码选择登录用户后调用该接口实现登录*/@Overridepublic Response<String> signinByQrCode(String userId, String scene) {// 检查scene是否有效String sceneValue = (String) redisService.get(scene);if (sceneValue != null) {// 生成token并绑定userUser user = userService.getById(userId);if (user != null) {String token = generateToken(user);redisService.set(scene, token, RedisConstants.WX_LOGIN_TIMEOUT);// 将随机参数存入缓存 有效时间两分钟return new Response<String>().success("扫码登录成功");} else {return new Response<String>().fail("登录用户不存在,请重新选择");}} else {return new Response<String>().fail("二维码已超时,请重新扫码");}}

——————————————————————————————————————
到这里基本上就结束了,前端使用的是vue+elementUi,我不怎么懂前端所以就不放代码了,放了反而会绕晕,不过东西也不多,说还缺什么吧大多就是一些定时任务了,前端的定时扫描啥的。

第一次写,如有错误请指正~

SSM通过微信小程序实现扫码登录及绑定相关推荐

  1. 微信小程序实现扫码一键连wifl

    微信小程序一键扫码连接WiFi 实例: // pages/connect/connect.js Page({ /*** 页面的初始数据*/ data: {wifiname:'wifi商家',ssid: ...

  2. 微信小程序订单扫码结算的步骤

    微信小程序订单扫码结算的步骤,在 小程序结算中,如果用户下单后到店自提或货到付款的方式,这种情况用户可以提现下单或预定下单,下单成功后,用户到店里自提或等待商家配送到家,在收到订单产品之后,商家扫码用 ...

  3. Java后台微信点餐小程序开发最新版笔记,Springboot+Mysql+Freemarker+Bootstrap+微信小程序实现扫码点餐小程序,包含语音提示,微信消息推送,网页管理后台

    由于之前的Java后台微信点餐小程序有些知识点过时了,所以今天重新出一版,把里面过时的知识点更新下 前五章是部署笔记,后面是知识点的详细讲解,大家可以先看部署笔记,部署起来后,再跟着详细知识学习. 第 ...

  4. 微信小程序手机扫码上传图片报错500

    报错截图如下: **错误产生环境:**微信小程序手机扫描二维码上传图片,一直是正常使用,没有做任何修改,突然有一天扫码上传图片的时候报错. **项目环境:**前后端分离,图片传到后端服务器. 找到问题 ...

  5. 自己实现微信小程序实现扫码点餐

    本人自己实现的一套小程序扫码点餐例子,如图: 1.登录时首页获得用户的权限: 2.首页,现只有扫码点餐,预约订餐功能未做! 3.点击扫码点餐时,调用扫码功能,识别餐做二维码,既可以访问相册,也可以直接 ...

  6. 微信小程序-实现扫码自动连接wifi(android)

    项目实路 饭店,商铺存在共享的wifi的地方,只需要贴出二维码,用户扫描后自动连接 小程序 缺点:android6版本 ios11版本 图片演示 实现代码(IOS没看懂文档说明 只简单的带过 希望能实 ...

  7. 微信小程序自定义扫码界面

    选择框架:wepy框架 调用微信扫码的api时, wx.scanCode({success (res) {console.log(res)} }) 这个界面是不支持在扫码界面做自定义界面功能的.解决方 ...

  8. 微信小程序—调用扫一扫功能,通过扫描二维码连接蓝牙模块

    使用微信小程序的扫码功能连接蓝牙,具体操作如下 实现流程图 Created with Raphaël 2.2.0准备好二维码小程序调用扫码功能小程序获取到二维码内容(我这里为蓝牙的名字)小程序通过搜索 ...

  9. 基于java SSM框架+微信小程序实现电子书城阅读器演示【附项目源码+论文说明】分享

    基于java SSM框架+微信小程序实现电子书城阅读器演示 摘要 而随着互联网技术的不断发展,互联网已经渗入到我们生活中的各个方面.移动设备的普及使我们的生活发生了翻天覆地的变化,这种变化也深刻影响着 ...

最新文章

  1. Effective C++ 1.0 -- 概述
  2. 30岁二刷博士,17个月发6篇一作获顶会最佳!现实版人生重开模拟器
  3. Yii中缓存依赖的处理
  4. Spring Boot 自动配置之条件注解
  5. Qt之Q_GLOBAL_STATIC创建全局静态对象
  6. Unity Android解决信息流广告关闭报错
  7. 【Vegas原创】X connection to localhost:11.0 broken (explicit kill or server shutdown)解决方法...
  8. OPENCV-7 学习笔记
  9. intention lock_写作技巧:你写出来的情节有用吗?好情节的原则——LOCK系统
  10. linux dev log设备文件,Linux中设备号及设备文件【转】
  11. cad在线转换低版本_资源分享/CAD版本转换器
  12. PowerVR SGX
  13. json 微信小程序 筛选_GitHub - zhengyangkang/sl-filter: uni -app 一款使用简单的筛选组件,适配app、微信小程序、H5。...
  14. python图形化编程 在线教程_使用Python Editor进行在线图形化编程
  15. 图像处理中像素和毫米的换算
  16. 阿里10年:一个普通技术人的成长之路
  17. 程序员如何接私活、外包的秘技
  18. 读后感----《我奋斗了18年才和你坐在一起喝咖啡》
  19. win10 +anaconda+pytorch_gpu
  20. COOX培训材料 — PMT(2.Operation)

热门文章

  1. QTP自动化测试权威指南(第二版)
  2. 3.16 使用铅笔工具和平滑工具绘制气球 [Illustrator CC教程]
  3. JAVA知识体系之数据库篇——MySQL
  4. Java SpringBoot下载文件超时
  5. HTTP请求方式GET/POST
  6. php环境安装使用方法,如何一键安装PHP环境(适合新手使用)
  7. iOS 苹果开发者账号续费-图文教程
  8. CAN一致性测试 上升沿与下降沿时间测试 跳变沿时间测试
  9. Linux如何添加用户及用户权限管理
  10. 网民“娱乐至上” 引领视频网站娱乐化趋势