最近做了个领取微信卡券的小程序,看了很多文档资料以及花了很多时间才算搞定的,不过也算是好事多磨,这边记录分享一下,也算给一点提升。
一、开发前准备
1:申请微信公众号和微信小程序,这是两个不同的东西,都需要单独申请、不同的帐号;
2:微信公众号需要开通微信卡券的功能;
3:在微信公众号里面去绑定小程序;
4:申请微信开放平台,并将微信公众号和微信小程序绑定到该开放平台。(注:绑定到开发平台下的作用只是为了获取unionid,因为同一用户在公众号和小程序下获得的openid是不一样的,如果公众号和小程序都需要领取卡券,则最好通过unionid来跟踪用户;如果你只是开发微信小程序的领取卡券,则完全可以忽略第4点,博主本人也没有去绑定到微信开放平台,感觉步骤好多,特别麻烦!)
二、开始开发
1:获取微信卡券
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1451025272
这边可以直接通过微信公众号提供的接口获取或者创建微信的卡券,此处不过多介绍,只是提一下这边要获取的access_token,网址如下https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183,代码直接如下:
privatestaticStringgrantType="client_credential";publicstaticStringappId="";//微信公众号appidpublicstaticStringsecret="";//微信公众号密钥publicstaticAccessTokentoken=null;//微信公众号的accessToken对象,由于请求次数有限制,这里使用全局静态变量保存起来publicstaticAccessTokengetToken()throwsWeixinException,JsonParseException,JsonMappingException,IOException{if(token==null||token.getExpires_in()System.currentTimeMillis()){//拼接参数Stringparam="?grant_type="+grantType+"&appid="+appId+"&secret="+secret;//创建请求对象HttpsClienthttp=newHttpsClient();//调用获取access_token接口Responseres=http.get("https://api.weixin.qq.com/cgi-bin/token"+param);System.out.println(res.asString());ObjectMappermapper=newObjectMapper();token=mapper.readValue(res.asString(),AccessToken.class);}returntoken;}
其中需要jackson和weixin4j的jar包,比较普遍,请自行下载;而AccessToken对象也比较简单,就errcode、errmsg、access_token、expires_in这四个参数,比较简单,在文章结尾贴代码
2:升级微信卡券
其实这个步骤也可以省略,升级微信卡券的目的是可以直接从微信卡券跳转到对应的小程序,博主就偷懒了,直接跳过了这个步骤;
不过升级卡券也比较简单,就是调用调用微信公众号的更改微信卡券接口(URL:https://api.weixin.qq.com/card/update?access_token=TOKEN),添加几个字段,可以参考微信官方文档3.1,链接如下:https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&key=1490190158&version=1&lang=zh_CN&platform=2
3:领取卡券
3.1:先获取openId
小程序端代码,通过调用wx.login获取code,再调用https://api.weixin.qq.com/sns/jscode2session接口获取openid,博主看到很多例子是直接从小程序端调用这个接口,但我事实中发现是行不通的,因为这个域名无法添加到小程序的request合法域名中,微信给的说明是不要在前端调用这个接口,需要通过后台,那没办法喽
wx.login({success:function(res){varservice_url='https://???/???/weixin/api/login?code='+res.code;//需要将服务器域名添加到小程序的request合法域名中,而且必须是https开头wx.request({url:l,data:{},method:'GET',success:function(res){console.log(res);if(res.data!=null&&res.data!=undefined&&res.data!=''){wx.setStorageSync("openid",res.data.openid);//将获取的openid存到缓存中}}});}});
后端java代码
/小程序后台登录,向微信平台发送获取access_token请求,并返回openId@paramcode@return用户凭证@throwsWeixinException@throwsIOException@throwsJsonMappingException@throwsJsonParseException/@RequestMapping("login")@ResponseBodypublicMapString,Objectlogin(Stringcode,HttpServletRequestrequest)throwsWeixinException,JsonParseException,JsonMappingException,IOException{if(code==null||code.equals("")){thrownewWeixinException("invalidnull,codeisnull.");}MapString,Objectret=newHashMapString,Object();//拼接参数Stringparam="?grant_type="+grant_type+"&appid="+appid+"&secret="+secret+"&js_code="+code;System.out.println("https://api.weixin.qq.com/sns/jscode2session"+param);//创建请求对象HttpsClienthttp=newHttpsClient();//调用获取access_token接口Responseres=http.get("https://api.weixin.qq.com/sns/jscode2session"+param);//根据请求结果判定,是否验证成功JSONObjectjsonObj=res.asJSONObject();if(jsonObj!=null){Objecterrcode=jsonObj.get("errcode");if(errcode!=null){//返回异常信息thrownewWeixinException(getCause(Integer.parseInt(errcode.toString())));}ObjectMappermapper=newObjectMapper();OAuthJsTokenoauthJsToken=mapper.readValue(jsonObj.toJSONString(),OAuthJsToken.class);ret.put("openid",oauthJsToken.getOpenid());}returnret;}
其中OAuthJsToken对象的字段为:openid、expires_in、session_key(会话密钥),在文章结尾贴代码;
3.2:生成领取卡券的签名,并调用wx.addCard方法领取卡券
这边写贴java后端代码
publicstaticApiTicketticket=null;//使用全局静态变量存储ApiTicket对象,当然如果使用缓存框架保存当然更好,这边只是做一个简单示例/@Description:获取领取卡券获取签名等参数@paramcardId:需要领取的卡券的cardId@return@throwsWeixinException@throwsJsonParseException@throwsJsonMappingException@throwsIOException/@RequestMapping("getCardSign")@ResponseBodypublicMapString,StringgetCardSign(StringcardId)throwsWeixinException,JsonParseException,JsonMappingException,IOException{MapString,Stringret=newHashMapString,String();//先要获取api_ticket,由于请求api_ticket的接口访问有次数限制,所以最好将获得到的api_ticket保存到缓存中,这边做法比较简单,直接使用的静态变量if(ticket==null||ticket.getExpires_in()System.currentTimeMillis()){//创建请求对象HttpsClienthttp=newHttpsClient();ObjectMappermapper=newObjectMapper();AccessTokentoken=OpenApi.getToken();//这里获取的token就是最上方代码保存的微信公众号全局静态变量token//通过access_token调用获取api_ticket接口Responseres=http.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+token.getAccess_token()+"&type=wx_card");System.out.println(res.asString());ticket=mapper.readValue(res.asString(),ApiTicket.class);}ret=sign(ticket.getTicket(),cardId);//生成领取卡券需要的签名,并返回相关的参数for(Map.Entryentry:ret.entrySet()){System.out.println(entry.getKey()+","+entry.getValue());}returnret;}/@Description:生成卡券需要的签名并返回参数@paramapi_ticket:@paramcardId:需要领取的卡券的cardId@return/publicstaticMapString,Stringsign(Stringapi_ticket,StringcardId){MapString,Stringret=newHashMapString,String();Stringnonce_str=create_nonce_str();Stringtimestamp=create_timestamp();Stringsignature="";Stringparam[]=newString[4];param[0]=nonce_str;param[1]=timestamp;param[2]=api_ticket;param[3]=cardId;Arrays.sort(param);//对参数的value值进行字符串的字典序排序StringBuildersb=newStringBuilder();for(Stringb:param){sb.append(b);}System.out.println(sb);//对上面拼接的字符串进行sha1加密,得到signaturetry{MessageDigestcrypt=MessageDigest.getInstance("SHA-1");crypt.reset();crypt.update(sb.toString().getBytes("UTF-8"));signature=byteToHex(crypt.digest());}catch(NoSuchAlgorithmExceptione){e.printStackTrace();}catch(UnsupportedEncodingExceptione){e.printStackTrace();}//返回领取卡券需要的参数,其中nonceStr和timestamp必须和签名中的保持一致ret.put("card_id",cardId);ret.put("api_ticket",api_ticket);ret.put("nonceStr",nonce_str);ret.put("timestamp",timestamp);ret.put("signature",signature);returnret;}
其中ApiTicket对象的属性有:errcode、errmsg、ticket、expires_in,在文章结尾贴出该代码再贴小程序端代码
varthat=this;varservice_url='https://???/???/weixin/api/getCardSign?cardId='+cardId;//需要将服务器域名添加到小程序的request合法域名中,而且必须是https开头wx.request({url:service_url,data:{},method:'GET',success:function(res){console.log(res);wx.addCard({cardList:[{cardId:that.data.cardId,cardExt:'{"code":"","openid":"","timestamp":'+res.data.timestamp+',"nonce_str":"'+res.data.nonceStr+'","signature":"'+res.data.signature+'"}'}],//这里需要注意的是cardExt参数的value值是String类型,不要使用对象发送;另外openid如果在创建优惠券的时候没有指定,则这边为空,千万不要填写当前用户的openidsuccess:function(result){console.log(res);wx.showToast({title:'领取成功',icon:'success',duration:2000});},fail:function(res){console.log('领取失败');console.log(res);}})}});
ok,如果领取成功,可以直接到微信卡包里面查看。下面贴出AccessToken、ApiTicket、OAuthJsToken的java模型代码
publicclassBaseResponse{privateinterrcode;privateStringerrmsg;publicintgetErrcode(){returnerrcode;}publicvoidsetErrcode(interrcode){this.errcode=errcode;}publicStringgetErrmsg(){returnerrmsg;}publicvoidsetErrmsg(Stringerrmsg){this.errmsg=errmsg;}}publicclassAccessTokenextendsBaseResponse{privateStringaccess_token;privatelongexpires_in;publicStringgetAccess_token(){returnaccess_token;}publicvoidsetAccess_token(Stringaccess_token){this.access_token=access_token;}publiclonggetExpires_in(){returnexpires_in;}publicvoidsetExpires_in(longexpires_in){this.expires_in=System.currentTimeMillis()+(expires_in-100)1000;//原expires_in是有效时长,比如:7200,现改为过期的时间戳}}publicclassApiTicketextendsBaseResponse{privateStringticket;privatelongexpires_in;publicStringgetTicket(){returnticket;}publicvoidsetTicket(Stringticket){this.ticket=ticket;}publiclonggetExpires_in(){returnexpires_in;}publicvoidsetExpires_in(longexpires_in){this.expires_in=System.currentTimeMillis()+(expires_in-100)1000;//原expires_in是有效时长,比如:7200,现改为过期的时间戳}}publicclassOAuthJsToken{privateStringopenid;//用户唯一标识privateintexpires_in=7200;//凭证有效时间,单位:秒privateStringsession_key;//会话密匙privatelongexprexpiredTime;//过期时间publicStringgetOpenid(){returnopenid;}publicvoidsetOpenid(Stringopenid){this.openid=openid;}publicintgetExpires_in(){returnexpires_in;}publicvoidsetExpires_in(intexpires_in){this.expires_in=expires_in;this.exprexpiredTime=System.currentTimeMillis()+expires_in1000;}publicStringgetSession_key(){returnsession_key;}publicvoidsetSession_key(Stringsession_key){this.session_key=session_key;}publiclonggetExprexpiredTime(){returnexprexpiredTime;}publicvoidsetExprexpiredTime(longexprexpiredTime){this.exprexpiredTime=exprexpiredTime;}/判断用户凭证是否过期@return过期返回true,否则返回false/publicbooleanisExprexpired(){returnSystem.currentTimeMillis()=this.exprexpiredTime;}}
最新资讯
-

小程序制作平台选型踩坑记录:2026年五大主流方案横向对比
2026 年微信小程序月活达 10.7 亿、覆盖 108 个行业,本次横向对比即速应用、乔拓云、凡科、有赞、微盟五大主流平台,分三阶段给出选型结论,核心聚焦成本、扩展性、运营能力三大维度。 -

即速应用,赋能企业玩转微信小程序智慧经营
作为国内领军的智慧商业经营服务商,即速应用始终秉承“让每个企业都拥有自己的智慧店铺”的愿景,持续赋能更多企业玩转智慧经营。即速应用旗下拥有“小程序搭建工具-即速应用”、“私域流量专家-即客云”等产品,帮助商家打通互联网全生态营销闭环。 -

即客云2.0重磅更新,让微信小程序运营更简单!
即客云作为一款基于企业微信的第三方工具,现从多维度提供超过30种功能,自上线以来,已服务多家企业,受到一致好评。近期,我们根据客户反馈和市场调研正式推出升级版 即客云2.0!更新了私域运营SOP,群日历功能,批量拓客,客户雷达,消息推送,个人欢迎语,帮助企业更好运用企业微信;同时提升了社群运营工作标准化,提升运营效率,帮助企业实现客户增长,玩转私域流量。










