找了好多资料,感觉我的这个问题还是得不到解决,希望有志之士可以帮我看看= =!
框架用的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中的格式也是按照文档上写的。。。。真的不知道是哪错了= =
各位博友求助攻啊= =