场景:户扫描微信公众号的二维码,关注后自动登录网站,若已关注则直接登录。

逻辑:

  1. 系统生成带参数的临时二维码:参数 scene_str 自定义为唯一值(可以是uuid),临时二维码的生成方式参照官方接口的开发文档
  2. 用户使用微信扫描该二维码,关注后微信服务器会将关注事件的响应数据返回给我们的应用服务器:微信通过我们在公众号配置的“服务器地址(URL)”,将响应数据返回给我们的应用服务器,响应数据包括 参数 scene_str 和 openid
  3. 应用服务器将接收到的openid再次向微信服务器发起请求,获取该用户的信息(昵称、头像、地域、unionid(若绑定了微信开放平台,则有此参数))
  4. 将返回的信息存储到数据库,用于登录:特别是 scene_str 也要记录,因为需要根据这个唯一值来判断当前是谁在扫描关注并登录

准备工作:登录微信公众号平台,在基本配置下获取 AppID,AppSecret,“服务器地址(URL)”即“回调函数”,令牌Token。如下图:

  

本人用的开发框架是 springboot,代码如下:

  1. 后台代码:

    • HttpClientKit.java:封装https请求,调用微信接口

      package com.ht.website.utils;
      
      import java.io.BufferedReader;
      import java.io.InputStream;
      import java.io.InputStreamReader;
      import java.io.OutputStream;
      import java.net.URL;
      import java.security.cert.CertificateException;
      import java.security.cert.X509Certificate; import javax.net.ssl.HttpsURLConnection;
      import javax.net.ssl.SSLContext;
      import javax.net.ssl.SSLSocketFactory;
      import javax.net.ssl.TrustManager;
      import javax.net.ssl.X509TrustManager; import com.alibaba.fastjson.JSONObject; public class HttpClientKit { /**
      * https请求信任管理器
      * @author Timely-03
      */
      private static class TrustAnyTrustManager implements X509TrustManager { public X509Certificate[] getAcceptedIssuers() {
      return null;
      } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { }
      } /**
      * 发送https请求
      */
      private static JSONObject https(String requestUrl, String requestMethod, String submitData) {
      HttpsURLConnection httpsURLCon = null; try {
      // 设置https访问模式,采用SSL加密
      TrustManager[] tm = { new TrustAnyTrustManager() }; // 创建SSLContext对象,并使用我们指定的信任管理器初始化
      SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
      sslContext.init(null, tm, new java.security.SecureRandom()); // 从sslContext获取SSLSocketFactory
      SSLSocketFactory ssf = sslContext.getSocketFactory();
      URL url = new URL(requestUrl);
      httpsURLCon = (HttpsURLConnection) url.openConnection();
      httpsURLCon.setSSLSocketFactory(ssf);
      httpsURLCon.setDoInput(true);
      httpsURLCon.setDoOutput(true);
      httpsURLCon.setUseCaches(false);
      httpsURLCon.setRequestMethod(requestMethod);// 设置请求方式get;post if ("GET".equalsIgnoreCase(requestMethod)) {
      httpsURLCon.connect();
      } // 当需要有数据提交给微信接口时
      if (submitData != null) {
      OutputStream outputStream = httpsURLCon.getOutputStream();
      outputStream.write(submitData.getBytes(WSConst.ENCODE_UTF_8));
      outputStream.close();
      } // 从输入流读取返回内容
      InputStream inputStream = httpsURLCon.getInputStream();
      InputStreamReader inputStreamReader = new InputStreamReader(inputStream, WSConst.ENCODE_UTF_8);
      BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
      String str = null;
      StringBuffer buffer = new StringBuffer();
      while ((str = bufferedReader.readLine()) != null) {
      buffer.append(str);
      } // 释放资源
      bufferedReader.close();
      inputStreamReader.close();
      inputStream.close();
      inputStream = null;
      httpsURLCon.disconnect(); return JSONObject.parseObject(buffer.toString()); } catch (Exception e) {
      throw new RuntimeException(e);
      } finally {
      if (httpsURLCon != null) {
      httpsURLCon.disconnect();
      }
      }
      } /**
      * 发送https请求,请求方法:POST
      * @param requestUrl 请求地址,比如:https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=
      * @param submitData 提交参数
      * @return 返回请求结果字符串
      */
      public static JSONObject httpsPost(String requestUrl, String submitData) {
      return https(requestUrl, "POST", submitData);
      } /**
      * 发送https请求,请求方法:GET
      * @param requestUrl 请求地址,比如:https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=
      * @param submitData 提交参数
      * @return 返回请求结果字符串
      */
      public static JSONObject httpsGet(String requestUrl, String submitData) {
      return https(requestUrl, "GET", submitData);
      } }
    • application.properties:配置微信appid,appSecret
      server.port=8088
      
      ##############数据连接开始
      #mysql
      spring.datasource.url=jdbc:mysql://10.10.10.10:3306/database_wc?useUnicode=true&characterEncoding=utf8
      spring.datasource.driver-class-name=com.mysql.jdbc.Driver
      spring.datasource.username=root
      spring.datasource.password=123456
      spring.datasource.dbcp2.validation-query=SELECT 1
      spring.datasource.dbcp2.time-between-eviction-runs-millis=3600000
      ##############数据库连接结束 ##############前端模板开始
      spring.thymeleaf.suffix=.html
      spring.thymeleaf.cache=false
      spring.thymeleaf.prefix=/
      ##############前端模板结束 ##############日志配置开始
      logging.level.root=INFO
      logging.level.org.springframework.web=INFO
      ##############日志配置结束 ##############微信配置参数开始
      proconfig.wechatAppId = wx21abcdbafe0aaac
      proconfig.wechatAppSecret = e472b01d2fdsadfsafdsafdsafad
      ##############微信配置参数结束
    • WSConfig.java:获取配置文件配置信息
      package com.ht.website.utils;
      
      import org.springframework.boot.context.properties.ConfigurationProperties;
      
      /**
      * 配置文件类,获取对应配置文件中以 proconfig 开头的属性值
      * @author Timely-03
      */
      @ConfigurationProperties(prefix = "proconfig")
      public class WSConfig { //微信AppId
      private String wechatAppId;
      //微信AppSecret
      private String wechatAppSecret; public String getWechatAppId() {
      return wechatAppId;
      } public void setWechatAppId(String wechatAppId) {
      this.wechatAppId = wechatAppId;
      } public String getWechatAppSecret() {
      return wechatAppSecret;
      } public void setWechatAppSecret(String wechatAppSecret) {
      this.wechatAppSecret = wechatAppSecret;
      } }
    • WeChatAccessToken.java:定时获取微信access_token的类,这里用的Springboot的cache 和 定时器来管理access_token
      package com.ht.website.wechat;
      
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.cache.annotation.CachePut;
      import org.springframework.cache.annotation.Cacheable;
      import org.springframework.scheduling.annotation.Scheduled;
      import org.springframework.stereotype.Service; import com.alibaba.fastjson.JSONObject;
      import com.ht.website.utils.HttpClientKit;
      import com.ht.website.utils.WSConfig; /**
      * 微信 access_token 生成并缓存
      * 1.调用微信接口,获取access_token
      * 2.存入缓存,缓存名称为“accesstoken”
      * 3.定时获取access_token,更新“accesstoken”缓存
      * @author Timely-03
      *
      */
      @Service
      public class WeChatAccessToken { private static final Logger _log = LoggerFactory.getLogger(WeChatAccessToken.class); // 获取access_token url
      private static final String _URL_GET_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; // 记录更新
      private int _fixedRateCount = 0; // 属性配置 ProConfig
      @Autowired
      private WSConfig _wsConfig; /**
      * 缓存 token
      * @return token信息
      */
      @Cacheable(cacheNames= "accesstokencache")
      public String getAccessToken() { return getAccessTokenStr();
      } /**
      * 更新缓存token,定时更新(100分钟更新一次)
      * @return token信息
      */
      @CachePut(cacheNames = "accesstokencache")
      @Scheduled(fixedRate = 100*60*1000)
      public String updateAccessToken() { return getAccessTokenStr();
      } /**
      * 获取access_token字符串
      * @return 获取{"access_token":"ACCESS_TOKEN","expires_in":7200}中的access_token
      */
      private String getAccessTokenStr() {
      // 调用接口,获取access_token
      JSONObject accessTokenInfo = getAccessTokenInfo();
      if (accessTokenInfo == null) {
      return null;
      } return accessTokenInfo.containsKey("access_token") ? accessTokenInfo.getString("access_token") : null;
      } /**
      * 调用微信接口,获取access_token
      * @return 正常情况下返回:{"access_token":"ACCESS_TOKEN","expires_in":7200}<br/>错误时返回错误码:{"errcode":40013,"errmsg":"invalid appid"}
      */
      private JSONObject getAccessTokenInfo() {
      // 微信appId
      String appId = _wsConfig.getWechatAppId();
      // 微信 appSecret
      String appSecret = _wsConfig.getWechatAppSecret(); if (appId.isEmpty() || appSecret.isEmpty()) {
      return null;
      } _fixedRateCount++; _log.info("fixedRateCount = " + _fixedRateCount); //调用微信接口url,返回access_token信息
      JSONObject responseJson = HttpClientKit.httpsGet(_URL_GET_ACCESS_TOKEN.replace("APPID", appId).replace("APPSECRET", appSecret), null); if (responseJson.containsKey("access_token") == false) {
      _log.info("定时刷新access_token失败,微信返回的信息是" + responseJson.toJSONString());
      } return responseJson;
      } }
    • WeChatService.java:调用微信接口服务类
      package com.ht.website.wechat;
      
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service; import com.alibaba.fastjson.JSONObject;
      import com.ht.website.utils.HttpClientKit;
      import com.ht.website.utils.WSConst; @Service
      public class WeChatService { private static final Logger _log = LoggerFactory.getLogger(WeChatService.class); // 生成带参数的二维码
      public static final String _URL_CREATE_QRCODE = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=";
      // 获取带参数的二维码
      public static final String _URL_GET_QRCODE = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket="; // 获取关注用户信息
      public static final String _URL_GET_USERINFO = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="; // 二维码业务类型:【QRLOGIN:登录二维码】
      public static final String _QR_TYPE_LOGIN = "WSLOGIN-";
      public static final String _QR_TYPE_LOGIN_SUPPLIER = "WSLOGIN-SUPPLIER-";
      public static final String _QR_TYPE_LOGIN_CUSTOMER = "WSLOGIN-CUSTOMER-"; @Autowired
      private WeChatAccessToken _wechatAccessToken; /**
      * 获取带参数的 临时二维码(登录用)
      * 如果返回access_token过期,则重新调用一次获取access_token的方法,再用新的access_token去生成二维码
      * @return
      */
      public JSONObject getQRCodeInfoLogin(String scene_str) {
      // 生成临时二维码
      JSONObject qrcodeInfo = getQrCodeInfo(scene_str); // 生成二维码返回消息:如果access_token过期,则执行一次获取access_token,并且重新生成临时二维码
      if (WSConst.WECHAT_ERROR_CODE_40001.equals(qrcodeInfo.getString("errcode"))) {
      _wechatAccessToken.updateAccessToken(); // 生成临时二维码
      qrcodeInfo = getQrCodeInfo(scene_str);
      } return qrcodeInfo;
      } /**
      * 获取带参数的 临时二维码
      * @return
      */
      private JSONObject getQrCodeInfo(String scene_str) { _log.info("access_token = " + _wechatAccessToken.getAccessToken()); // access_token验证
      String accessToken = _wechatAccessToken.getAccessToken(); // 请求参数: scene(场景字符串)
      JSONObject scene = new JSONObject();
      scene.put("scene_str", scene_str); // 长度:8 + 36 = 44 // 请求参数:action_info
      JSONObject actioninfo = new JSONObject();
      actioninfo.put("scene", scene); // 获取二维码提交的参数
      JSONObject param = new JSONObject();
      param.put("expire_seconds", 120); // 二维码过期时间:120秒
      param.put("action_name", "QR_STR_SCENE"); // 字符串形式的二维码参数
      param.put("action_info", actioninfo); return HttpClientKit.httpsPost(_URL_CREATE_QRCODE + accessToken, param.toJSONString());
      } /**
      * 通过openid,获取关注用户信息
      * @param openid
      * @return
      * @throws Exception
      */
      public JSONObject getUserInfoByOpenId(String openid) throws Exception { return HttpClientKit.httpsGet(_URL_GET_USERINFO + _wechatAccessToken.getAccessToken(), null);
      }
      }
    • WeChatController.java:生成临时二维码,将二维码的 URL 返回到前端;接收微信的关注事件;登录验证
      package com.ht.website.controller;
      
      import java.io.InputStream;
      import java.util.List;
      import java.util.UUID; import javax.servlet.http.HttpServletRequest; import org.dom4j.Element;
      import org.dom4j.io.SAXReader;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Controller;
      import org.springframework.ui.Model;
      import org.springframework.util.StringUtils;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RequestMethod;
      import org.springframework.web.bind.annotation.ResponseBody; import com.alibaba.fastjson.JSONObject;
      import com.ht.website.entity.WeChatUser;
      import com.ht.website.service.WeChatUserService;
      import com.ht.website.wechat.WeChatService; /**
      * 微信相关控制器
      * @author Timely-03
      */
      @Controller
      @RequestMapping(value="/wechat")
      public class WeChatController { private static final Logger _log = LoggerFactory.getLogger(WeChatController.class); //微信接口服务类
      @Autowired
      private WeChatService _weChatService; //微信用户服务类
      @Autowired
      private WeChatUserService _weChatUserService; /**
      * 跳到login页面,并生成登录二维码的URL
      */
      @RequestMapping(value = "/login",method = RequestMethod.GET)
      public String login(Model model, String eventKey) { // 带参数二维码的 scene_str:QRLOGIN-{UUID},此字符串会当作关注事件的eventKey返回,写入到数据库表的eventKey中
      String scene_str = WeChatService._QR_TYPE_LOGIN + UUID.randomUUID(); // 获取登录二维码
      JSONObject qrcodeInfo = _weChatService.getQRCodeInfoLogin(scene_str);
      if (qrcodeInfo.containsKey("ticket")) {
      model.addAttribute("qrcodeurl", WeChatService._URL_GET_QRCODE + qrcodeInfo.getString("ticket"));
      } model.addAttribute("eventKey", scene_str); _log.info("获取登录二维码:" + qrcodeInfo.toJSONString()); return "login";
      } /**
      * 回调函数,配置在微信公众号的服务器地址URL中,接收微信的推送事件
      * @param httpServletRequest
      * @throws Exception
      */
      @RequestMapping(value = "/channel")
      public void channel(HttpServletRequest httpServletRequest) throws Exception {
      JSONObject callBackInfo = xmlToJson(httpServletRequest); //获取回调信息
      //下面是返回的xml
      //<xml><ToUserName><![CDATA[gh_f6b4da984c87]]></ToUserName> //微信公众号的微信号
      //<FromUserName><![CDATA[oJxRO1Y2NgWJ9gMDyE3LwAYUNdAs]]></FromUserName> //openid用于获取用户信息,做登录使用
      //<CreateTime>20190531</CreateTime> //回调时间
      //<MsgType><![CDATA[event]]></MsgType>
      //<Event><![CDATA[SCAN]]></Event>
      //<EventKey><![CDATA[lrfun.com.UxJkWC1531967386903]]></EventKey> //上面自定义的参数(scene_str)
      //<Ticket><![CDATA[gQF57zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyY2ljbjB3RGtkZWwxbExLY3hyMVMAAgTvM0NbAwSAOgkA]]></Ticket> //换取二维码的ticket
      //</xml>
      if (callBackInfo != null && StringUtils.isEmpty(callBackInfo.getString("FromUserName")) == false) {
      // 通过openid获取用户信息
      JSONObject wechatUserInfo = _weChatService.getUserInfoByOpenId(callBackInfo.getString("FromUserName"));
      // 将数据写入到数据库中,前面自定义的参数(scene_str)也需记录到数据库中,后面用于检测匹配登录
      // INSERT INTO wechat_user_info......(数据库操作)
      }
      } /**
      * 是否登录验证,如果在表中找到了当前的eventKey,则表示是当前用户的关注登录动作:
      * 1. eventKey在用户关注后,微信将关注的事件,通过配置的“服务器地址URL”推送出来,返回到channel方法中
      * 2. channel方法将eventKey写入到用户表中
      * 3. 前端用定时器,以1秒的频率不停的调用checkLogin请求,通过eventKey到用户表中检测是否存在这个eventKey的数据
      */
      @RequestMapping(value = "/checkLogin")
      @ResponseBody
      public JSONObject checkLogin(String eventKey) {
      JSONObject retObj = new JSONObject(); _log.info("eventKey = " + eventKey); // 取用户信息
      List<WeChatUser> wechatUserList = _weChatUserService.getUserByEventKey(eventKey);
      if (wechatUserList.size() > 0) {
      retObj.put("errCode", "0");
      retObj.put("errMsg", "登录成功!");
      retObj.put("eventKey", eventKey);
      } else {
      retObj.put("errCode", "-1");
      retObj.put("errMsg", "登录失败");
      } return retObj;
      } // xml转为map
      private JSONObject xmlToJson(HttpServletRequest httpServletRequest) {
      JSONObject info = new JSONObject(); try {
      InputStream inputStream = httpServletRequest.getInputStream();
      SAXReader reader = new SAXReader(); // 读取输入流
      org.dom4j.Document document = reader.read(inputStream);
      Element root = document.getRootElement(); // 得到xml根元素
      List<Element> elementList = root.elements(); // 得到根元素的所有子节点 // 遍历所有子节点
      for (Element e : elementList) {
      info.put(e.getName(), e.getText());
      } // 释放资源
      inputStream.close();
      inputStream = null; return info; } catch (Exception e) {
      e.getMessage();
      } return null;
      } }
  2. 前端代码:
    • login.html:显示登录二维码,定时请求后台

      <!DOCTYPE html>
      <!-- saved from url=(0058)http://www.17sucai.com/preview/1/2017-11-05/nav/index.html -->
      <html lang="zh">
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>扫描登录</title> </head>
      <body>
      <!-- 内容 -->
      <div id="content" class="bg-color-gray">
      <div class="login-container">
      <div class="row padding-20">
      <div class="col-sm-12">
      <div class="padding-20">
      <span id="loginMsg" style="font-size: 25px;">扫描二维码注册/登录</span>
      </div>
      <img th:src="${qrcodeurl}" /> <input type="hidden" id="eventKey" name="eventKey" th:value="${eventKey}">
      <div class="padding-20">
      <i class="glyphicon glyphicon-qrcode"></i>&nbsp;微信扫描二维码
      </div>
      </div>
      </div>
      </div>
      </div> <script type="text/javascript">
      var wechatCheckLoginFunTimer = null;
      $(document).ready(function () {
      wechatCheckLoginFunTimer = setInterval("wechatCheckLogin()", 1000);
      }); function wechatCheckLogin(){
      $.post("/wechat/checkLogin", {eventKey:$("input#eventKey").val()}, function(data){ if(data.errCode == "0"){
      clearInterval(wechatCheckLoginFunTimer);
      $("#loginMsg").text(data.errMsg); //停顿1秒
      setTimeout(function(){
      window.location.href = "/user/loginSuccess?eventKey=" + data.eventKey;
      },1000) } else {
      $("input#eventKey").innerHTML = data.errMsg;
      } }, "JSON");
      }
      </script> </body>
      </html>

      扫描登录逻辑到此完成!

