一、appsettings.json定义小程序配置信息

"WX": {
  "AppId": "wx88822730803edd44",
  "AppSecret": "75b269042e8b5026e6ed14aa24ba9353",
  "Templates": {
  "Audit": {
    "TemplateId": "aBaIjTsPBluYtj2tzotzpowsDDBGLhXQkwrScupnQsM",
    "PageUrl": "/pages/index/formAudit?formId={0}&tableId={1}",
    "MiniprogramState": "developer",
    "Lang": "zh_TW",
    "Data": {
        "Title": "thing6",
        "Content": "thing19",
        "Date": "date9"
      }
    }
  },
  "SignatureToken": "aaaaaa",
  "MessageSendUrl": "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token={0}",
  "AccessTokenUrl": "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}"
}

二、编写通用类加载配置

using System;
using System.Text;
using System.Security.Cryptography;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json; namespace WXERP.Services
{
/// <summary>
/// 项目公有静态类
/// </summary>
public class Common
{
/// <summary>
/// 獲取根目錄
/// </summary>
public static string AppRoot => Environment.CurrentDirectory;// AppContext.BaseDirectory;
/// <summary>
/// 獲取項目配置
/// </summary>
public static IConfiguration Configuration { get; set; }
/// <summary>
/// 加載項目配置
/// </summary>
static Common()
{
  Configuration = new ConfigurationBuilder()
  .Add(new JsonConfigurationSource
  {
    Path = "appsettings.json",
    ReloadOnChange = true //当appsettings.json被修改时重新加载
  })
  .Build();
} /// <summary>
/// SHA1加密
/// </summary>
/// <param name="content">需要加密的字符串</param>
/// <returns>返回40位大寫字符串</returns>
public static string SHA1(string content)
{
  try
  {
    SHA1 sha1 = new SHA1CryptoServiceProvider();
    byte[] bytes_in = Encoding.UTF8.GetBytes(content);
    byte[] bytes_out = sha1.ComputeHash(bytes_in);
    sha1.Dispose();
    string result = BitConverter.ToString(bytes_out);
    result = result.Replace("-", "");
    return result;
  }
  catch (Exception ex)
  {
    throw new Exception("Error in SHA1: " + ex.Message);
  }
} }
}

三、编写HttpHelper请求类

using System;
using System.Text;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Collections.Generic; namespace WXERP.Services
{
/// <summary>
/// HTTP請求輔助類
/// </summary>
public class HttpHelper
{
/// <summary>
/// post同步請求
/// </summary>
/// <param name="url">地址</param>
/// <param name="postData">數據</param>
/// <param name="contentType">application/xml、application/json、application/text、application/x-www-form-urlencoded</param>
/// <param name="headers">請求頭</param>
/// <returns></returns>
public static string HttpPost(string url, string postData = null, string contentType = null, Dictionary<string, string> headers = null)
{
  using HttpClient client = new HttpClient();   if (headers != null)
  {
    foreach (var header in headers)
    client.DefaultRequestHeaders.Add(header.Key, header.Value);
  }   postData ??= "";
  using HttpContent httpContent = new StringContent(postData, Encoding.UTF8);
  if (contentType != null)
  httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);   HttpResponseMessage response = client.PostAsync(url, httpContent).Result;
  return response.Content.ReadAsStringAsync().Result;
} /// <summary>
/// post異步請求
/// </summary>
/// <param name="url">地址</param>
/// <param name="postData">數據</param>
/// <param name="contentType">application/xml、application/json、application/text、application/x-www-form-urlencoded</param>
/// <param name="timeOut">請求超時時間</param>
/// <param name="headers">請求頭</param>
/// <returns></returns>
public static async Task<string> HttpPostAsync(string url, string postData = null, string contentType = null, int timeOut = 30, Dictionary<string, string> headers = null)
{
  using HttpClient client = new HttpClient();
  client.Timeout = new TimeSpan(0, 0, timeOut);   if (headers != null)
  {
    foreach (var header in headers)
    client.DefaultRequestHeaders.Add(header.Key, header.Value);
  }   postData ??= "";
  using HttpContent httpContent = new StringContent(postData, Encoding.UTF8);
  if (contentType != null)
  httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);   HttpResponseMessage response = await client.PostAsync(url, httpContent);
  return await response.Content.ReadAsStringAsync();
} /// <summary>
/// get同步請求
/// </summary>
/// <param name="url">地址</param>
/// <param name="headers">請求頭</param>
/// <returns></returns>
public static string HttpGet(string url, Dictionary<string, string> headers = null)
{
  using HttpClient client = new HttpClient();   if (headers != null)
  {
  foreach (var header in headers)
  client.DefaultRequestHeaders.Add(header.Key, header.Value);
  }   HttpResponseMessage response = client.GetAsync(url).Result;
  return response.Content.ReadAsStringAsync().Result;
} /// <summary>
/// get異步請求
/// </summary>
/// <param name="url"></param>
/// <param name="headers"></param>
/// <returns></returns>
public static async Task<string> HttpGetAsync(string url, Dictionary<string, string> headers = null)
{
  using HttpClient client = new HttpClient();   if (headers != null)
  {
    foreach (var header in headers)
    client.DefaultRequestHeaders.Add(header.Key, header.Value);
  }   HttpResponseMessage response = await client.GetAsync(url);
  return await response.Content.ReadAsStringAsync();
} }
}

