.Net6+Furion+Sqlsugar+SenparcSdk开发微信公众号系列之七:生成带参数的二维码

一、说明

为了满足用户渠道推广分析和用户帐号绑定等场景的需要,公众平台提供了生成带参数二维码的接口。使用该接口可以获得多个带不同场景值的二维码,用户扫描后,公众号可以接收到事件推送。使用接口过程中有任何问题,可以前往微信开放社区 #公众号 专区发帖交流。

目前有2种类型的二维码:

1、临时二维码,是有过期时间的,最长可以设置为在二维码生成后的30天(即2592000秒)后过期,但能够生成较多数量。临时二维码主要用于帐号绑定等不要求二维码永久保存的业务场景 2、永久二维码,是无过期时间的,但数量较少(目前为最多10万个)。永久二维码主要用于适用于帐号绑定、用户来源统计等场景。

用户扫描带场景值二维码时,可能推送以下两种事件:

如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。

如果用户已经关注公众号,在用户扫描后会自动进入会话,微信也会将带场景值扫描事件推送给开发者。

获取带参数的二维码的过程包括两步,首先创建二维码ticket,然后凭借 ticket 到指定 URL 换取二维码。

二、规范化API接口

因为是webapi所以我们接口返回要规范化,furion提供api返回规范化处理:Startup.cs修改AddInject()为AddInjectWithUnifyResult()

这个规范化处理是全局的,但是我们/wx接口是不能规范化处理的,所以我们要在/wx接口上加[NonUnify]特性,取消规范化处理

三、数据库设计

新建一个二维码表

建表语句

-- ----------------------------
-- Table structure for QrCode
-- ----------------------------
DROP TABLE IF EXISTS "QrCode";
CREATE TABLE "QrCode" (
  "Id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
  "ActionName" int NOT NULL,
  "ExpireSeconds" int NOT NULL,
  "SceneId" int NOT NULL,
  "Ticket" varchar(500) NOT NULL,
  "CodeUrl" varchar(500) NOT NULL,
  "ReceiveInfo" text NOT NULL,
  "CreatedTime" datetime,
  "ExpiredTime" datetime
);

创建实体,这里的ReceiveInfo字段我们是用的json存储,sqlsugar完美支持json存储,只需要在实体上加上[SugarColumn(IsJson = true)]

using Senparc.Weixin.MP;
using SqlSugar;
using System;

namespace WeiXinApi.Core
{
    /// <summary>
    /// 二维码表
    ///</summary>
    [SugarTable("QrCode")]
    public class QrCode
    {
        /// <summary>
        /// id 
        ///</summary>
        [SugarColumn(ColumnName = "Id", IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
        /// <summary>
        /// 二维码类型 
        ///</summary>
        [SugarColumn(ColumnName = "ActionName")]
        public QrCode_ActionName ActionName { get; set; }
        /// <summary>
        /// 过期时间 
        ///</summary>
        [SugarColumn(ColumnName = "ExpireSeconds")]
        public int ExpireSeconds { get; set; }
        /// <summary>
        /// SceneId 
        ///</summary>
        [SugarColumn(ColumnName = "SceneId")]
        public int SceneId { get; set; }
        /// <summary>
        /// ticket 
        ///</summary>
        [SugarColumn(ColumnName = "Ticket")]
        public string Ticket { get; set; }
        /// <summary>
        /// 二维码地址 
        ///</summary>
        [SugarColumn(ColumnName = "CodeUrl")]
        public string CodeUrl { get; set; }

        /// <summary>
        /// 创建时间
        /// </summary>

        [SugarColumn(ColumnName = "CreatedTime")]
        public DateTime CreatedTime { get; set; }

        /// <summary>
        /// 过期时间
        /// </summary>
        [SugarColumn(ColumnName = "ExpiredTime")]
        public DateTime? ExpiredTime { get; set; }

        /// <summary>
        /// 回复设置 
        ///</summary>
        [SugarColumn(ColumnName = "ReceiveInfo", IsJson = true)]
        public ReceiveInfo ReceiveInfo { get; set; }


        /// <summary>
        /// 是否过期
        /// </summary>
        [SugarColumn(IsIgnore = true)]
        public bool IsExpired { get; set; } = false;

    }

    public class ReceiveInfo
    {
        /// <summary>
        /// 回复类型:文字,图片等 
        ///</summary>
        public ReceiveType ReceiveType { get; set; }

        /// <summary>
        /// 回复内容 
        ///</summary>
        public string ReceiveString { get; set; }
    }
}

四、接口设计

新建如下结构

QRInput

namespace WeiXinApi.Application.Services
{
    public class QRInput
    {
        /// <summary>
        /// 二维码类型
        /// </summary>
        public QrCode_ActionName ActionName { get; set; }

        /// <summary>
        /// 过期时间
        /// </summary>
        public int ExpireSeconds { get; set; }

        /// <summary>
        /// 回复设置
        /// </summary>
        [Required(ErrorMessage = "回复设置必填")]
        public ReceiveInfo? ReceiveInfo { get; set; }
    }
}

接口

using Furion.RemoteRequest;
using Mapster;

namespace WeiXinApi.Application.Services
{
    public class QRService : BaseService
    {
        /// <summary>
        /// 生成二维码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("qr/add")]
        public async Task<dynamic> Add(QRInput input)
        {
            var qrCode = input.Adapt<QrCode>();

            var ticks = SystemTime.Now.Ticks.ToString();
            var sceneId = int.Parse(ticks.Substring(ticks.Length - 7, 7));
            var qrResult = await QrCodeApi.CreateAsync(AppId, input.ExpireSeconds, sceneId, input.ActionName);
            var qrCodeUrl = QrCodeApi.GetShowQrCodeUrl(qrResult.ticket);
            qrCode.Ticket = qrResult.ticket;
            qrCode.CodeUrl = qrCodeUrl;
            qrCode.SceneId = sceneId;
            qrCode.CreatedTime = DateTime.Now;
            if (input.ActionName == QrCode_ActionName.QR_SCENE)
            {
                qrCode.ExpiredTime = qrCode.CreatedTime.AddSeconds(input.ExpireSeconds);
            }
            await DbContext.Db.Insertable(qrCode).ExecuteCommandAsync();//插入数据库
            return qrCodeUrl;
        }

        /// <summary>
        /// 二维码列表
        /// </summary>
        /// <returns></returns>
        [HttpGet("qr/page")]
        public async Task<dynamic> Page(int pageNumber = 1, int pageSize = 20)
        {
            var result = await DbContext.Db.Queryable<QrCode>()
                .Mapper(it =>
                {
                    if (it.ActionName == QrCode_ActionName.QR_SCENE)//判断是否过期
                    {
                        it.IsExpired = it.ExpiredTime < DateTime.Now;
                    }

                })
                .ToPageListAsync(pageNumber, pageSize);
            return result;
        }
    }
}

 测试添加接口,返回的url可以正常显示二维码

获取二维码测试,成功显示刚才添加的二维码信息

五、本章Gitee链接

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章