业务需求
大确幸网站实现扫描二维码关注微信公众号,如果已经关注公众号就自动登陆网站并获取其微信昵称,头像等信息,如果用户未关注就等用户关注公众号后自动登陆网站
--如果用户已关注公众号,网站端直接自动登陆,如果没有关注,就等用户关注公众号之后网站端自动登陆
(目前已经完成了这个功能,示例网址:https://love.daquexing.com/ 大确幸-新社交,新生活,一个聚合百万单身年青的社群。大确幸是一个有温度的社区,宗旨是帮更多适龄单身青年解决单身问题。)
做微信扫码登陆,生成二维码必须是微信公众号中绑定的域这个域名,网站生成不了二维码(网站与微信服务器不是同一个域名) ,而是调用微信系统的接口获取二维码,用户扫码后也是请求微信服务器 。
ok 以上内容参考引用出自:
《网站实现扫描二维码关注微信公众号,自动登陆网站并获取其信息 》
《方案优化:网站实现扫描二维码关注微信公众号,自动登陆网站并获取其信息》
网上还有一篇文章推荐:
《微信扫描自定义二维码关注公众号》
如果以上三篇你都看懂了, 下面就简单, 或者你都不用看了。
微信公众平台技术文档:
获取access_token
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183
生成带参数的二维码
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433542
前端页面实现相关js
https://love.daquexing.com/theme/default/js/modules/authc.js
前端获取二维码方法:
@RequestMapping(value ="/qrcode", method = RequestMethod.GET)public @ResponseBodyData getqrcode(@RequestParam(value ="f")Stringf) {Data data = Data.failure("操作失败");Map map =newHashMap<>();Stringtimestamp = System.currentTimeMillis() +"";if("m".equals(f)) {timestamp ="m"+ timestamp;}map.put("timestamp", timestamp);// 获取二维码链接Stringresult = HttpKit.get(env.getProperty("api.url.wx_get_qrcode") + timestamp);if(StringUtils.isNotEmpty(result)) {JSONObject res =JSON.parseObject(result);map.put("ticket", res.get("ticket").toString());}returnData.success(map);}
/** * 登录 * *@paramusername *@paramtimestamp *@return*/@RequestMapping(value ="/wechat", method = RequestMethod.POST)public@ResponseBodyDatawechatlogin(String username, String timestamp)throwsException{ Data data = Data.failure("操作失败");//重置序列化redisTemplate.setValueSerializer(newGenericJackson2JsonRedisSerializer());if(StringUtils.isBlank(username) || StringUtils.isBlank(timestamp)) {returndata; }// 获取用户if(redisTemplate.opsForValue().get("wechat_"+ timestamp) ==null) { data.setMessage("获取用户失败");returndata; }// 其他登录逻辑。。。。。。。}
后台服务的websocket 实现packagecom.lotres.mp.controller;importnet.sf.json.JSONObject;importorg.springframework.stereotype.Component;importjavax.websocket.*;importjavax.websocket.server.PathParam;importjavax.websocket.server.ServerEndpoint;importjava.io.IOException;importjava.util.Hashtable;importjava.util.concurrent.ConcurrentHashMap;importjava.util.concurrent.ConcurrentMap;/** *@ServerEndpoint注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端, * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端 */@Component@ServerEndpoint("/websocket/wechat/{timestamp}")publicclassWebSocketController{//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。privatestaticintonlineCount =0;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识//private static CopyOnWriteArraySet webSocketSet = new CopyOnWriteArraySet();privatestaticConcurrentMap webSocketMap =newConcurrentHashMap();//与某个客户端的连接会话,需要通过它来给客户端发送数据privateSession session;/** * 连接建立成功调用的方法 * *@paramsession 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 */@OnOpenpublicvoidonOpen(@PathParam("timestamp")String timestamp, Session session){this.session = session; webSocketMap.put(timestamp,this);//在线数加1System.out.println("唯一key为:"+ timestamp); }/**
* 连接关闭调用的方法
*/@OnClosepublicvoidonClose(@PathParam("timestamp")String timestamp){ webSocketMap.remove(timestamp);//从map中删除}/** * 收到客户端消息后调用的方法 * *@parammessage 客户端发送过来的消息 *@paramsession 可选的参数 */@OnMessagepublicvoidonMessage(String message, Session session){ System.out.println("来自客户端的消息:"+ message); JSONObject jsonobject = JSONObject.fromObject(message); Hashtable params = (Hashtable) JSONObject.toBean(jsonobject, Hashtable.class);//群发消息WebSocketController webSocketController = webSocketMap.get(params.get("equipmentType"));try{ webSocketController.sendMessage((String) params.get("nickname")); }catch(IOException e) { e.printStackTrace(); } }/** * 发生错误时调用 * *@paramsession *@paramerror */@OnErrorpublicvoidonError(Session session, Throwable error){ System.out.println("发生错误"); error.printStackTrace(); }/** * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。 * *@parammessage *@throwsIOException */publicvoidsendMessage(String message)throwsIOException{this.session.getBasicRemote().sendText(message);//this.session.getAsyncRemote().sendText(message);}}
公众号后台配置
后台服务程序参考
https://github.com/binarywang/weixin-java-mp-demo-springboot
!!!好了,微信扫码关注公众号登录基本就实现了。 本系统实现直接使用了websocket 机制, 没有使用js 轮询检测用户是否已经扫码关注的方法。 轮询方法实现就是当系统生成带参数二维码后,获取到了后台生成的timestamp参数,前端js就开始轮询(例如:每三秒请求一次)。
致谢: 前面参考的几篇文章作者。
顺便提一下,我们系统使用了开源 https://gitee.com/mtons/mblog. 在此表示感谢!
最后,希望本文对你有帮助,欢迎体验一下
https://love.daquexing.com/login
如果你还有其他疑问,可以加我微信咨询
预告:《微信扫描自定义二维码关注公众号并登录(二)移动端/微信端的设计与实现》