java 扫描微信公众号二维码,关注并登录逻辑的更多相关文章

  1. Java 扫描微信公众号二维码,关注并自动登录网站

    https://blog.csdn.net/qq_42851002/article/details/81327770 场景:用户扫描微信公众号的二维码,关注后自动登录网站,若已关注则直接登录. 逻辑: ...

  2. 官网app下载更换成微信公众号二维码 测试

    微信现在很火啊.公司官网原先提供的ios和andriod的app下载链接要求切换成微信公众号二维码.简单的替换,大家都说不需要测试直接上线.还是测了下. 1 验证所有与下载相关的信息都已去除. 包括下 ...

  3. 在next主题添加微信公众号二维码

    在侧边栏添加微信公众号二维码 首先,当然是准备一张微信公众号二维码.有两种添加方式,添加到侧边栏或者添加到推文的结尾处.我的next主题是7.x版本的,使用的主题是Gemini,设置的侧栏显示方式是一 ...

  4. php微信生成微信公众号二维码扫描进入公众号带参数

    https://blog.csdn.net/qq_22823581/article/details/80248555 <?php namespace app\api\model; set_tim ...

  5. Java 获取微信小程序二维码(可以指定小程序页面 与 动态参数)

    一.准备工作 微信公众平台接口调试工具 小程序的唯一标识(appid) 小程序的密钥(secret) 二.获取access_token 打开微信公众平台接口调试工具,在参数列表中输入小程序的appid ...

  6. Java获取微信小程序二维码

    tip:通过该接口,仅能生成已发布的小程序的二维码. tip:可以在开发者工具预览时生成开发版的带参二维码. tip:接口A加上接口C,总共生成的码数量限制为100,000,请谨慎调用. tip: P ...

  7. 微信小程序二维码是无法识别二维码跳转到小程序

    今天测试了一下,微信小程序圆形二维码是不能直接识别跳转到小程序: 但h5页面的那种微信公众号二维码是可以直接识别

  8. Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发

    接入微信公众平台开发,开发者需要按照如下步骤完成: 1.填写服务器配置 2.验证服务器地址的有效性 3.依据接口文档实现业务逻辑 资料准备: 1.一个可以访问的外网,即80的访问端口,因为微信公众号接 ...

  9. ESA2GJK1DH1K微信小程序篇: 测试微信小程序扫描Air202上面的二维码绑定设备,并通过MQTT控制设备

    前言 一,微信小程序篇小程序下载(该功能为小程序篇基础功能源码) 实现功能概要 微信小程序通过扫描GPRS上的二维码,绑定GPRS设备.然后使用小程序通过GPRS远程控制开发板上的继电器, 远程显示单 ...