四、在sqlserver下存储并获取openid,这个主要是因为提交消息并不是在微信小程序端,如果是在微信小程序上发起订阅消息,可以忽略这个步骤

// 创建数据库表

create table TBSF_Conmmunicate_WXUser
(
  ID int identity(1,1) primary key,
  Staff_ID varchar(10),
  OpenId varchar(50),
  SessionKey varchar(50),
  UnionId varchar(50),
  IsValid bit,
) // SqlHelper数据库辅助类来自于CommunicationOperateDBUtility,可以自己编写 using System.Data;
using System.Text;
using CommunicationOperateDBUtility; namespace WXERP.Services.CommunicationOperateDAL
{
/// <summary>
/// 微信信息
/// </summary>
public class WXInforDeal
{
  private SqlHelper sqlHelper = null;
  /// <summary>
  /// 初始化數據庫輔助對象
  /// </summary>
  /// <param name="con"></param>
  public WXInforDeal(object con)
  {
    sqlHelper = new SqlHelper(con);
  }
  /// <summary>
  /// 獲取微信登陸用戶信息
  /// </summary>
  /// <param name="staffIdList">工號</param>
  /// <returns></returns>
  public DataSet GetLoginUserInfo(string staffIdList)
  {
    DataSet ds = new DataSet();
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.Append(" SELECT distinct OpenId FROM ");
    stringBuilder.Append(" TBSF_Conmmunicate_WXUser WHERE Staff_ID IN (");
    stringBuilder.Append(staffIdList);
    stringBuilder.Append(")");
    string strSql = stringBuilder.ToString();
    sqlHelper.DBRunSql(strSql, ref ds);
    return ds;
  }
}
}

五、编写订阅消息基类模型

using System;
using System.Data;
using Newtonsoft.Json;
using System.Collections.Generic;
using WXERP.Services.CommunicationOperateDAL; namespace WXERP.Models
{
/// <summary>
/// 訂閲消息請求模型
/// </summary>
public class SubscribeMessageModel
{
  /// <summary>
  /// 初始化審核訂閲消息
  /// </summary>
  /// <param name="dbTransOrCnn">數據庫事務</param>
  /// <param name="nextAuditStaffId">下一個審核通知用戶工號</param>
  public SubscribeMessageModel(object dbTransOrCnn, string nextAuditStaffId)
  {
    WXInforDeal wxInfoDeal = new WXInforDeal(dbTransOrCnn);
    DataSet wxUserInfo = wxInfoDeal.GetLoginUserInfo(nextAuditStaffId);
    if (wxUserInfo != null && wxUserInfo.Tables.Count > 0 && wxUserInfo.Tables[0].Rows.Count > 0)
    {
      Touser = wxUserInfo.Tables[0].Rows[0]["OpenId"].ToString();
    }
  }
  /// <summary>
  /// 消息接收者的openid
  /// </summary>
  [JsonProperty("touser")]
  public string Touser { get; set; }
  /// <summary>
  /// 消息模板ID
  /// </summary>
  [JsonProperty("template_id")]
  public string TemplateId { get; set; }
  /// <summary>
  /// 點擊模板卡片后的跳轉頁面,僅限本小程序内的頁面,支持帶參數(示例index?foo=bar),該字段不填則不跳轉
  /// </summary>
  [JsonProperty("page")]
  public string Page { get; set; }
  /// <summary>
  /// 跳轉小程序類型:developer開發版、trial體驗版、formal正式版,默认为正式版
  /// </summary>
  [JsonProperty("miniprogram_state")]
  public string MiniprogramState { get; set; }
  /// <summary>
  /// 進入小程序查看的語言類型,支持zh_CN(簡體中文)、en_US(英文)、zh_HK(繁體中文)、zh_TW(繁體中文),默認為zh_CN
  /// </summary>
  [JsonProperty("lang")]
  public string Lang { get; set; }
  /// <summary>
  /// 模板内容
  /// </summary>
  [JsonProperty("data")]
  public Dictionary<string, DataValue> Data { get; set; }
}
/// <summary>
/// 模板内容關鍵字
/// </summary>
public class DataValue
{
  /// <summary>
  /// 訂閲消息參數值
  /// </summary>
  [JsonProperty("value")]
  public string Value { get; set; }
} /// <summary>
/// 小程序訂閲消息響應模型
/// </summary>
public class SubscribeMsgResponseModel
{
  /// <summary>
  /// 錯誤代碼
  /// </summary>
  public int Errcode { get; set; }
  /// <summary>
  /// 錯誤信息
  /// </summary>
  public string Errmsg { get; set; }
} /// <summary>
/// 小程序獲取token響應模型
/// </summary>
public class AccessTokenResponseModel
{
  /// <summary>
  /// 小程序訪問token
  /// </summary>
  public string Access_token { get; set; }
  /// <summary>
  /// Token過期時間,單位秒
  /// </summary>
  public int Expires_id { get; set; }
  /// <summary>
  /// Token創建時間
  /// </summary>
  public DateTime Create_time { get; set; }
  /// <summary>
  /// 刷新以後的Token
  /// </summary>
  public string Refresh_token { get; set; }
  /// <summary>
  /// 小程序用戶唯一標識,如果用戶未關注公衆號,訪問公衆號網頁也會產生
  /// </summary>
  public string Openid { get; set; }
  /// <summary>
  /// 用戶授權的作用域,使用逗號分隔
  /// </summary>
  public string Scope { get; set; }
} }

