该功能我在程自己在学习时候尝试搭建的,可能会有很多问题,在这里只是做一下记录。直接上代码。如有不懂请联系楼主或者加群725395843 这里是技术讨论群。供大家讨论。
此文档做回顾。
先上官方文档:http://mp.weixin.qq.com/wiki/home/index.html
做之前建议先过遍文档,文档都说的清晰明了。
如果已经看过文档(或者已经急不可待了),那我们一起整理下JSSDK的流程步骤:
绑定域名
登陆微信公众号,根据下列路径找到添加页面:
微信公众号 - 公众号设置 - 功能设置 - JS接口安全域名
添加步骤:
1.下载txt文件(MP_verify_0HU5eN6Tzfwovxxx.txt),放到项目根目录下;
2.添加项目访问域名地址,点击保存。
在需要调用JS接口的页面引入js文件(页面不支持https的换成http://):
https://res.wx.qq.com/open/js/jweixin-1.0.0.js
config接口权限验证
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
这里着重说下jsApiList参数:
将要用到的接口用引号形式写进去,逗号隔开('','');
这里添加的js接口名称要跟下面的wx.ready()里面的接口顺序对应,当时就吃了这个亏~;
js接口名称见官方文档。
其他参数的值往下看...
通过ready接口处理成功验证:
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});
备注:
里面的js接口顺序一定要按照config()接口中的参数jsApiList中的js接口顺序排列。
通过error接口处理失败验证:
wx.error(function(res){
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
前端jsp页面
注意:要引入相应的文件
一定要引用
后台Controller
package cn.com.sinosoft.controller;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.alibaba.fastjson.JSONObject;
import cn.com.sinosoft.util.CommonUtil;
import cn.com.sinosoft.util.HttpUtil;@Controller
public class WxShareController {
private Logger log = Logger.getLogger(this.getClass());
//获取相关的参数,在application.properties文件中
// @Value("${wechat.appId}")
private String appId ="";//注意 这里必须填写 在你得公众号里面找
// @Value("${wechat.appSecret}")
private String appSecret ="";//注意 这里必须填写 在你得公众号里面找
// @Value("${wechat.url.accessToken}")
private String accessTokenUrl ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
// @Value("${wechat.url.apiTicket}")
private String apiTicketUrl ="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";//微信参数
private String accessToken;
private String jsApiTicket;
//获取参数的时刻
private Long getTiketTime = 0L;
private Long getTokenTime = 0L;
//参数的有效时间,单位是秒(s)
private Long tokenExpireTime = 0L;
private Long ticketExpireTime = 0L;//获取微信参数
@RequestMapping("/wechatParam")
@ResponseBody
public MapgetWechatParam(String url) throws Exception{
//当前时间
long now = System.currentTimeMillis();
log.info("currentTime====>"+now+"ms");//判断accessToken是否已经存在或者token是否过期
/*if(StringUtils.isBlank(accessToken)||(now - getTokenTime > tokenExpireTime*1000)){
JSONObject tokenInfo = getAccessToken();
log.info("————————————————————————————————+"+tokenInfo);
if(tokenInfo != null){
log.info("tokenInfo====>"+tokenInfo.toJSONString());
accessToken = tokenInfo.getString("access_token");
tokenExpireTime = tokenInfo.getLongValue("expires_in");
//获取token的时间
getTokenTime = System.currentTimeMillis();
log.info("accessToken====>"+accessToken);
log.info("tokenExpireTime====>"+tokenExpireTime+"s");
log.info("getTokenTime====>"+getTokenTime+"ms");
}else{
log.info("====>tokenInfo is null~");
log.info("====>failure of getting tokenInfo,please do some check~");
}}*/
//判断jsApiTicket是否已经存在或者是否过期
if(StringUtils.isBlank(jsApiTicket)||(now - getTiketTime > ticketExpireTime*1000)){
JSONObject ticketInfo = getJsApiTicket();
if(ticketInfo!=null){
log.info("ticketInfo====>"+ticketInfo.toJSONString());
jsApiTicket = ticketInfo.getString("ticket");
ticketExpireTime = ticketInfo.getLongValue("expires_in");
getTiketTime = System.currentTimeMillis();
log.info("jsApiTicket====>"+jsApiTicket);
log.info("ticketExpireTime====>"+ticketExpireTime+"s");
log.info("getTiketTime====>"+getTiketTime+"ms");
}else{
log.info("====>ticketInfo is null~");
log.info("====>failure of getting tokenInfo,please do some check~");
}
}//生成微信权限验证的参数
MapwechatParam= makeWXTicket(jsApiTicket,url);
return wechatParam;
}//获取accessToken
/*private JSONObject getAccessToken(){
//String accessTokenUrl = https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
String requestUrl = accessTokenUrl.replace("APPID",appId).replace("APPSECRET",appSecret);
log.info("getAccessToken.requestUrl====>"+requestUrl);
JSONObject result = HttpUtil.doGet(requestUrl);
return result ;
}*///获取ticket
private JSONObject getJsApiTicket() throws Exception{
//String apiTicketUrl = https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
accessToken = CommonUtil.getAccessToken();
String requestUrl = apiTicketUrl.replace("ACCESS_TOKEN", accessToken);
log.info("getJsApiTicket.requestUrl====>"+requestUrl);
JSONObject result = HttpUtil.doGet(requestUrl);
log.info("————————————————————"+result);
return result;
}//生成微信权限验证的参数
public MapmakeWXTicket(String jsApiTicket, String url) {
Mapret = new HashMap ();
String nonceStr = createNonceStr();
String timestamp = createTimestamp();
String string1;
String signature = "";//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + jsApiTicket +
"&noncestr=" + nonceStr +
"×tamp=" + timestamp +
"&url=" + url;
log.info("String1=====>"+string1);
try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
log.info("signature=====>"+signature);
}
catch (NoSuchAlgorithmException e)
{
log.error("WeChatController.makeWXTicket=====Start");
log.error(e.getMessage(),e);
log.error("WeChatController.makeWXTicket=====End");
}
catch (UnsupportedEncodingException e)
{
log.error("WeChatController.makeWXTicket=====Start");
log.error(e.getMessage(),e);
log.error("WeChatController.makeWXTicket=====End");
}ret.put("url", url);
ret.put("jsapi_ticket", jsApiTicket);
ret.put("nonceStr", nonceStr);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
ret.put("appid", appId);return ret;
}
//字节数组转换为十六进制字符串
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
//生成随机字符串
private static String createNonceStr() {
return UUID.randomUUID().toString();
}
//生成时间戳
private static String createTimestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
Util 之拿需要得就可以了
package cn.com.sinosoft.util;
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.*;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import redis.clients.jedis.Jedis;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.log4j.Logger;
import org.junit.Test;import com.alibaba.fastjson.JSONObject;
/**
* request信息
* @author
*
*/
public class CommonUtil {
private static Logger logger = Logger.getLogger(CommonUtil.class);
private static String appId = "";
private static String secret = "";
/*private static String appId = "";
private static String secret = "";*/
public static JSONObject getUrlInfo(String requestURL,String method,String json) throws Exception {
URL get_url = new URL(requestURL);
// 将url 以 open方法返回的urlConnection 连接强转为HttpURLConnection连接
// (标识一个url所引用的远程对象连接)
// 此时cnnection只是为一个连接对象,待连接中
HttpURLConnection httpURLConnection = (HttpURLConnection) get_url
.openConnection();
// 设置请求方式为post
httpURLConnection.setRequestMethod(method);
// 设置连接输出流为true,默认false (post 请求是以流的方式隐式的传递参数)
httpURLConnection.setDoOutput(true);
// 设置连接输入流为true
httpURLConnection.setDoInput(true);
// post请求缓存设为false
httpURLConnection.setUseCaches(false);
// 设置请求头里面的各个属性 (以下为设置内容的类型,设置为经过urlEncoded编码过的from参数)
// application/x-javascript text/xml->xml数据
// application/x-javascript->json对象
// application/x-www-form-urlencoded->表单数据
// ;charset=utf-8 必须要,不然妙兜那边会出现乱码
httpURLConnection.setRequestProperty("Content-type",
"application/json;charset=utf-8");
// 建立连接 (请求未开始,直到connection.getInputStream()方法调用时才发起,以上各个参数设置需在此方法之前进行)
httpURLConnection.connect();// 创建输入输出流,用于往连接里面输出携带的参数,(输出内容为?后面的内容)
OutputStreamWriter out = new OutputStreamWriter(httpURLConnection.getOutputStream(), "UTF-8");
if(method.equals("POST")){
out.append(json);
}
out.flush();
out.close();// 连接发起请求,处理服务器响应 (从连接获取到输入流并包装为bufferedReader)
BufferedReader reader = new BufferedReader(new InputStreamReader(
httpURLConnection.getInputStream(), "UTF-8"));
// 读取数据操作
String str = null;
StringBuffer buffer = new StringBuffer();
while((str = reader.readLine())!= null){
buffer.append(str);
}
//转换成json
JSONObject jsonObj = JSONObject.parseObject(buffer.toString());
reader.close();
return jsonObj;}
public static String getAccessToken() throws Exception{
Jedis jedis = new Jedis("localhost");
String access_token = null;
Boolean conn_flag = true;
try{
logger.info("jedis "+jedis.ping());
access_token = jedis.get("access_token_dg");
if (access_token !=null && access_token.length() > 0 ){
return access_token;
}
}catch(Exception e){
logger.info("redis连接失败");
conn_flag = false;
}
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ appId + "&secret=" + secret;
JSONObject access_token_json = getUrlInfo(url,"GET",null);
access_token = access_token_json.getString("access_token");
if (conn_flag == true){
jedis.set("access_token_dg", access_token);
jedis.expire("access_token_dg", 7000);
}
return access_token;
}
public static String getFreight() throws Exception{
Jedis jedis = new Jedis("localhost");
String freight = null;
try{
logger.info("jedis "+jedis.ping());
freight = jedis.get("freight");
if (freight !=null && freight.length() > 0 ){
return freight;
}
}catch(Exception e){
logger.info("redis连接失败");
}
return null;
}
public static String getOpenId(String code) throws Exception{
logger.debug("code "+code);
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+ appId +"&secret="+ secret +"&code="+ code +"&grant_type=authorization_code";
JSONObject openid_json = getUrlInfo(url,"GET",null);
return openid_json.getString("openid");
}
public static JSONObject getUserInfo(String code) throws Exception{
String access_token = getAccessToken();
logger.debug("access_token "+access_token);
String openid = getOpenId(code);
logger.debug("openid "+openid);
String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+access_token+"&openid="+openid+"&lang=zh_CN";
return getUrlInfo(url,"GET",null);
}
public static JSONObject getUserInfoByOpenid(String openid) throws Exception{
String access_token = getAccessToken();
logger.debug("access_token "+access_token);
String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token="+access_token+"&openid="+openid+"&lang=zh_CN";
return getUrlInfo(url,"GET",null);
}
public static JSONObject createQRcode(String args,String qrtype) throws Exception{
String access_token = getAccessToken();
String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+access_token;
String jsonStr = null;
TreeMaptm = new TreeMap ();
Mapm = new HashMap ();
if (qrtype.equals("limit")){
logger.debug("-----"+args);
jsonStr = "{\"action_name\": \"QR_LIMIT_STR_SCENE\", \"action_info\":{\"scene\": {\"scene_str\":\""+ args + "\"}}}";
//JSONObject jsonObject = getUrlInfo(url,"POST",jsonStr);
logger.debug("jsonStr "+jsonStr);
}else{
}
return getUrlInfo(url,"POST",jsonStr);
}
/*public static JSONObject createQRcode(int args,String qrtype) throws Exception{
String access_token = getAccessToken();
String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token="+access_token;
String jsonStr = null;
TreeMaptm = new TreeMap ();
Mapm = new HashMap ();
if (qrtype.equals("limit")){
logger.debug("-----"+args);
jsonStr = "{\"action_name\": \"QR_LIMIT_SCENE\", \"action_info\":{\"scene\": {\"scene_id\": "+args+"}}}";
logger.debug("jsonStr "+jsonStr);
}else{
jsonStr = "{\"expire_seconds\": 2592000,\"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": "+args+"}}}";
}
return getUrlInfo(url,"POST",jsonStr);
}*/
public static Boolean downloadFile(String urlString, String filePath){
// 构造URL
URL url;
try {
url = new URL(urlString);
// 打开连接
URLConnection con;
try {
con = url.openConnection();
// 输入流
InputStream is = con.getInputStream();
// 1K的数据缓冲
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
// 输出的文件流
OutputStream os = new FileOutputStream(filePath);
// 开始读取
while ((len = is.read(bs)) != -1) {
os.write(bs, 0, len);
}
// 完毕,关闭所有链接
os.close();
is.close();
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
@Test
public void shsh(){
System.out.println("df "+CommonUtil.class);
logger.info("sle");
}
@Test
public static Boolean checkNum(String args){
String pattern = "\\d+";
boolean isMatch = Pattern.matches(pattern, args);
if(isMatch == true){
System.out.println("true");
}else{
System.out.println("false");
}
return isMatch;
}public static String PostSendMsg(JSONObject json, String url) {
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", "application/json");
post.addHeader("Authorization", "Basic YWRtaW46");
String result = "";
try {
StringEntity s = new StringEntity(json.toString(), "utf-8");
s.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
post.setEntity(s);
// 发送请求
HttpResponse httpResponse = HttpClients.createDefault().execute(post);
// 获取响应输入流
InputStream inStream = httpResponse.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "utf-8"));
StringBuilder strber = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null)
strber.append(line + "\n");
inStream.close();result = strber.toString();
System.out.println(result);if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
System.out.println("请求服务器成功,做相应处理");
} else {
System.out.println("请求服务端失败");
}
} catch (Exception e) {
System.out.println("请求异常");
throw new RuntimeException(e);
}
return result;
}
public static void returnMsg(HttpServletResponse response,String message) throws IOException{
response.setContentType("text/html;charset=UTF-8");
response.getWriter().print(message);
}
}
httpUtil
package cn.com.sinosoft.util;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;public class HttpUtil {
//get请求
public static JSONObject doGet(String requestUrl) {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String responseContent = null;
com.alibaba.fastjson.JSONObject result = null;
try {
//创建Get请求,
HttpGet httpGet = new HttpGet(requestUrl);
//执行Get请求,
response = httpClient.execute(httpGet);
//得到响应体
HttpEntity entity = response.getEntity();
//获取响应内容
responseContent = EntityUtils.toString(entity,"UTF-8");
//转换为map
result = JSON.parseObject(responseContent);
} catch (IOException e) {
}
return result;
}
}