系列目录

思维导图

下面我们来看一个思维导图,这样就可以更快了解所需要的功能:

上一节我们利用了一个简单的代码例子,完成了与微信公众号的对话(给公众号发一条信息,并得到回复)

这一节将讲解公众号如何设置,虽然公众号管理只是一张表,但是设计起来还是有一些技巧

1.一个企业可能底下有多个业务公众号在同一个系统中需要处理(用户发起的请求,是对应我们哪个公众号)

2.多个公众号下,后台如何取得操作比较方便(设置当前公众号为默认操作号)

3.可以手动刷新Access_Token,因为我们随时要保持Access_Token可用,这是调用微信接口的主要令牌(我们后面将讲解定时更新,而非手动)

知识点

1.表设计

2.设置为默认公众号

3.生成指定格式的URL资源服务器

4.更新Access_Token

表设计

表的设计没有太多的成分,我们根据公众号的信息,自己建立对应的字段,下面是我已经已建立好的数据表

CREATE TABLE [dbo].[WC_OfficalAccounts](
[Id] [varchar](50) NOT NULL, --主键
[OfficalId] [varchar](200) NULL, --公众号的唯一ID
[OfficalName] [varchar](200) NOT NULL, --公众号名称
[OfficalCode] [varchar](200) NOT NULL, --公众号帐号
[OfficalPhoto] [varchar](1000) NULL, --头像
[OfficalKey] [varchar](500) NULL, --EncodingAESKey
[ApiUrl] [varchar](1000) NULL, --我们的资源服务器
[Token] [varchar](200) NULL, --Token
[AppId] [varchar](200) NULL, --AppId
[AppSecret] [varchar](200) NULL, --Appsecret
[AccessToken] [varchar](200) NULL, --访问Token
[Remark] [varchar](2000) NULL, --说明
[Enable] [bit] NOT NULL, --是否启用
[IsDefault] [bit] NOT NULL, --是否为当前默认操作号
[Category] [int] NOT NULL, --类别(媒体号,企业号,个人号,开发测试号)
[CreateTime] [datetime] NOT NULL, --创建时间
[CreateBy] [varchar](50) NOT NULL, --创建人
[ModifyTime] [datetime] NOT NULL, --修改时间
[ModifyBy] [varchar](50) NULL, --修改人
CONSTRAINT [PK_WC_OfficalAcconts] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

每个字段我都有注释,但是可能还不够明白,我们来看网站对应的数据,这样更加清楚一点

这5个字段是必要的,其他其实都是非必要的。我写了那么多,只是让后台管理能够得知当前操作号的信息情况,所以到时创建的时候,这个是对应的填写字段

程序设计

操作EF的增删该查,我在这里就不做代码演示了,已经在前面的相同功能演示过很多遍(下载尾部代码或者自己动手做起来)

我们来看主要的功能代码。

设置公众号为当前的操作号

这里我以字段IsDefault来标识,哪个公众号为系统当前的操作公众号

第一、设置所有公众号的IsDefault为Flase

第二、设置指定ID的公众号的IsDefault为True

update [dbo].[WC_OfficalAccounts] set IsDefault=0
update [dbo].[WC_OfficalAccounts] set IsDefault=1 where id='XXXXXXX'
 public bool SetDefault(string id)
{
//更新所有为不默认0
ExecuteSqlCommand(@"update [dbo].[WC_OfficalAccounts] set IsDefault=0");
//设置当前为默认1
return ExecuteSqlCommand(@"update [dbo].[WC_OfficalAccounts] set IsDefault=1 where id='"+id+"'")>;
}

我们之前系统并未出现,这种直接执行Sql语句的,所以我写了ExecuteSqlCommand这个方法(还有其他几个,可能以后会用到),扩展在仓储中BaseRepository

  /// <summary>
/// 执行一条SQL语句
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public int ExecuteSqlCommand(string sql)
{
return Context.Database.ExecuteSqlCommand(sql);
}
/// <summary>
/// 异步执行一条SQL语句
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public Task<int> ExecuteSqlCommandAsync(string sql)
{
return Context.Database.ExecuteSqlCommandAsync(sql);
} public DbRawSqlQuery<T> SqlQuery(string sql)
{
return db.Database.SqlQuery<T>(sql);
}
/// <summary>
/// 查询一条语句返回结果集
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public DbRawSqlQuery<T> SqlQuery(string sql,params object[] paras)
{
return db.Database.SqlQuery<T>(sql,paras);
}

这里肯定有人会问,你那个可能会被注入,没错,实际应该用参数的方式,但是我在过滤器处理了SQL的注入。

那么在过滤器如果处理注入?这是扩展出另一个问题了,如果感兴趣,展开下面代码(莫非是对传入的参数进行格式处理)

 var actionParameters = filterContext.ActionDescriptor.GetParameters();
foreach (var p in actionParameters)
{
if (p.ParameterType == typeof(string))
{
if (filterContext.ActionParameters[p.ParameterName] != null)
{
filterContext.ActionParameters[p.ParameterName] = ResultHelper.Formatstr(filterContext.ActionParameters[p.ParameterName].ToString());
}
}
}

OnActionExecuting

 public static string Formatstr(string html)
{
System.Text.RegularExpressions.Regex regex1 = new System.Text.RegularExpressions.Regex(@"<script[\s\S]+</script *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex2 = new System.Text.RegularExpressions.Regex(@" href *= *[\s\S]*script *:", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex3 = new System.Text.RegularExpressions.Regex(@" on[\s\S]*=", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex4 = new System.Text.RegularExpressions.Regex(@"<iframe[\s\S]+</iframe *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex5 = new System.Text.RegularExpressions.Regex(@"<frameset[\s\S]+</frameset *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex10 = new System.Text.RegularExpressions.Regex(@"select", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex11 = new System.Text.RegularExpressions.Regex(@"update", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex regex12 = new System.Text.RegularExpressions.Regex(@"delete", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
html = regex1.Replace(html, ""); //过滤<script></script>标记
html = regex2.Replace(html, ""); //过滤href=javascript: (<A>) 属性
html = regex3.Replace(html, " _disibledevent="); //过滤其它控件的on...事件
html = regex4.Replace(html, ""); //过滤iframe
html = regex10.Replace(html, "s_elect");
html = regex11.Replace(html, "u_pudate");
html = regex12.Replace(html, "d_elete");
html = html.Replace("'", "’");
html = html.Replace("&nbsp;", " ");
return html;
}

Formatstr

获得当前公众号

业务层

 public WC_OfficalAccountsModel GetCurrentAccount()
{
WC_OfficalAccounts entity = m_Rep.GetCurrentAccount();
if (entity == null)
{
return new WC_OfficalAccountsModel();
}
WC_OfficalAccountsModel model = new WC_OfficalAccountsModel();
model.Id = entity.Id;
model.OfficalName = entity.OfficalName;
model.OfficalCode = entity.OfficalCode;
model.OfficalPhoto = entity.OfficalPhoto;
model.ApiUrl = entity.ApiUrl;
model.Token = entity.Token;
model.AppId = entity.AppId;
model.AppSecret = entity.AppSecret;
model.AccessToken = entity.AccessToken;
model.Remark = entity.Remark;
model.Enable = entity.Enable;
model.IsDefault = entity.IsDefault;
model.Category = entity.Category;
model.CreateTime = entity.CreateTime;
model.CreateBy = entity.CreateBy;
model.ModifyTime = entity.ModifyTime;
model.ModifyBy = entity.ModifyBy;
return model;
}

数据访问层

 public WC_OfficalAccounts GetCurrentAccount()
{
return Context.WC_OfficalAccounts.Where(p=>p.IsDefault).FirstOrDefault();
}

其他代码都由生成器生成,没有争议,也很简单

生成资源服务器的链接

上一节我们用的是一个地址

http://ymnets.imwork.net/WC/WcChat

这次我们这个地址要稍微改变一下,让系统知道请求者发送的请求是来自哪个公众号:

http://ymnets.imwork.net/WC/WcChat?Id=XXXXXXXX     (XXXXXXX是我们系统自己定义的GUID)

这样请求的时候就知道是请求哪个ID

所以我们的Post方法必须加上判断代码,并利用这个Id去获取当前公众号的信息

 [HttpPost]
[ActionName("Index")]
public Task<ActionResult> Post(PostModel postModel)
{
return Task.Factory.StartNew<ActionResult>(() =>
{
WC_OfficalAccountsModel model = account_BLL.GetCurrentAccount(); //没有参数
if (string.IsNullOrEmpty(Request["id"]))
{
return new WeixinResult("非法路径请求!");
}
if (!CheckSignature.Check(postModel.Signature, postModel.Timestamp, postModel.Nonce, model.Token))
{
return new WeixinResult("参数错误!");
}
postModel.Token = Token;
postModel.EncodingAESKey = EncodingAESKey; //根据自己后台的设置保持一致
postModel.AppId = model.AppId; //根据自己后台的设置保持一致 var messageHandler = new CustomMessageHandler(Request.InputStream, postModel, Request["id"], ); messageHandler.Execute(); //执行微信处理过程 return new FixWeixinBugWeixinResult(messageHandler); }).ContinueWith<ActionResult>(task => task.Result);
}

1.判断URL是否是正确的

2.根据获得ID到数据库或者(Redis,缓存)等获得公众号信息

刷新Access_Token

由于我们的访问Token默认是2个小时过时,而且我们不能时刻去微信服务器获取

1.获取的次数是有限制。所以我们需要保存这个Token地址,在下次过期之前更新来永远保持Access_Token的有效

2.这里我保存在表里面,在获取当前操作号的时候顺便可以获得这个Access_Token

他的样子大约是这样的:tZH82Jd6JQL6dPEU1hwhM9_jl0SrLRZV3j6-DV-EOQFUl3r37OXQNq-rpmjXEV2sVj1EQdxLotLCDMz_DdVAhZHQG6vgckOW8k90_9i24jP7giAOJM669zbiqc3HYW6wQDGeAJAYLO

如何获得Token:这里我们使用Senparc.WeiXin SDK的方法,

Senparc.Weixin.MP.CommonAPIs.CommonApi.GetToken(model.AppId, model.AppSecret).access_token;

一句话,获得当前操作号之后,利用AppId和Appsecret,微信服务器将给你一个Token。所以这个两个东西是要打码的,要不很麻烦。

虽然他帮我们封装了,但是不用他的方法,我们自己也可以直接调用微信的接口方法

            var url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type={0}&appid={1}&secret={2}",
grant_type.AsUrlData(), appid.AsUrlData(), secret.AsUrlData()); AccessTokenResult result = Get.GetJson<AccessTokenResult>(url);
return result;

这个接口,只有几个参数,具体参数可以查看帮助文档 传送门 成功返回:{"access_token":"ACCESS_TOKEN","expires_in":7200}

所以我这里是一个更新当前所有公众号的过程

 public JsonResult GetToken()
{
List<WC_OfficalAccountsModel> list = m_BLL.GetList(ref setNoPagerAscById, "");
foreach (var model in list)
{
if (!string.IsNullOrEmpty(model.AppId) && !string.IsNullOrEmpty(model.AppSecret))
{
model.AccessToken = Senparc.Weixin.MP.CommonAPIs.CommonApi.GetToken(model.AppId, model.AppSecret).access_token;
model.ModifyTime = ResultHelper.NowTime;
m_BLL.Edit(ref errors, model);
}
}
return Json(JsonHandler.CreateMessage(, "成批更新成功"));
}

总结

谢谢大家

ASP.NET MVC5+EF6+EasyUI 后台管理系统(71)-微信公众平台开发-公众号管理的更多相关文章

  1. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库  您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB  升级后界面效果如下: 任务调度系统界面 http: ...

  2. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(转)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库 您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB 升级后界面效果如下: 日程管理   http://ww ...

  3. ASP.NET MVC5+EF6+EasyUI 后台管理系统(63)-Excel导入和导出-自定义表模导入

    系列目录 前言 上一节使用了LinqToExcel和CloseXML对Excel表进行导入和导出的简单操作,大家可以跳转到上一节查看: ASP.NET MVC5+EF6+EasyUI 后台管理系统(6 ...

  4. ASP.NET MVC5+EF6+EasyUI 后台管理系统-WebApi的用法与调试

    1:ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-WebApi与Unity注入 使用Unity是为了使用我们后台的BLL和DAL层 2:ASP.NET MVC5+EF6+Easy ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(51)-系统升级

    系统很久没有更新内容了,期待已久的更新在今天发布了,最近花了2个月的时间每天一点点,从原有系统 MVC4+EF5+UNITY2.X+Quartz 2.0+easyui 1.3.4无缝接入 MVC5+E ...

  6. ASP.NET MVC5+EF6+EasyUI 后台管理系统(58)-DAL层重构

    系列目录 前言:这是对本文系统一次重要的革新,很久就想要重构数据访问层了,数据访问层重复代码太多.主要集中增删该查每个模块都有,所以本次是为封装相同接口方法 如果你想了解怎么重构普通的接口DAL层请查 ...

  7. ASP.NET MVC5+EF6+EasyUI 后台管理系统(34)-文章发布系统①-简要分析

    系列目录 最新比较闲,为了学习下Android的开发构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(1)-前言与,虽然有点没有目的的学习,但还是了解了Andro ...

  8. ASP.NET MVC5+EF6+EasyUI 后台管理系统(54)-工作流设计-所有流程监控

    系列目录 先补充一个平面化登陆页面代码,自己更换喜欢的颜色背景 @using Apps.Common; @{ Layout = null; } <!DOCTYPE html> <ht ...

  9. ASP.NET MVC5+EF6+EasyUI 后台管理系统(56)-插件---单文件上传与easyui使用fancybox

    系列目录 https://yunpan.cn/cZVeSJ33XSHKZ  访问密码 0fc2 今天整合lightbox插件Fancybox1.3.4,发现1.3.4版本太老了.而目前easyui 1 ...

随机推荐

  1. ExtJS 4.2 评分组件

    上一文章是扩展ExtJS自带的Date组件.在这里将创建一个评分组件. 目录 1. 介绍 2. 示例 3. 资源下载 1. 介绍 代码参考的是 Sencha Touch 2上的一个RatingStar ...

  2. javascript动画系列第三篇——碰撞检测

    前面的话 前面分别介绍了拖拽模拟和磁性吸附,当可视区域内存在多个可拖拽元素,就出现碰撞检测的问题,这也是javascript动画的一个经典问题.本篇将详细介绍碰撞检测 原理介绍 碰撞检测的方法有很多, ...

  3. StringMVC 中如何做数据校验

    步骤一:引入四个jar包 步骤二:注册类型转换器 <context:component-scan base-package="cn.happy.controller"> ...

  4. HTML5 Boilerplate - 让页面有个好的开始

    最近看到了HTML5 Boilerplate模版,系统的学习与了解了一下.在各种CSS库.JS框架层出不穷的今天,能看到这么好的HTML模版,感觉甚爽.写篇博客,推荐给大家使用.   一:HTML5 ...

  5. C语言 · Torry的困惑(基本型)

    问题描述 Torry从小喜爱数学.一天,老师告诉他,像2.3.5.7--这样的数叫做质数.Torry突然想到一个问题,前10.100.1000.10000--个质数的乘积是多少呢?他把这个问题告诉老师 ...

  6. Java中用得比较顺手的事件监听

    第一次听说监听是三年前,做一个webGIS的项目,当时对Listener的印象就是个"监视器",监视着界面的一举一动,一有动静就触发对应的响应. 一.概述 通过对界面的某一或某些操 ...

  7. H3 BPM产品安装手册(.Net版本)

    1         安装说明 1.1    服务器安装必备软件 在使用该工作流软件之前,有以下一些软件是必须安装: l  IIS7.0以上版本(必须): l  .Net Framework 4.5(必 ...

  8. GitHub管理代码-随笔

    公司一直用的SVN进行项目管理,平时便自己折腾了下Git,这里做下GitHub的最简单的记录... 在git上创建仓库等就免谈了,网上也有好多教程,直接从创建之后记录: 在github的readme文 ...

  9. ERROR 1300 (HY000): Invalid utf8 character string: ''

    在load csv 进mysql的时候,报这个错,苦恼了很长时间,网上搜索不到答案. mysql>    load data infile '/home/hdh/8_sr/8_45.csv'   ...

  10. Android快乐贪吃蛇游戏实战项目开发教程-04虚拟方向键(三)三角形按钮效果

    该系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html 一.知识点讲解 当我们点击系统自带的按钮时,按钮的外观会发生变化.上篇博文中我们 ...