六、实现消息订阅基类,下面的SetTemplateData方法根据自己的情况设置需要推送消息的内容,如果以后有其他订阅消息模板,新增一个类实现SubscribeMessageModel

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using BestSoft.Common.Resources;
using BSFWorkFlow.Common.GeneralUtility;
using WXERP.Models; namespace WXERP.Services.SubscribeMessage
{
/// <summary>
/// 審核訂閲消息
/// </summary>
public class AuditSubscribeMessage : SubscribeMessageModel
{
  private string page;
  private string lang;
  private Dictionary<string, DataValue> data;
  /// <summary>
  /// 設置小程序OpenId
  /// </summary>
  /// <param name="dbTransOrCnn">數據庫事務</param>
  /// <param name="nextAuditStaffId">下一個審核通知用戶工號</param>
  public AuditSubscribeMessage(object dbTransOrCnn, string nextAuditStaffId)
  : base(dbTransOrCnn, nextAuditStaffId)
  {   }
  /// <summary>
  /// 消息模板ID
  /// </summary>
  [JsonProperty("template_id")]
  public new string TemplateId => Common.Configuration["WX:Templates:Audit:TemplateId"];   /// <summary>
  /// 設置小程序訂閲消息跳轉頁面
  /// </summary>
  /// <param name="formId"></param>
  /// <param name="tableId"></param>
  public void SetPageUrl(string formId, string tableId)
  {
    Page = string.Format(Common.Configuration["WX:Templates:Audit:PageUrl"],
    formId, tableId);
  }
  /// <summary>
  /// 點擊模板卡片后的跳轉頁面
  /// </summary>
  [JsonProperty("page")]
  public new string Page
  {
    get
    {
    return page;
    }
    set
    {
      page = value;
      return;
    }
  }
  /// <summary>
  /// 跳轉小程序類型
  /// </summary>
  [JsonProperty("miniprogram_state")]
  public new string MiniprogramState => Common.Configuration["WX:Templates:Audit:MiniprogramState"];
  /// <summary>
  /// 進入小程序查看的語言類型,支持zh_CN(簡體中文)、en_US(英文)、zh_HK(繁體中文)、zh_TW(繁體中文),默認為zh_CN
  /// </summary>
  [JsonProperty("lang")]
  public new string Lang
  {
    get
    {
      lang = Common.Configuration["WX:Templates:Audit:Lang"];
      if (!string.IsNullOrEmpty(MyHttpContext.Current.Request.Headers["bsLanKind"]))
      lang = MyHttpContext.Current.Request.Headers["bsLanKind"];       return lang;
    }
    set
    {
      lang = value;
      return;
    }
  }
  /// <summary>
  /// 設置審核訂閲消息數據
  /// </summary>
  /// <param name="operation">審核動作:通過、否決、作廢、退回</param>
  /// <param name="itemAuditStatus">審核狀態:1代表審核完畢</param>
  /// <param name="currentWorkflowName">審核標題</param>
  public void SetTemplateData(WFAuditOperation operation, WFAuditItemStatus itemAuditStatus, string currentWorkflowName)
  {
    string tip_msg = "";
    switch (operation)
    {
      case WFAuditOperation.AuditPassAndAgree:
        if (itemAuditStatus == WFAuditItemStatus.SuccessfulToFinishAllAudits)
          tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_FinishAuditTip"), "您的單據已審核完成!");
        else
          tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditAgreeTip"), "您有一筆新單據待審核!");
      break;
      case WFAuditOperation.AuditPassButDegree:
        tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditDegreeTip"), "您提交的單據等待異議!");
      break;
      case WFAuditOperation.AuditAbort:
        tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditAbortTip"), "您提交的單據已被作廢!");
      break;
      case WFAuditOperation.AuditBack:
        tip_msg = GeneralFunction.ReplaceNullOrEmptyStr(SourcesWarehouse.GetStringSources("WFEngine_AuditBackTip"), "您提交的單據已被退回修正!");
      break;
    }     string title = Common.Configuration["WX:Templates:Audit:Data:Title"];
    string content = Common.Configuration["WX:Templates:Audit:Data:Content"];
    string date = Common.Configuration["WX:Templates:Audit:Data:Date"];
    Dictionary<string, DataValue> data = new Dictionary<string, DataValue>()
    {
      {title, new DataValue{ Value= currentWorkflowName }},
      {content, new DataValue{ Value= tip_msg }},
      {date, new DataValue{ Value= DateTime.Now.ToShortDateString() }}
    };     Data = data;
  }
  /// <summary>
  /// 審核訂閲消息數據
  /// </summary>
  [JsonProperty("data")]
  public new Dictionary<string, DataValue> Data
  {
    get
    {
      return data;
    }
    set
    {
      data = value;
      return;
    }
  } }
}

