微信H5分享 代码和详细配置步骤 js + Java 代码

正常分享状态显示:

分享异常状态显示:

一切变得那么的。。。无助!!!

开始以为在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

 

=================以下是本人开发的全部代码,如有遗漏代码,麻烦留言提示一下,谢谢

 

JAVA代码:

 


    
    
  1. /****************************** js请求接口 ***************/
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. /**
  5. * 用途描述:微信内部点击分享Controller
  6. *
  7. * @author
  8. * @version 1.0.0
  9. */
  10. @RestController
  11. @RequestMapping(value = "/wechat")
  12. public class WeChatShareController {
  13. private final static Logger LOG = LoggerFactory.getLogger(WeChatShareController.class);
  14. @Autowired
  15. private WeChatShareService weChatShareService;
  16. /**
  17. * 获取微信加密信息
  18. *
  19. * @param request
  20. * @return
  21. */
  22. @RequestMapping(value = "/getsignature", method = {RequestMethod.GET})
  23. public Map<String, Object> toTranscript(@RequestParam(value = "url", required = true) String url) {
  24. Map<String, Object> data = new HashMap<String, Object>();
  25. try {
  26. // 去数据库查询已保存的微信加密信息token等等(调用微信api获取token和保存的代码下面都有)
  27. Map<String, Object> wxInfo = weChatShareService.queryWechatInfo(url);
  28. data.put( "wxInfo", wxInfo);
  29. return MsgCodeUtil.createMsg(MsgCodeUtil.CODE_SUCCESS, data);
  30. } catch (Exception e) {
  31. LOG.error( "获取微信加密信息" + e.getMessage(), e);
  32. return MsgCodeUtil.createMsg(MsgCodeUtil.CODE_UNKNOWN_ERROR);
  33. }
  34. }
  35. }
  36. /****************************** WeChatShareService ***************/
  37. /**
  38. * 用途描述:微信内部点击分享Service
  39. *
  40. * @version 1.0.0
  41. */
  42. @Service
  43. public class WeChatShareService {
  44. @Autowired
  45. private WechatShareTokenDao wechatShareTokenDao;
  46. /**
  47. * 获取微信加密信息
  48. *
  49. * @param url
  50. * @return
  51. * @throws Exception
  52. */
  53. public Map<String, Object> queryWechatInfo(String url) throws Exception {
  54. Map<String, Object> wxInfo = new HashMap<>();
  55. String accessToken = "";
  56. String jsapiTicket = "";
  57. //1、获取AccessToken和jsapiTicket,先从数据库获取最近一次保存的。
  58. // Map<String, Object> result = wechatShareTokenDao.queryWechatInfo();
  59. // if (null != result && !result.isEmpty()) {
  60. // accessToken = this.objToString(result.get("wechat_access_token"), "");
  61. // jsapiTicket = this.objToString(result.get("wechat_jsapi_ticket"), "");
  62. // }
  63. // 先不存储,直接调用api查询测试(注意:每日查询token次数有限,所以我们要自己定时获取并存储到数据库,
  64. // 每个token是2小时过期,我们间隔30分钟去更新一个就差不多了,时间设置多久自己看着办)
  65. accessToken = WeChatUitl.getAccessToken();
  66. jsapiTicket = WeChatUitl.getTicket(accessToken);
  67. //3、时间戳和随机字符串
  68. long currentTimes = System.currentTimeMillis(); // 时间戳
  69. String noncestr = UUID.randomUUID().toString().replace( "-", "").substring( 0, 16); //随机字符串
  70. String timestamp = String.valueOf(currentTimes / 1000); // 时间戳
  71. //5、将参数排序并拼接字符串
  72. String params = "jsapi_ticket=" + jsapiTicket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + url;
  73. //6、将字符串进行sha1加密
  74. String signature = WeChatUitl.getSHA1(params);
  75. //7、微信appId
  76. String appId = WeChatUitl.appIdWx;
  77. wxInfo.put( "appId", appId);
  78. wxInfo.put( "accessToken", accessToken);
  79. wxInfo.put( "jsapiTicket", jsapiTicket);
  80. wxInfo.put( "timestamp", timestamp);
  81. wxInfo.put( "nonceStr", noncestr);
  82. wxInfo.put( "params", params);
  83. wxInfo.put( "signature", signature);
  84. return wxInfo;
  85. }
  86. public static String objToString(Object obj, String def) {
  87. return obj == null ? def : obj.toString();
  88. }
  89. }
  90. ****************************** WeChatUitl ***************
  91. import net.sf.json.JSONObject;
  92. import java.io.InputStream;
  93. import java.net.HttpURLConnection;
  94. import java.net.URL;
  95. import java.security.MessageDigest;
  96. import java.security.NoSuchAlgorithmException;
  97. import java.util.UUID;
  98. /**
  99. * 用途描述: 微信开发获取信息---微信开放平台
  100. * (这个方法内参数不要去改,说不定会出什么问题,除了tokenWx,appIdWx,appSecretWx,keyWx修改为自己对应值)
  101. *
  102. * @version 1.0.0
  103. */
  104. public class WeChatUitl {
  105. // 获取token的描述,自己定义就可以了
  106. public static final String tokenWx = "*****_token";
  107. public static final String appIdWx = "wx700000000000000"; // 微信appid---微信公众平台
  108. public static final String appSecretWx = "71**************************4"; // 微信AppSecret---微信公众平台
  109. // 测试号,可以在微信公众平台直接创建一个,下面我会贴图考诉你怎么创建,这些都是要获取微信token用的
  110. // public static final String appIdWx = "wx500000000000000"; // 微信appid---微信公众平台--测试号
  111. // public static final String appSecretWx = "8e**************************ad"; // 微信AppSecret---微信公众平台--测试号
  112. /**
  113. * 获取access_token
  114. *
  115. * @return
  116. */
  117. public static String getAccessToken() {
  118. String access_token = "";
  119. String grant_type = "client_credential"; //获取access_token填写client_credential
  120. String AppId = appIdWx; //第三方用户唯一凭证
  121. String secret = appSecretWx; //第三方用户唯一凭证密钥,即appsecret
  122. //这个url链接地址和参数皆不能变
  123. String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=" + grant_type + "&appid=" + AppId + "&secret=" + secret;
  124. try {
  125. URL urlGet = new URL(url);
  126. HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
  127. http.setRequestMethod( "GET"); // 必须是get方式请求
  128. http.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded");
  129. http.setDoOutput( true);
  130. http.setDoInput( true);
  131. System.setProperty( "sun.net.client.defaultConnectTimeout", "30000"); // 连接超时30秒
  132. System.setProperty( "sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
  133. http.connect();
  134. InputStream is = http.getInputStream();
  135. int size = is.available();
  136. byte[] jsonBytes = new byte[size];
  137. is.read(jsonBytes);
  138. String message = new String(jsonBytes, "UTF-8");
  139. JSONObject demoJson = JSONObject.fromObject(message);
  140. System.out.println( "JSON字符串:" + demoJson);
  141. access_token = demoJson.getString( "access_token");
  142. is.close();
  143. } catch (Exception e) {
  144. e.printStackTrace();
  145. }
  146. return access_token;
  147. }
  148. /**
  149. * 获取jsapi_ticket
  150. *
  151. * @param access_token
  152. * @return
  153. */
  154. public static String getTicket(String access_token) {
  155. String ticket = null;
  156. String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi"; //这个url链接和参数不能变
  157. try {
  158. URL urlGet = new URL(url);
  159. HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
  160. http.setRequestMethod( "GET"); // 必须是get方式请求
  161. http.setRequestProperty( "Content-Type", "application/x-www-form-urlencoded");
  162. http.setDoOutput( true);
  163. http.setDoInput( true);
  164. System.setProperty( "sun.net.client.defaultConnectTimeout", "30000"); // 连接超时30秒
  165. System.setProperty( "sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
  166. http.connect();
  167. InputStream is = http.getInputStream();
  168. int size = is.available();
  169. byte[] jsonBytes = new byte[size];
  170. is.read(jsonBytes);
  171. String message = new String(jsonBytes, "UTF-8");
  172. JSONObject demoJson = JSONObject.fromObject(message);
  173. System.out.println( "JSON字符串:" + demoJson);
  174. ticket = demoJson.getString( "ticket");
  175. is.close();
  176. } catch (Exception e) {
  177. e.printStackTrace();
  178. }
  179. return ticket;
  180. }
  181. /**
  182. * SHA、SHA1加密
  183. *
  184. * @parameter: str:待加密字符串
  185. * @return: 加密串
  186. **/
  187. public static String getSHA1(String str) {
  188. try {
  189. MessageDigest digest = java.security.MessageDigest
  190. .getInstance( "SHA-1"); //如果是SHA加密只需要将"SHA-1"改成"SHA"即可
  191. digest.update(str.getBytes());
  192. byte messageDigest[] = digest.digest();
  193. // Create Hex String
  194. StringBuffer hexStr = new StringBuffer();
  195. // 字节数组转换为 十六进制 数
  196. for ( int i = 0; i < messageDigest.length; i++) {
  197. String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
  198. if (shaHex.length() < 2) {
  199. hexStr.append( 0);
  200. }
  201. hexStr.append(shaHex);
  202. }
  203. return hexStr.toString();
  204. } catch (NoSuchAlgorithmException e) {
  205. e.printStackTrace();
  206. }
  207. return null;
  208. }
  209. public static void main(String[] args) {
  210. //1、获取AccessToken
  211. String accessToken = getAccessToken();
  212. // String accessToken = "6_Exc9VRFdPMLeF-4gPaJJGmoo-BJUGzgSJcs3vkT_y4eXPiQzRf1vdMvlVXNE85sfYH9AtQcdd-zptyD5t5S98VXSwIapyMoYjBNfvH7A11GZOoWs2u6agFlLS9NMqzTgN1N5V16BZrL1BnV_WTIaAIAHET";
  213. //2、获取Ticket
  214. String jsapi_ticket = getTicket(accessToken);
  215. //3、时间戳和随机字符串
  216. String noncestr = UUID.randomUUID().toString().replace( "-", "").substring( 0, 16); //随机字符串
  217. String timestamp = String.valueOf(System.currentTimeMillis() / 1000); //时间戳
  218. System.out.println( "accessToken:" + accessToken + "\njsapi_ticket:" + jsapi_ticket + "\n时间戳:" + timestamp + "\n随机字符串:" + noncestr);
  219. //4、获取url
  220. String url = "http://localhost:8080/project/share";
  221. // 根据JSSDK上面的规则进行计算,这里比较简单,我就手动写啦
  222. // String[] ArrTmp = {"jsapi_ticket","timestamp","nonce","url"};
  223. // Arrays.sort(ArrTmp);
  224. // StringBuffer sf = new StringBuffer();
  225. // for(int i=0;i<ArrTmp.length;i++){
  226. // sf.append(ArrTmp[i]);
  227. // }
  228. //5、将参数排序并拼接字符串
  229. String str = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + url;
  230. //6、将字符串进行sha1加密
  231. String signature = Constant.getSHA1(str);
  232. System.out.println( "参数:" + str + "\n签名:" + signature);
  233. }
  234. }
  235. ****************************** MsgCodeUtil工具类 ***************
  236. import java.util.HashMap;
  237. import java.util.Map;
  238. import org.apache.commons.lang.StringUtils;
  239. /**
  240. * 返回code及提示消息
  241. * @version 1.0.0
  242. */
  243. public class MsgCodeUtil {
  244. /**
  245. * 成功
  246. */
  247. public final static int CODE_SUCCESS = 1;
  248. /**
  249. * 失败
  250. */
  251. public final static int CODE_FAILED = 2;
  252. /**
  253. * 无权限
  254. */
  255. public final static int CODE_UNAUTHORIZED = 401;
  256. /**
  257. * 未知错误
  258. */
  259. public final static int CODE_UNKNOWN_ERROR = 1000;
  260. private final static String MSG_SUCCESS = "成功!";
  261. private final static String MSG_FAILED = "失败!";
  262. private final static String MSG_UNAUTHORIZED = "无权限访问!";
  263. private final static String MSG_UNKNOWN_ERROR = "系统出错了!";
  264. public static Map<String, Object> createMsg(int code, String msg, Object data) {
  265. Map<String, Object> message = new HashMap<String, Object>();
  266. message.put( "code", code);
  267. message.put( "msg", setMsg(code, msg));
  268. if (data != null) {
  269. message.put( "data", data);
  270. }
  271. return message;
  272. }
  273. public static Map<String, Object> createMsg(int code, String msg) {
  274. return createMsg(code, msg, null);
  275. }
  276. public static Map<String, Object> createMsg(int code, Object obj) {
  277. return createMsg(code, null, obj);
  278. }
  279. public static Map<String, Object> createMsg(int code) {
  280. return createMsg(code, null, null);
  281. }
  282. private static String setMsg(int code, String msg) {
  283. if (code == CODE_SUCCESS) {
  284. return StringUtils.isBlank(msg) ? MSG_SUCCESS : msg;
  285. }
  286. if (code == CODE_FAILED) {
  287. return StringUtils.isBlank(msg) ? MSG_FAILED : msg;
  288. }
  289. if (code == CODE_UNAUTHORIZED) {
  290. return StringUtils.isBlank(msg) ? MSG_UNAUTHORIZED : msg;
  291. }
  292. if (code == CODE_UNKNOWN_ERROR) {
  293. return StringUtils.isBlank(msg) ? MSG_UNKNOWN_ERROR : msg;
  294. }
  295. return msg;
  296. }
  297. }

 

H5,js代码

在需要分享的页面加入以下代码:

1.引入微信分享必须用到的 js

<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js">
    
    

2.input标签

3.js代码


    
    
  1. <%-- IOS JSON 赋值 getShareBean(); --%>
  2. <input type="hidden" id="shareTitle" name="shareTitle" value="这个是分享标题"/>
  3. <input type="hidden" id="shareContent" name="shareContent" value="这个是分享内容"/>
  4. <input type="hidden" id="shareImage" name="shareImage" value="这里填一个图片全路径"/>
  5. <c:import url="../common_footer.jsp"/>
  6. <%--------------------------------------- 微信分享开始 ---------------------------------%>
  7. <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
  8. <script>
  9. // 只有先这样取值,再赋值给下面的title,desc,imgUrl,link,不然IOS苹果端无法调用成功
  10. var shareTitle = $( "#shareTitle").val();
  11. var shareContent = $( "#shareContent").val();
  12. var shareImage = $( "#shareImage").val();
  13. // 分享出去点击跳转链接必须用这个
  14. var shareUrl = location.href.split( '#')[ 0].toString();
  15. var title = shareTitle;
  16. var desc = shareContent;
  17. // 分享的图片,最好是正方形,不是也没关系,但是一定是http模式,即绝对路径,而不是服务器路劲
  18. var imgUrl = shareImage;
  19. // 该链接域名或路径必须与当前页面对应的公众号JS安全域名一致-----这个特别重要,请看清楚
  20. // 这里的地址可以写死,也可以动态获取,但是一定不能带有微信分享后的参数,不然分享也是失败的
  21. var link = shareUrl;
  22. </script>
  23. <%----这个页面写公共的JS方法,在下面-----%>
  24. <c:import url="../wechat_share.jsp"/>
  25. <%----或者封装成js文件再引入-----%>
  26. <%---- <script src="js/wechat.js"></script>-----%>
  27. <%--------------------------------------- 微信分享结束 ---------------------------------%>
  28. /****************************** wechat_share.jsp ***************/
  29. <script>
  30. // 当前页面访问路径
  31. var url = location.href.split( '#')[ 0].toString();
  32. var getUrl = "wechat/getsignature";
  33. $.get(getUrl,
  34. { "url": url}).done( function (data) {
  35. // 注意这里的url,一定要这样写,也就是动态获取,不然也不会成功的。
  36. // console.log(data);
  37. // console.log(data.code);
  38. if (data.code == 1) {
  39. var wxInfo = data.wxInfo;
  40. if (wxInfo.signature != null) {
  41. wx.config({
  42. debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
  43. appId: wxInfo.appId, // 必填,公众号的唯一标识
  44. timestamp: wxInfo.timestamp, // 必填,生成签名的时间戳
  45. nonceStr: wxInfo.nonceStr, // 必填,生成签名的随机串
  46. signature: wxInfo.signature, // 必填,签名,见附录1
  47. jsApiList: [
  48. 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'onMenuShareQZone'
  49. ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
  50. });
  51. }
  52. }
  53. }).fail( function (msg) {
  54. // console.log("error:" + msg);
  55. });
  56. // 分享给朋友、QQ、微博
  57. var shareData = {
  58. "imgUrl": imgUrl,
  59. "title": title,
  60. "desc": desc,
  61. 'link': link,
  62. success: function() {
  63. // layer.msg("分享成功~", {});
  64. },
  65. cancel: function() {
  66. // layer.msg("取消分享");
  67. }
  68. };
  69. // 分享到朋友圈
  70. var shareToTimeline = {
  71. "imgUrl": imgUrl,
  72. "title": title,
  73. 'link': link,
  74. success: function() {
  75. // layer.msg("分享成功~", {});
  76. },
  77. cancel: function() {
  78. // layer.msg("取消分享");
  79. }
  80. }
  81. wx.ready( function () {
  82. wx.onMenuShareTimeline(shareToTimeline); // 分享到微信朋友圈
  83. wx.onMenuShareAppMessage(shareData); // 分享给微信朋友
  84. wx.onMenuShareQQ(shareData); // 分享到QQ
  85. wx.onMenuShareQZone(shareData); // 分享到QQ空间
  86. wx.onMenuShareWeibo(shareData); // 分享到微博
  87. wx.error( function (res) {
  88. alert(res.errMsg);
  89. });
  90. });
  91. </script>

 

===========================代码结束,接下来就是一个最麻烦的步骤了,公众平台配置


 

第二步:

1.注册/登录微信公众号,获取AppID和AppSecret

 

2.配置公众号业务域名和js安全域名


 

3,在公众号后台添加IP白名单

 

本机IP获取方式

调用“获取access_token”接口,返回结果。

错误信息显示ip无权限,就是这个。

在这里也一起把线上服务器的IP也一起设置进去,因为每次设置的时候都要找老板的手机来扫微信二维码,脑壳疼

注意,如果线上服务器ip地址有变动,必须修改微信公众号ip白名单配置

4.最好先去申请一个域名(花生壳),用于测试,不然只有发布到线上测试了【微信只认域名,不认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,简单,方便,实用

 

spring_scheduled.xml配置文件


    
    
  1. <beans xmlns= "http://www.springframework.org/schema/beans"
  2. xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:task= "http://www.springframework.org/schema/task"
  4. xmlns:context= "http://www.springframework.org/schema/context"
  5. xsi:schemaLocation= "http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context-3.0.xsd
  9. http://www.springframework.org/schema/task
  10. http://www.springframework.org/schema/task/spring-task-3.0.xsd">
  11. <!-- 设置定时任务 -->
  12. <task:annotation-driven/>
  13. <!--扫描包路径-->
  14. <context:component-scan base- package= "com.nas.timed"/>
  15. <!--注意这边需要配置供扫描的类-->
  16. <bean id= "pickDealOrderTask" class= "com.***.***.pickTask"/>
  17. <!--开启定时任务-->
  18. <task:scheduled-tasks scheduler= "scheduler">
  19. <task:scheduled ref= "pickTask" method= "tickers" cron= "0 */30 * * * ?"/> <!--每 30分钟执行一次,cron表达式很多种写法,问一下度娘-->
  20. </task:scheduled-tasks>
  21. <!--最大线程数-->
  22. <task:scheduler id= "scheduler" pool-size= "9" />
  23. </beans>

配置文件加好之后,PickTask这个类下面的【tickers】方法,30分钟执行一次。

具体使用方法,问度娘。

有关数据存储做好之后,最好再存储一下缓存,比如redis,每次分享就不用去查询数据库了

 

祝君好运!!!

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值