准备工作:
- 一个可以开通卡券功能的服务公众号
- 一个小程序账号
注意两者是独立的,分别有着不同的appid和appsercet
开发框架:jfinal-weixin
需求:
- 创建会议门票卡券
- 每人限领一张
- 不可转赠给好友
- 自己定义二维码内容
第一步:创建卡券
Map base_info = new HashMap<>();
//卡券的商户logo,建议像素为300*300
base_info.put("logo_url", "");//logo
base_info.put("brand_name", ""); //商户名字,字数上限为12个汉字
base_info.put("code_type", "CODE_TYPE_QRCODE");//Code展示类型 "CODE_TYPE_TEXT",文本; "CODE_TYPE_BARCODE",一维码 ; "CODE_TYPE_QRCODE",二维码; "CODE_TYPE_ONLY_QRCODE",二维码无code显示; "CODE_TYPE_ONLY_BARCODE",一维码无code显示;
base_info.put("title", "");//卡券名,字数上限为9个汉字。(建议涵盖卡券属性、服务及金额)
base_info.put("color", "Color100");//券颜色。按色彩规范标注填写Color010-Color100。
base_info.put("notice", "使用时向检票员出示此券");//卡券使用提醒,字数上限为16个汉字
base_info.put("service_phone", "");//客服电话
base_info.put("description", "请务必准时入场");//卡券使用说明,字数上限为1024个汉字
Map date_info = new HashMap<>();
date_info.put("type", 1);//使用时间的类型,仅支持填写1或2。1为固定日期区间,2为固定时长(自领取后按天算)。
date_info.put("begin_timestamp", "时间戳(秒级)");// type为1时专用,表示起用时间。从1970年1月1日00:00:00至起用时间的秒数,最终需转换为字符串形态传入。(东八区时间(UTC+8),单位为秒)
date_info.put("end_timestamp", "时间戳(秒级)");//type为1时专用,表示结束时间,建议设置为截止日期的23:59:59过期。(东八区时间 (UTC+8) ,单位为秒)
base_info.put("date_info", date_info);//使用日期,有效期的信息
Map sku = new HashMap<>();
sku.put("quantity", "100000000");//卡券库存的数量,不支持填写0,上限为100000000。
base_info.put("sku", sku);
base_info.put("get_limit", 1);//每人可领券的数量限制
base_info.put("use_custom_code", true);//是否自定义Code码。填写true或false,默认为false。通常自有优惠码系统的开发者选择自定义Code码,在卡券投放时带入
base_info.put("bind_openid", false);//是否指定用户领取,填写true或false。默认为false。
base_info.put("can_share", false);//卡券领取页面是否可分享
base_info.put("can_give_friend", false);//卡券是否可转赠。
meeting_ticket.put("base_info", base_info);
card.put("meeting_ticket", meeting_ticket);
Map data = new HashMap<>();
data.put("card", card);
ApiResult apiResult = CardApi.create(JSON.toJSONString(data));
自己定义二维码内容的好处
- 小程序和公众号是两套独立的appid和appsercet,因此在小程序获取到用户的openid和查询用户领取卡券后返回的openid是不一致的,所以如果自己定义二维码,就可以事先知道并决定二维码的内容,并且可以将其作为桥梁,在用户领取卡券后做领取事件回调。
- 对应的参数是("use_custom_code", true)
生成卡券后,即可获得cardId,后面用户领取时会用到
第二步:小程序中添加卡券
官方文档地址:
https://developers.weixin.qq.com/miniprogram/dev/api/card.html#wxaddcardobject
单个卡券添加需要提供的参数:
所需参数
其中cardExt需要以下参数:
cardExt
比较麻烦的一点就是签名的生成,在官方文档中如此描述:
卡券签名和JSSDK的签名完全独立,两者的算法和意义完全不同,请不要混淆。JSSDK的签名是使用所有JS接口都需要走的一层鉴权,用以标识调用者的身份,和卡券本身并无关系。其次,卡券的签名考虑到协议的扩展性和简单的防数据擅改,设计了一套独立的签名协议。另外由于历史原因,卡券的JS接口先于JSSDK出现,当时的JSAPI并没有鉴权体系,所以在卡券的签名里也加上了appsecret/api_ticket这些身份信息,希望开发者理解。
- 首先获取卡券 api_ticket
注意是:JsApiType.wx_card
JsTicket jsApiTicket = JsTicketApi.getTicket(JsTicketApi.JsApiType.wx_card);
String api_ticket = jsApiTicket.getTicket();
- 然后是timestamp和nonce_str
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
private static String create_nonce_str() {
return UUID.randomUUID().toString();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
- 卡券id即cardId在生成卡券成功时有返回
- 然后根据参数的顺序,按照 key 值 ASCII 码升序排序
ArrayList list = new ArrayList();
list.add(timestamp);
list.add(CardCode);//自己定义,可以使用12位随机数
list.add(nonce_str);
list.add(api_ticket);
list.add(cardId);
Collections.sort(list);
- 最后进行sha1加密,得到signature
String signature = HashKit.sha1(str);
注意的事情
- 卡券的签名算法与JSSDK签名算法不一致,卡券的签名是按照值来排序的,而JSSDK签名是按照键值对固定排序的,这个地方需要着重注意一下。
第三步:卡券事件回调
卡券事件分别是领取事件,核销事件,删除事件...
这里只描述领取事件和核销事件
首先要在公众号中设置开发者模式,这样才会接收到微信发过来的信息
如果不知道如何设置开发者模式,可以参考这篇文章:
https://blog.csdn.net/zyw_java/article/details/61415205
- 领取事件
因为CardCode在派发时已经知道了,可以事先保存到数据库,用户领取后,根据下面的userCardCode 从而得知是哪个用户领取的,从而做自己想要的处理
/**
* 卡券领取事件推送
*
* @param msg 卡券领取事件推送
*/
@Override
protected void processInUserGetCardEvent(InUserGetCardEvent msg) {
String userCardCode = msg.getUserCardCode();//code序列号
//To-Do
renderNull();
}
- 核销事件
/**
* 卡券核销事件推送
*
* @param msg 卡券核销事件推送
*/
@Override
protected void processInUserConsumeCardEvent(InUserConsumeCardEvent msg) {
String userCardCode = msg.getUserCardCode();//code序列号
//To-Do
renderNull();
}
第四步:在小程序中获取卡券列表
官方文档:
https://developers.weixin.qq.com/miniprogram/dev/api/card.html#wxopencardobject
简单来说就需要两样东西,一个是cardId,一个是cardCode
- cardId就是需要打开的卡券 Id
- cardCode就是自己定义的二维码内容