正常分享状态显示:
分享异常状态显示:
一切变得那么的。。。无助!!!
开始以为在H5页面上添加一些东西即可,后来发现,完全不是自己想象的那个样子。
这个东西,对于一个从未用过微信JS的码农来说,或许要被带坑里去卡个几天!!!
以下是本人的一点点经验拿来和各位分享,希望刚接触到的少走一些弯路!
1.需要公众号一个,得到appid,appkey等等
2.需要在H5页面添加一些js方法,作用:调用微信api,获取access_token和jsapi_ticket【api的每天调用次数有限,每次调用返回的结果也不同,即,会改变之前的token,之前的就会失效,分享结果也失效】
3.调用api目的就是通过 access_token 和 jsapi_ticket 得到“nonceStr”和“signature”
4.将获得的参数注入H5页面中的【wx.config】中,加载、配置微信分享参数
over。。。
官方的示例代码:http://demo.open.weixin.qq.com/jssdk/sample.zip
官方文档:点击打开链接
【调用次数有限,请注意】
http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
=================以下是本人开发的全部代码,如有遗漏代码,麻烦留言提示一下,谢谢
/****************************** js请求接口 ***************/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 用途描述:微信内部点击分享Controller
*
* @author
* @version 1.0.0
*/
@RestController
@RequestMapping(value = "/wechat")
public class WeChatShareController {
private final static Logger LOG = LoggerFactory.getLogger(WeChatShareController.class);
@Autowired
private WeChatShareService weChatShareService;
/**
* 获取微信加密信息
*
* @param request
* @return
*/
@RequestMapping(value = "/getsignature", method = {RequestMethod.GET})
public Map toTranscript(@RequestParam(value = "url", required = true) String url) {
Map data = new HashMap();
try {
// 去数据库查询已保存的微信加密信息token等等(调用微信api获取token和保存的代码下面都有)
Map wxInfo = weChatShareService.queryWechatInfo(url);
data.put("wxInfo", wxInfo);
return MsgCodeUtil.createMsg(MsgCodeUtil.CODE_SUCCESS, data);
} catch (Exception e) {
LOG.error("获取微信加密信息" + e.getMessage(), e);
return MsgCodeUtil.createMsg(MsgCodeUtil.CODE_UNKNOWN_ERROR);
}
}
}
/****************************** WeChatShareService ***************/
/**
* 用途描述:微信内部点击分享Service
*
* @version 1.0.0
*/
@Service
public class WeChatShareService {
@Autowired
private WechatShareTokenDao wechatShareTokenDao;
/**
* 获取微信加密信息
*
* @param url
* @return
* @throws Exception
*/
public Map queryWechatInfo(String url) throws Exception {
Map wxInfo = new HashMap<>();
String accessToken = "";
String jsapiTicket = "";
//1、获取AccessToken和jsapiTicket,先从数据库获取最近一次保存的。
// Map result = wechatShareTokenDao.queryWechatInfo();
// if (null != result && !result.isEmpty()) {
// accessToken = this.objToString(result.get("wechat_access_token"), "");
// jsapiTicket = this.objToString(result.get("wechat_jsapi_ticket"), "");
// }
// 先不存储,直接调用api查询测试(注意:每日查询token次数有限,所以我们要自己定时获取并存储到数据库,
// 每个token是2小时过期,我们间隔30分钟去更新一个就差不多了,时间设置多久自己看着办)
accessToken = WeChatUitl.getAccessToken();
jsapiTicket = WeChatUitl.getTicket(accessToken);
//3、时间戳和随机字符串
long currentTimes = System.currentTimeMillis(); // 时间戳
String noncestr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);//随机字符串
String timestamp = String.valueOf(currentTimes / 1000);// 时间戳
//5、将参数排序并拼接字符串
String params = "jsapi_ticket=" + jsapiTicket + "&noncestr=" + noncestr + "×tamp=" + timestamp + "&url=" + url;
//6、将字符串进行sha1加密
String signature = WeChatUitl.getSHA1(params);
//7、微信appId
String appId = WeChatUitl.appIdWx;
wxInfo.put("appId", appId);
wxInfo.put("accessToken", accessToken);
wxInfo.put("jsapiTicket", jsapiTicket);
wxInfo.put("timestamp", timestamp);
wxInfo.put("nonceStr", noncestr);
wxInfo.put("params", params);
wxInfo.put("signature", signature);
return wxInfo;
}
public static String objToString(Object obj, String def) {
return obj == null ? def : obj.toString();
}
}
****************************** WeChatUitl ***************
import net.sf.json.JSONObject;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
/**
* 用途描述: 微信开发获取信息---微信开放平台
* (这个方法内参数不要去改,说不定会出什么问题,除了tokenWx,appIdWx,appSecretWx,keyWx修改为自己对应值)
*
* @version 1.0.0
*/
public class WeChatUitl {
// 获取token的描述,自己定义就可以了
public static final String tokenWx = "*****_token";
public static final String appIdWx = "wx700000000000000"; // 微信appid---微信公众平台
public static final String appSecretWx = "71**************************4"; // 微信AppSecret---微信公众平台
// 测试号,可以在微信公众平台直接创建一个,下面我会贴图考诉你怎么创建,这些都是要获取微信token用的
// public static final String appIdWx = "wx500000000000000"; // 微信appid---微信公众平台--测试号
// public static final String appSecretWx = "8e**************************ad"; // 微信AppSecret---微信公众平台--测试号
/**
* 获取access_token
*
* @return
*/
public static String getAccessToken() {
String access_token = "";
String grant_type = "client_credential";//获取access_token填写client_credential
String AppId = appIdWx;//第三方用户唯一凭证
String secret = appSecretWx;//第三方用户唯一凭证密钥,即appsecret
//这个url链接地址和参数皆不能变
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=" + grant_type + "&appid=" + AppId + "&secret=" + secret;
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = new byte[size];
is.read(jsonBytes);
String message = new String(jsonBytes, "UTF-8");
JSONObject demoJson = JSONObject.fromObject(message);
System.out.println("JSON字符串:" + demoJson);
access_token = demoJson.getString("access_token");
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return access_token;
}
/**
* 获取jsapi_ticket
*
* @param access_token
* @return
*/
public static String getTicket(String access_token) {
String ticket = null;
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi";//这个url链接和参数不能变
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = new byte[size];
is.read(jsonBytes);
String message = new String(jsonBytes, "UTF-8");
JSONObject demoJson = JSONObject.fromObject(message);
System.out.println("JSON字符串:" + demoJson);
ticket = demoJson.getString("ticket");
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return ticket;
}
/**
* SHA、SHA1加密
*
* @parameter: str:待加密字符串
* @return: 加密串
**/
public static String getSHA1(String str) {
try {
MessageDigest digest = java.security.MessageDigest
.getInstance("SHA-1"); //如果是SHA加密只需要将"SHA-1"改成"SHA"即可
digest.update(str.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexStr = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexStr.append(0);
}
hexStr.append(shaHex);
}
return hexStr.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
//1、获取AccessToken
String accessToken = getAccessToken();
// String accessToken = "6_Exc9VRFdPMLeF-4gPaJJGmoo-BJUGzgSJcs3vkT_y4eXPiQzRf1vdMvlVXNE85sfYH9AtQcdd-zptyD5t5S98VXSwIapyMoYjBNfvH7A11GZOoWs2u6agFlLS9NMqzTgN1N5V16BZrL1BnV_WTIaAIAHET";
//2、获取Ticket
String jsapi_ticket = getTicket(accessToken);
//3、时间戳和随机字符串
String noncestr = UUID.randomUUID().toString().replace("-", "").substring(0, 16);//随机字符串
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);//时间戳
System.out.println("accessToken:" + accessToken + "\njsapi_ticket:" + jsapi_ticket + "\n时间戳:" + timestamp + "\n随机字符串:" + noncestr);
//4、获取url
String url = "http://localhost:8080/project/share";
// 根据JSSDK上面的规则进行计算,这里比较简单,我就手动写啦
// String[] ArrTmp = {"jsapi_ticket","timestamp","nonce","url"};
// Arrays.sort(ArrTmp);
// StringBuffer sf = new StringBuffer();
// for(int i=0;i createMsg(int code, String msg, Object data) {
Map message = new HashMap();
message.put("code", code);
message.put("msg", setMsg(code, msg));
if (data != null) {
message.put("data", data);
}
return message;
}
public static Map createMsg(int code, String msg) {
return createMsg(code, msg, null);
}
public static Map createMsg(int code, Object obj) {
return createMsg(code, null, obj);
}
public static Map createMsg(int code) {
return createMsg(code, null, null);
}
private static String setMsg(int code, String msg) {
if (code == CODE_SUCCESS) {
return StringUtils.isBlank(msg) ? MSG_SUCCESS : msg;
}
if (code == CODE_FAILED) {
return StringUtils.isBlank(msg) ? MSG_FAILED : msg;
}
if (code == CODE_UNAUTHORIZED) {
return StringUtils.isBlank(msg) ? MSG_UNAUTHORIZED : msg;
}
if (code == CODE_UNKNOWN_ERROR) {
return StringUtils.isBlank(msg) ? MSG_UNKNOWN_ERROR : msg;
}
return msg;
}
}
在需要分享的页面加入以下代码:
1.引入微信分享必须用到的 js
2.input标签
3.js代码
<%-- IOS JSON 赋值 getShareBean(); --%>
<%--------------------------------------- 微信分享开始 ---------------------------------%>
<%----这个页面写公共的JS方法,在下面-----%>
<%----或者封装成js文件再引入-----%>
<%---------%>
<%--------------------------------------- 微信分享结束 ---------------------------------%>
/****************************** wechat_share.jsp ***************/
===========================代码结束,接下来就是一个最麻烦的步骤了,公众平台配置
本机IP获取方式
调用“获取access_token”接口,返回结果。
错误信息显示ip无权限,就是这个。
在这里也一起把线上服务器的IP也一起设置进去,因为每次设置的时候都要找老板的手机来扫微信二维码,脑壳疼
注意,如果线上服务器ip地址有变动,必须修改微信公众号ip白名单配置
花生壳配置:
IDEA Tomcat 配置:
a.按照步骤下载文件,将文件复制到项目根目录和tomcat项目根目录
下载文件:MP_verify_1pnZudconNzHFayL.txt 注意不要修改文件名称
b.在浏览器能访问到文件就OK
比如项目名是:tb_project
本地测试调用:http://192.168.88.91:8080/tb_project/MP_verify_1pnZudconNzHFayL.txt
花生壳调用:http://5743xhb03479.xxx/MP_verify_1pnZudconNzHFayL.txt
到这里,就完全到位了,over
关于定时保存token到自己的服务器,推荐用 spring scheduled,简单,方便,实用
配置文件加好之后,PickTask这个类下面的【tickers】方法,30分钟执行一次。
具体使用方法,问度娘。
有关数据存储做好之后,最好再存储一下缓存,比如redis,每次分享就不用去查询数据库了