随机推荐

  1. java.net.NoRouteToHostException: Cannot assign requested address 问题分析(端口被用完的解决方法)

    问题: 错误原因: 由于liunx 分配的客户端连接端口用尽,无法建立socket连接所致,虽然socket正常关闭,但是端口不是立即释放,而是处于 TIME_WAIT 状态,默认等待60s后释放.查 ...

  2. Python - Django - 添加首页尾页上一页下一页

    添加首页和尾页: views.py: from django.shortcuts import render from app01 import models def book_list(reques ...

  3. 【opencv】opencv函数isContinuous

    isContinuous 参考 1. opencv_isContinuous; 完

  4. JS扩展Array.prototype引发的问题及解决方法

    遇到的问题 一上班收到个bug,写的表单联动插件在ie里面会出现js源码,当时有点意外,从没出现过这问题. 问题的原由 为什么会出现一个function呢?其它调用的插件的页面为什么没有这问题? 控制 ...

  5. Linux配置Docker镜像加速器

    Docker默认镜像为官方镜像,可以配置成国内加速器提高速度 登录阿里云控制台,搜索容器镜像服务获取到镜像加速服务地址 新建配置文件 /etc/docker/daemon.json 输入以下内容 { ...

  6. Python3之内建模块datetime

    datetime datetime是python处理日期和时间的标准库 获取当前日期和时间 >>> from datetime import datetime #获取当前的datet ...

  7. Data - 【转】数据分析的道与术

    简要说明 本文来自网络流传的"百度内部培训PPT - 数据分析的道与术",版权属于"百度",如有冒犯,即刻删除. PDF下载 - 数据分析的道与术 什么是数据分 ...

  8. Nginx负载均衡-如何自定义URL中的hash key2

    upstream backend1 {            server 192.168.3.236:555;            server 192.168.3.236:222;        ...

  9. Actor模型的状态(State)+行为(Behavior)+邮箱(Mailbox)

    状态(State)+行为(Behavior)+邮箱(Mailbox) 基于Actor模型的CQRS.ES解决方案分享 开场白 大家晚上好,我是郑承良,跟大家分享的话题是<基于Actor模型的CQ ...

  10. Jira强制退出时(如意外停电)再启动报Locked错误的几个解决办法

    查看jira_home的路径在/opt/atlassian/jira/atlassian-jira/WEB-INF/classes/jira-application.properties文件中查看 方 ...