七、编写发送订阅消息,消息推送配置签名认证

using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Newtonsoft.Json;
using WXERP.Models; namespace WXERP.Services
{
/// <summary>
/// 系統消息上下文
/// </summary>
public class MessageContext
{
  /// <summary>
  /// 獲取AccessToken的全局鎖
  /// </summary>
  private readonly static object SyncLock = new object();   private static Dictionary<string, AccessTokenResponseModel> tokenCache = new Dictionary<string, AccessTokenResponseModel>();   /// <summary>
  /// 發送訂閲消息
  /// </summary>
  /// <param name="msg">消息内容</param>
  /// <param name="errMsg">可能由於獲取的token錯誤</param>
  /// <returns></returns>
  public static bool SendSubscribeMsg(SubscribeMessageModel msg, out string errMsg)
  {
    errMsg = "";
    try
    {
      string token = GetAccessToken();
      if (token.Length < 20)
      {
        errMsg = "Failed to send subscription message, Access token error!";
        return false;
      }
      string url = string.Format(Common.Configuration["WX:MessageSendUrl"], token);
      string requestJson = JsonConvert.SerializeObject(msg);
      string responseJson = HttpHelper.HttpPost(url, requestJson, "application/json", null);       var msgResponse = JsonConvert.DeserializeObject<SubscribeMsgResponseModel>(responseJson);
      if (msgResponse.Errcode != 0)
      {
        errMsg = string.Format("Failed to send subscription message, {0}", msgResponse.Errmsg);
        return false;
      }
    }
    catch (Exception exp)
    {
      throw new Exception("SendSubscribeMsg: " + exp.Message);
    }
    return true;
  }   /// <summary>
  /// 獲取小程序訪問token
  /// </summary>
  /// <returns></returns>
  private static string GetAccessToken()
  {
    lock (SyncLock)
    {
      string appid = Common.Configuration["WX:AppId"];
      string appsecret = Common.Configuration["WX:AppSecret"];
      string accessTokenUrl = string.Format(Common.Configuration["WX:AccessTokenUrl"], appid, appsecret);       AccessTokenResponseModel result = null;
      if (tokenCache.ContainsKey(appid))
      result = tokenCache[appid];       if (result == null)
      {
        string responseJson = HttpHelper.HttpGet(accessTokenUrl, null);
        result = JsonConvert.DeserializeObject<AccessTokenResponseModel>(responseJson);
        result.Create_time = DateTime.Now;
        tokenCache.Add(appid, result);
      }
      else if (DateTime.Compare(result.Create_time.AddSeconds(result.Expires_id), DateTime.Now) < 1)
      {
        string responseJson = HttpHelper.HttpGet(accessTokenUrl, null);
        result = JsonConvert.DeserializeObject<AccessTokenResponseModel>(responseJson);
        result.Create_time = DateTime.Now;
        tokenCache[appid] = result;
      }
      return result.Access_token;
    }
  }   /// <summary>
  /// 驗證消息來自於微信服務器
  /// </summary>
  /// <param name="signature">微信加密簽名,signature結合了開發者填寫的token、timestamp、nonce</param>
  /// <param name="timestamp">時間戳</param>
  /// <param name="nonce">隨機數</param>
  /// <returns></returns>
  public async Task<bool> CheckSignature(string signature, string timestamp, string nonce)
  {
    string token = Common.Configuration["WX:SignatureToken"];
    string[] tmpArr = { token, timestamp, nonce };
    Array.Sort(tmpArr);
    string tmpStr = string.Join("", tmpArr);
    tmpStr = Common.SHA1(tmpStr);     if (!tmpStr.Equals(signature, StringComparison.OrdinalIgnoreCase))
      return false;     await Task.CompletedTask;
    return true;
  } }
}

