有关微信卡券的问题

时间:2022-08-30 07:25:44

找了好多资料,感觉我的这个问题还是得不到解决,希望有志之士可以帮我看看= =!

框架用的springMVC,然后要实现的功能就是简单的微信卡券添加,然后领取。

首先理一下思路,按照微信开发者文档上的JSSDK使用步骤

1.绑定域名

  先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

2.引用js文件

  在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js

3.通过config接口注入权限验证配置

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

4.通过ready接口处理成功验证

wx.ready(function(){
    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,
  // 则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});

5.批量添加卡券接口

wx.addCard({
    cardList: [{
        cardId: '',
        cardExt: ''
    }], // 需要添加的卡券列表
    success: function (res) {
        var cardList = res.cardList; // 添加的卡券列表信息
    }
});

 

根据以上步骤,一下贴出我自己的代码

1.域名已绑定(不然也不会走到下面的步骤了)

2.引用js文件(在以下jsp中已引用)

3.config注入(在以下jsp中已注入)

这是index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="http://demo.open.weixin.qq.com/jssdk/css/style.css?ts=1420774989">
<title>Insert title here</title>
</head>
<body>
    <button class="btn btn_primary" id="addCard">addCard</button>
    <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    <script>
    alert(location.href.split('#')[0]);//alert当前页面的url
        wx.config({
            debug : true,
            appId : '${wxAppid}',
            timestamp : '${timestamp}',
            nonceStr : '${nonceStr}',
            signature : '${js_signature}',
            jsApiList : [ 'addCard' ]
        });
        wx.ready(function() {
        //添加卡券
        document.querySelector('#addCard').onclick = function() {
            wx.addCard({
                cardList :[{
                        cardId : '${cardId}',
              // cardExt详见附录4,
值得注意的是,这里的card_ext参数必须与参与签名的参数一致,格式为字符串而不是Object,否则会报签名错误。 cardExt : '{code:'+'${code}'+',timestamp:'+'${timestamp}'+',signature:'+'${card_signature}'+'}' }], success : function(res) { alert('已添加卡券:' + JSON.stringify(res.cardList)); } }); }; }); </script> </body> </html>

 card_signature签名规则与上面的js_signature不一样,要获取不同的卡券api_ticket,此签名也使用了微信提供的sign规则的签名

以下是后台java代码

/*
 * 文 件 名:  WxTest.java
 * 版    权:  Copyright YYYY-YYYY,  All rights reserved
 * 描    述:  <描述>
 * 创 建 人:  james
 * 创建时间:  2016年5月11日
 */
package com.koolyun.coupon.card.controller;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.google.gson.Gson;
import com.james.base.WxCardBaseInfo;
import com.james.base.WxCardGroupon;
import com.koolyun.coupon.card.protocol.WxCardResponse;
import com.koolyun.coupon.card.protocol.WxCardSign;
import com.koolyun.coupon.card.protocol.WxWhiteList;
import com.koolyun.coupon.card.util.Sign;
import com.koolyun.coupon.mall.protocol.WxAccessTokenResponse;
import com.koolyun.coupon.mall.protocol.WxJsApiTicketResponse;
import com.koolyun.coupon.mall.util.HttpClientHelper;
import com.koolyun.coupon.mall.util.JsonHelper;

/**
 * <一句话功能简述>
 *  
 * @author  james
 * @version  [V1.00, 2016年5月11日]
 * @see  [相关类/方法]
 * @since V1.00
 */
@Controller
@RequestMapping("/WxTest")
public class WxTest {
    
    private Logger log = LoggerFactory.getLogger(getClass());

    private String white_list_url = "https://api.weixin.qq.com/card/testwhitelist/set?access_token=%s";
    private String jsApi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi";
    private String cardApi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=wx_card";
    private String getAccessToken_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
    private String cardCreate_url = "https://api.weixin.qq.com/card/create?access_token=%s";
    private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
  //appid和appsecret我就不贴出来了
   private static String appid = ""; private static String appSecret = ""; //获取accessToken public WxAccessTokenResponse getAccessToken(String appid,String appSecret){ WxAccessTokenResponse token = new WxAccessTokenResponse(); String url = String.format(getAccessToken_url, appid, appSecret); String result = HttpClientHelper.get(url); token = JsonHelper.str2bean(result, WxAccessTokenResponse.class); log.info("token" + token); return token; } public String getCardApiTicket(){ String tokenStr = getAccessToken(appid, appSecret).getAccessToken(); String url = String.format(cardApi_ticket_url,tokenStr); String result = HttpClientHelper.get(url); WxJsApiTicketResponse resp = JsonHelper.str2bean(result, WxJsApiTicketResponse.class); String cardapi_ticket = resp.getTicket(); log.info("cardapi_ticket:"+cardapi_ticket); return cardapi_ticket; } public String getJsApiTicket(){ String tokenStr = getAccessToken(appid, appSecret).getAccessToken(); String url = String.format(jsApi_ticket_url, tokenStr); String result = HttpClientHelper.get(url); WxJsApiTicketResponse resp = JsonHelper.str2bean(result, WxJsApiTicketResponse.class); String jsapi_ticket = resp.getTicket(); log.debug("jsapi_ticket",jsapi_ticket); return jsapi_ticket; } @RequestMapping("/index") public ModelAndView index(HttpServletRequest request) throws ParseException, JSONException{ ModelAndView mav = new ModelAndView(); cardCreate(); String jsapi_ticket = getJsApiTicket(); StringBuilder url = new StringBuilder(); url.append(request.getScheme()).append("://") .append(request.getServerName()).append(":").append(request.getServerPort()) .append(request.getContextPath()).append(request.getServletPath()); if (null != request.getQueryString()) { url.append(request.getQueryString()); } Map<String, String> signMap = Sign.sign(jsapi_ticket, url.toString()); String nonceStr = signMap.get("nonceStr"); String timestamp = signMap.get("timestamp"); String js_signature = signMap.get("signature"); log.info("\nnonceStr:{},\ntimestamp:{},\njs_signature:{}",nonceStr,timestamp,js_signature); mav.addObject("wxAppid",appid); mav.addObject("timestamp", timestamp); mav.addObject("nonceStr", nonceStr); mav.addObject("js_signature", js_signature); String cardapi_ticket = getCardApiTicket(); String code = "nic18951853790"; String cardId = ((WxCardResponse)cardCreate().getModel().get("resp")).getCard_id(); WxCardSign sign = new WxCardSign(); sign.AddData(nonceStr); sign.AddData(timestamp); sign.AddData(cardapi_ticket); sign.AddData(code); sign.AddData(cardId); //cardsign签名 String card_signature =sign.GetSignature(); log.info("card_signature:" + card_signature); mav.addObject("cardId", cardId); mav.addObject("code",code); mav.addObject("openid", "oa-UKw2o8oxbkhDC0DzcJzxEWaOc"); mav.addObject("card_signature",card_signature); mav.setViewName("card/index"); return mav; } @RequestMapping("/createCard") public ModelAndView cardCreate() throws ParseException, JSONException{ ModelAndView mav = new ModelAndView(); String tokenStr = getAccessToken(appid, appSecret).getAccessToken(); String whiteListUrl = String.format(white_list_url, tokenStr); //WxWhiteListResponse whiteResp = new WxWhiteListResponse(); WxWhiteList list = new WxWhiteList(); List<String> openidList = new ArrayList<String>(); String openid = "oa-UKw2o8oxbkhDC0DzcJzxEWaOc"; openidList.add(openid); list.setOpenid(openidList); String whiteListResult = HttpClientHelper.postString(whiteListUrl, new Gson().toJson(list)); //whiteResp = JsonHelper.str2bean(whiteListResult, WxWhiteListResponse.class); log.info("whiteListResult" + whiteListResult); String url = String.format(cardCreate_url,tokenStr); WxCardResponse resp = new WxCardResponse(); WxCardGroupon card = new WxCardGroupon(); card.setDealDetail("团购详情啊啊啊啊啊!!!"); WxCardBaseInfo baseInfo = card.getBaseInfo(); baseInfo.setLogoUrl( "http://mmbiz.qpic.cn/mmbiz/iaL1LJM1mF9aRKPZJkmG8xXhiaHqkKSVMMWeN3hLut7X7hicFNjakmxibMLGWpXrEXB33367o7zHN0CwngnQY7zb7g/0"); baseInfo.setBrandName("海底捞测试账号"); baseInfo.setCodeType(0); baseInfo.setTitle("380元测试账号"); baseInfo.setSubTitle("周末狂欢必备"); baseInfo.setColor("Color010"); baseInfo.setNotice("使用时向服务员出示此券"); baseInfo.setServicePhone("020-88888888"); baseInfo.setDescription("不可与其他优惠同享\n如需团购券发票,请在消费时向商户提出\n店内均可使用,仅限堂食"); /* * DateInfo dateInfo = new DateInfo(); * dateInfo.setType("DATE_TYPE_FIX_TERM"); dateInfo.setFixed_term(15); * dateInfo.setFixed_begin_term(0); baseInfo.setDate_info(dateInfo); */ //baseInfo.setDateInfoFixTerm(15, 0); Date begin = formatter.parse("2016-05-11 00:00:00"); Date end = formatter.parse("2016-05-21 23:59:59"); baseInfo.setDateInfoTimeRange(begin, end); /* * List<Integer> list = new ArrayList<Integer>(); * baseInfo.setQuantity(500000); list.add(baseInfo.getQuantity()); * baseInfo.setSku(list); */ baseInfo.setQuantity(500000); baseInfo.setGetLimit(3); baseInfo.setUseCustomCode(true); baseInfo.setBindOpenid(false); baseInfo.setCanShare(true); baseInfo.setCanGiveFriend(true); /*List<Integer> locationList = new ArrayList<Integer>(); locationList.add(123); locationList.add(234); locationList.add(345); baseInfo.setLocationIdList(locationList);*/ String result = HttpClientHelper.postString(url, card.toJsonString()); log.info("cardCreate:" + result); resp = JsonHelper.str2bean(result, WxCardResponse.class); mav.addObject("card", card); ModelMap map = new ModelMap(); map.put("description", card.getBaseInfo().getDescription()); map.put("brand_name", card.getBaseInfo().GetBrandName()); map.put("title", card.getBaseInfo().getTitle()); map.put("sub_title", card.getBaseInfo().getSubTitle()); map.put("notice", card.getBaseInfo().getNotice()); map.put("service_phone", card.getBaseInfo().getServicePhone()); map.put("location_id_list", card.getBaseInfo().getLocationIdList()); map.put("type", card.getBaseInfo().getDateInfo().get("type")); map.put("beginTime", formatter.format(card.getBaseInfo().getDateInfo().get("begin_timestamp"))); map.put("endTime", formatter.format(card.getBaseInfo().getDateInfo().get("end_timestamp"))); mav.addAllObjects(map); mav.setViewName("card/createCard"); mav.addObject("resp", resp); return mav; } }

万事俱备,只欠东风,然而通过微信访问此网页,在通过config校验之后,按照微信接口应该跳到微信领取卡券的页面,但是报“参数错误”

根据卡券错误码接口文档描述  领取时提示参数错误:错误原因有

1:未设置用户白名单2:自定义code 超过20 字符3:cardext中格式错误

白名单已设置,自定义code也没超过20字符,cardext中的格式也是按照文档上写的。。。。真的不知道是哪错了= =

各位博友求助攻啊= =