因为工作需要,最近在做微信公众号开发,主要是在微信分享时自定义公司的logo和文案,开发过程中遇到了一些问题,总结如下:
因为工作需要,最近在做微信公众号开发,主要是在微信分享时自定义公司的logo和文案,开发过程中遇到了一些问题,总结如下:
开发前首先得去微信公众号平台申请注册一个账号,注册成功后拿到appid和secret。具体申请流程请参考微信公众号平台。
开发步骤:
1.通过appid,secret和“client_credential”获取token,因为获取token的api调用次数有限且有限时长为2小时,所以第一次取到token后必须全局缓存(放到数据库还是前端根据业务需要)。
2.通过第一步得到的token,调用微信jsapi获取ticket,同样ticket也需要进行全局缓存。
3.通过获取到的ticket,随机串,时间戳和当前页面的url,按照微信生成签名的规则进行加密并生成签名。
4.把上述得到的数据返回给前端。
开发过程中遇到了一些问题:
1.2小时内尽管token,ticket,timestamp等都是不变的,但是每次进入新的页面时url是变化的,所以sign得相应的变化。
2.自定义的图片太大时会出现图片显示不出来的问题,所以要将图片压缩,最好在10K以内。
JavaScript代码:
!function() {
var dataForWeixin = {
title: "",
desc: "",
imgUrl:“logo.png",
link: ”要分享的链接“
};
var href = location.origin + location.pathname + location.search;
$.ajax({
url: '/ebusiness/auto/getWechatConfigParams.do',
data: {
'href': href,
'ticket': localStorage.getItem('ticket') || "",
'nonceStr': localStorage.getItem('nonceStr') || "",
'timestamp': localStorage.getItem('timestamp') || ""
},
datatype: 'json',
cache: false,
async: false,
success: function(msg) {
var result = JSON.parse(msg);
if (result.code == 1) {
localStorage.setItem('appId', result.appId);
localStorage.setItem('accessToken', result.access_token);
localStorage.setItem('timestamp', result.timestamp);
localStorage.setItem('ticket', result.ticket);
localStorage.setItem('nonceStr', result.nonceStr);
localStorage.setItem('signature', result.signature);
dataForWeixin.title = result.title;
dataForWeixin.desc = result.desc;
} else if (result.code == 2) {
localStorage.setItem('signature', result.signature);
dataForWeixin.title = result.title;
dataForWeixin.desc = result.desc;
} else {
console.log("获取token异常!");
}
},
error: function(msg) {
console.log("请求数据失败!");
}
});
wx.config({
debug : false,
appId : localStorage.getItem('appId'),
timestamp : localStorage.getItem('timestamp'),
nonceStr : localStorage.getItem('nonceStr'),
signature : localStorage.getItem('signature'),
jsApiList : [ 'checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ' ]
});
wx.ready(function() {
wx.checkJsApi({
jsApiList : ['onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ' ],
fail: function(res) {
console.log("微信版本过低,请升级到新版本!");
}
});
wx.onMenuShareTimeline({
title : dataForWeixin.desc,
link : dataForWeixin.link,
imgUrl : dataForWeixin.imgUrl,
success: function (res) {
console.log("分享到朋友圈成功!");
},
fail: function(res) {
console.log("分享到朋友圈失败!");
}
});
wx.onMenuShareAppMessage({
title : dataForWeixin.title,
desc : dataForWeixin.desc,
link : dataForWeixin.link,
imgUrl : dataForWeixin.imgUrl,
success: function (res) {
console.log("分享到微信好友成功!");
},
fail: function(res) {
console.log("分享到微信好友失败!");
}
});
wx.onMenuShareQQ({
title: dataForWeixin.title,
desc: dataForWeixin.desc,
link: dataForWeixin.link,
imgUrl: dataForWeixin.imgUrl,
success: function (res) {
console.log("分享到QQ好友成功!");
},
fail: function(res) {
console.log("分享到QQ好友失败!");
}
});
});
wx.error(function(res) {
console.log(res.errMsg);
});
}();
public class GetWechatConfigParamsController extends AbstractController {
private static final String APP_ID = "";
private static final String SECRET = "";
private static final String GRANT_TYPE = "client_credential";
private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
private static final String TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
private static final String WECHAT_TITLE = "wechat.title";
private static final String WECHAT_DESC = "wechat.desc";
private Logger logger = Logger.getLogger(this.getClass());
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String href = request.getParameter("href");
String ticket = request.getParameter("ticket");
String nonceStr = request.getParameter("nonceStr");
String timestamp = request.getParameter("timestamp");
long curTimestmap = (long)(new Date().getTime() / 1000);
JSONObject result = new JSONObject();
if (!this.isNullOrEmpty(ticket) && !this.isNullOrEmpty(nonceStr) && !this.isNullOrEmpty(timestamp)
&& (curTimestmap - Long.parseLong(timestamp) <= 7000)) {
logger.info("已缓存token且没有超过2小时!");
result.put("code", 2);
result.put("appId", APP_ID);
result.put("timestamp", timestamp);
result.put("ticket", ticket);
result.put("nonceStr", nonceStr);
String signature = CoderUtils.encodeSHA(this.constructEncryptString(href, nonceStr, result));
logger.info("进行sha1签名后的字符串为---> " + signature);
result.put("signature", signature);
result.put("title", Configuration.getValue(WECHAT_TITLE));
result.put("desc", Configuration.getValue(WECHAT_DESC));
} else {
logger.info("开始获取access_token!");
String accessTokenResult = this.getWechatInfoByGetMethod(this.constructAccessTokenUrl(GRANT_TYPE, APP_ID, SECRET));
logger.info("获取到的access_token信息为:" + accessTokenResult);
result = JSONObject.fromObject(accessTokenResult);
//用于给页面的标识:0表示失败,1表示成功,2表示已缓存相关值
if (null != accessTokenResult) {
result.put("code", 1);
result.put("appId", APP_ID);
result.put("timestamp", (long)(new Date().getTime() / 1000));
logger.info("开始获取jsapi_ticket!");
String ticketResult = this.getWechatInfoByGetMethod(this.constructTicketUrl(result.getString("access_token"), "jsapi"));
logger.info("获取到的jsapi_ticket信息为:" + ticketResult);
JSONObject ticketJson = JSONObject.fromObject(ticketResult);
if (0 == ticketJson.getInt("errcode") &&
"ok".equals(ticketJson.getString("errmsg").toLowerCase())) { //成功
result.put("ticket", ticketJson.getString("ticket"));
String nonceString = this.createRandomString();
result.put("nonceStr", nonceString);
String signature = CoderUtils.encodeSHA(this.constructEncryptString(href, nonceString, result));
logger.info("进行sha1签名后的字符串为:" + signature);
result.put("signature", signature);
result.put("title", Configuration.getValue(WECHAT_TITLE));
result.put("desc", Configuration.getValue(WECHAT_DESC));
}
} else {
result.put("code", 0);
}
}
logger.info("返回给页面的数据:" + result.toString());
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.getWriter().print(result);
return null;
}
/**
* @param grant_type
* @param appId
* @param secret
* @return 组装好的获取access_token的url
*/
private String constructAccessTokenUrl(String grant_type, String appId, String secret) {
StringBuffer url = new StringBuffer(ACCESS_TOKEN_URL);
url.append("?")
.append("grant_type=" + grant_type)
.append("&")
.append("appid=" + appId)
.append("&")
.append("secret=" + secret);
logger.info("获取微信access_token的URL为:" + url.toString());
return url.toString();
}
/**
* @param accessToken
* @param jsApi
* @return 获取jsapi_ticket的url
*/
private String constructTicketUrl(String accessToken, String jsApi) {
StringBuffer url = new StringBuffer(TICKET_URL);
url.append("?")
.append("access_token=" + accessToken)
.append("&")
.append("type=" + jsApi);
logger.info("获取微信jsapi_ticket的URIL为:" + url.toString());
return url.toString();
}
/**
* @param url 获信息的url
* @return 获取到的微信信息
*/
private String getWechatInfoByGetMethod(String url) {
HttpClient httpClient = HttpClientUtils.getHttpClient();
GetMethod getMethod = new GetMethod(url);
try {
if (HttpStatus.SC_OK == httpClient.executeMethod(getMethod)) {
return getMethod.getResponseBodyAsString();
}
} catch (HttpException e) {
logger.error("http请求错误!请求路径为:" + url);
e.printStackTrace();
} catch (IOException e) {
logger.error("io读写错误!");
e.printStackTrace();
}
return null;
}
/**
* @return 生成随机字符串
*/
private String createRandomString() {
StringBuffer result = new StringBuffer();
String fromString = "0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ";
int length = fromString.length();
Random random = new Random();
for (int index = 0; index < 16; index++) {
result.append(fromString.charAt(random.nextInt(length)));
}
logger.info("随机字符串为:" + result.toString());
return result.toString();
}
/**
* @param href 链接
* @param randomString 随机串
* @param jsonStr json对象
* @return 拼接后的字符串
*/
private String constructEncryptString(String href, String randomString, JSONObject jsonStr) {
StringBuffer result = new StringBuffer();
result.append("jsapi_ticket=" + jsonStr.getString("ticket"))
.append("&")
.append("noncestr=" + randomString)
.append("&")
.append("timestamp=" + jsonStr.getString("timestamp"))
.append("&")
.append("url=" + href);
logger.info("拼接后的待签名字符串为:" + result.toString());
return result.toString();
}
/**
* @param str 待判断的字符串
* @return 空返回true,非空返回fasle
*/
private boolean isNullOrEmpty(String str) {
if (null == str || str.isEmpty() || "".equals(str)) {
return true;
}
return false;
}
}