八、编写消息推送配置签名认证控制器

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using WXERP.Services; namespace WXERP.Controllers
{
  /// <summary>
  /// 消息控制器
  /// </summary>
  [Route("api/[controller]")]
  [ApiController]
  public class MessageController : ControllerBase
  {
    private readonly MessageContext _context;
    /// <summary>
    /// 初始化消息
    /// </summary>
    public MessageController()
    {
      _context = new MessageContext();
    }   /// <summary>微信消息</summary>
  /// <remarks>驗證消息來自於微信服務器</remarks>
  /// <param name="signature">微信加密簽名,signature結合了開發者填寫的token、timestamp、nonce</param>
  /// <param name="timestamp">時間戳</param>
  /// <param name="nonce">隨機數</param>
  /// <param name="echostr">隨機字符串</param>
  /// <returns></returns>
  [HttpGet("checkSignature")]
  [AllowAnonymous]
  public async void CheckSignature(string signature,string timestamp,string nonce,string echostr)
  {
    bool result = await _context.CheckSignature(signature, timestamp, nonce);
    if (result)
    {
      HttpContext.Response.ContentType = "text/plain; charset=utf-8";
      await HttpContext.Response.WriteAsync(echostr);
    }
    else
    {
      HttpContext.Response.StatusCode = 409;
      HttpContext.Response.ContentType = "text/plain; charset=utf-8";
      await HttpContext.Response.WriteAsync("error");
  }
} }
}

九、调用小程序订阅消息,需要自己实现其他逻辑

//@iFormSaveDAL.GetTran 数据库链接事务,如果发送消息失败,应该回滚提交的表单数据
//@wFControl.NextAuditNotifyStaffIDStr 下一个审核用户的工号
//@auditPageData.FormID 表单编号
//@auditPageData.MainRecordID 表单数据ID
//@operationByCode 一个枚举类型,前端传递的:审核通过、作废、退回等
//@wFControl.ItemAuditStatus 一个枚举类型,如果全部审核完毕为1,否则为0
//@wFControl.CurrentWorkflowName 当前流程的名称,例如:请假单审核
//@SaveAfterInfo 全局字符变量,用于保存结果信息 AuditSubscribeMessage auditMsg = new AuditSubscribeMessage(iFormSaveDAL.GetTran, wFControl.NextAuditNotifyStaffIDStr);
auditMsg.SetPageUrl(auditPageData.FormID, auditPageData.MainRecordID);
auditMsg.SetTemplateData(operationByCode, wFControl.ItemAuditStatus, wFControl.CurrentWorkflowName);
if (!string.IsNullOrEmpty(auditMsg.Touser))
{
  if (!MessageContext.SendSubscribeMsg(auditMsg, out messageStr))
  {
    SaveAfterInfo = messageStr;
    return false;
  }
}

有不懂或需要改正的欢迎留言!

.netcore 3.1 C# 微信小程序发送订阅消息的更多相关文章

  1. 微信小程序发送订阅消息(之前是模板消息)

    之前的模板消息已经废弃,现在改为订阅消息,订阅消息发布前,需要用户确认后才能接收订阅消息. 小程序端 index.wxml <button bindtap="send"> ...

  2. 微信小程序发送模板消息

    微信小程序发送模板消息 标签(空格分隔): php 看小程序文档 [模板消息文档总览]:https://developers.weixin.qq.com/miniprogram/dev/framewo ...

  3. 微信小程序 发送模版消息

    微信小程序开发之发送模板消息 1,小程序wxml页面form表单添加 report-submit="true" <form bindsubmit="sub" ...

  4. 微信小程序 发送模板消息的功能实现

    背景 - 小程序开发的过程中,绝大多数会满足微信支付 - 那么,作为友好交互的体现,自然就会考虑到支付后的消息通知咯 - 所以,我的小程序项目也要求完成这个效果,so.分享一下自己的实现步骤,以方便道 ...

  5. 微信小程序-发送模板消息

    1 添加一个小程序的消息模板,获取到模板id,存储到数据库中,方便以后修改调用 2. https://developers.weixin.qq.com/miniprogram/dev/api-back ...

  6. 微信小程序-发送模板消息(C#)

    步骤一:获取模板ID 有两个方法可以获取模版ID 通过模版消息管理接口获取模版ID 在微信公众平台手动配置获取模版ID 步骤二:页面的 <form/> 组件,属性report-submit ...

  7. Q:微信小程序一次性订阅消息(前台收集)

    说明:官方文档(https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/subscribe-message.ht ...

  8. 微信小程序发送短信验证码完整实例

    微信小程序注册完整实例,发送短信验证码,带60秒倒计时功能,无需服务器端.效果图: 代码: index.wxml <!--index.wxml--> <view class=&quo ...

  9. 微信小程序发送ajax

    微信小程序通过 wx.request发送ajax请求 1. GET wx.request({ url: app.globalData.pubSiteUrl + 'user-information/ge ...

随机推荐

  1. Redis主从复制(读写分离)

    主从复制(读写分离):读在从库读,写在主库写. 主从复制的好处:避免redis单点故障构建读写分离架构,满足读多写少的需求. 主从架构: 操作(启动实例,在一台机器上启动不同的实例,进行伪主从复制): ...

  2. C#串口通讯,复制粘贴就可用,仅仅介绍怎样最快的搭建一个串口通讯,异常拦截等等需要自己加上

    using System; using System.Collections.Generic; using System.IO.Ports; using System.Text; //串口通讯类 pu ...

  3. py_冒泡排序

    import random """ 排序:将一组无序记录序列调整为有序记录序列 列表排序:将无序列表调整为有序列表 输入:列表 输出:有序列表 升序与降序 内置函数sor ...

  4. 获取访问的ip地址

    最近有一个这样的需求:{ 内网没有访问互联网的权限(没网) 内网:访问链接地址,跳转http://www.123.com 外网:访问链接地址,跳转http;//www.456.com } 在网上看到一 ...

  5. e3mall商城的归纳总结7之solr搭建和应用

    敬给读者的话 本文主要应用的技术是solr技术的搭建和应用,本文小编尽量写的更详细一些,让读者在不考虑项目的情况下也能正常完成solr的搭建,说完搭建之后,再说明运行solrj在项目中如何应用solr ...

  6. 通过WordCount解析Spark RDD内部源码机制

    一.Spark WordCount动手实践 我们通过Spark WordCount动手实践,编写单词计数代码:在wordcount.scala的基础上,从数据流动的视角深入分析Spark RDD的数据 ...

  7. Android开发之华为手机无法看log日志解决方法(亲测可用华为荣耀6)

    作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985, 转载请说明出处. 在上家公司上班的时候,公司配了华为荣耀6的测试机,发现在eclipse下 无法查看 ...

  8. Android开发之解决Error:(16) Error: "ssdk_baidutieba_client_inavailable" is not translated in "en" (Englis

    由于添加ShareSDK文件,导致打包突然报错, 错误信息: Error:(16) Error: "baidutieba_client_inavailable" is not tr ...

  9. AndroidStudio与eclipse打包的时候报错。Error:(4) Error: "ssdk_instapager_login_html" is not translated in "en"

    作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 QQ986945193 博客园主页:http://www.cnblogs.com/mcxiaobing ...

  10. Selenium使用cookis登录,并临时将cookis存储在本地【shelve数据库】

    Python中自带了一个shelve库,可以帮助我们存储一些少量的数据. shelve数据库类似redis,是以[键值对]的方式进行数据的存储,有点像"字典"这种数据结构,存储在本 ...