2016-01-12 12:44:59 u013142781 阅读数 11760
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27810 人正在学习 去看看 秦子恒

在本篇博客之前,博主已经写了4篇关于微信相关文章,其中三篇是本文基础:

1、微信开发之入门教程,该文章详细讲解了企业号体验号免费申请与一些必要的配置,以及如何调用微信接口。

2、微信开发之通过代理调试本地项目,该文章详细讲解了如何调试本地项目,使用工具的详细安装与配置。

3、微信开发之使用java获取签名signature(贴源码,附工程),该文详细讲些了如何获取签名,代码十分详细。

对于初学者,可能还不知道订阅号、服务号、和企业号的区别,博主之前也是一直没有弄清楚,因此查阅资料整理了一篇博客供大家阅读:微信服务号、订阅号和企业号的区别(运营和开发两个角度)。建议有时间得猿友还是阅读一下为好。

上面的文章内容虽然有点多而且繁琐,看完之后不敢说已经入门,但是初步了解,自己写实例是没有问题的。不积跬步无以至千里,希望猿友们耐心继续下去!!!!!!

上面的文章内容虽然有点多而且繁琐,看完之后不敢说已经入门,但是初步了解,自己写实例是没有问题的。不积跬步无以至千里,希望猿友们耐心继续下去!!!!!!

上面的文章内容虽然有点多而且繁琐,看完之后不敢说已经入门,但是初步了解,自己写实例是没有问题的。不积跬步无以至千里,希望猿友们耐心继续下去!!!!!!

期间可能会遇到一些坑,欢迎与博主评论交流

有了上面的基础,接下来博主将分享一个具体的微信开发实例,获取用户当前的地理位置。

一、结果演示

这里写图片描述 这里写图片描述
这里写图片描述 这里写图片描述

二、代码及代码讲解

本工程使用的环境是eclipse + maven + springmvc,下面附上关键代码,springmvc和web.xml相关配置和maven相关依赖就不一一列举,最后会附上工程供大家下载。

2.1、获取签名工具类(httpclient和sha1加密)

package com.luo.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import net.sf.json.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

public class HttpXmlClient {

    public static String post(String url, Map<String, String> params) {
        DefaultHttpClient httpclient = new DefaultHttpClient();
        String body = null;
        HttpPost post = postForm(url, params);
        body = invoke(httpclient, post);
        httpclient.getConnectionManager().shutdown();
        return body;
    }

    public static String get(String url) {
        DefaultHttpClient httpclient = new DefaultHttpClient();
        String body = null;
        HttpGet get = new HttpGet(url);
        body = invoke(httpclient, get);
        httpclient.getConnectionManager().shutdown();
        return body;
    }

    private static String invoke(DefaultHttpClient httpclient,
            HttpUriRequest httpost) {
        HttpResponse response = sendRequest(httpclient, httpost);
        String body = paseResponse(response);
        return body;
    }

    private static String paseResponse(HttpResponse response) {
        HttpEntity entity = response.getEntity();
        String charset = EntityUtils.getContentCharSet(entity);
        String body = null;
        try {
            body = EntityUtils.toString(entity);
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return body;
    }

    private static HttpResponse sendRequest(DefaultHttpClient httpclient,
            HttpUriRequest httpost) {
        HttpResponse response = null;
        try {
            response = httpclient.execute(httpost);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response;
    }

    private static HttpPost postForm(String url, Map<String, String> params) {

        HttpPost httpost = new HttpPost(url);
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();

        Set<String> keySet = params.keySet();
        for (String key : keySet) {
            nvps.add(new BasicNameValuePair(key, params.get(key)));
        }

        try {
            httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return httpost;
    }

    public static void main(String[] args) {

        //获取access_token
        Map<String, String> params = new HashMap<String, String>();
        params.put("corpid","wx5f24fa0db1819ea2");
        params.put("corpsecret","uQtWzF0bQtl2KRHX0amekjpq8L0aO96LSpSNfctOBLRbuYPO4DUBhMn0_v2jHS-9");
        String xml = HttpXmlClient.post("https://qyapi.weixin.qq.com/cgi-bin/gettoken",params);
        JSONObject jsonMap  = JSONObject.fromObject(xml);
        Map<String, String> map = new HashMap<String, String>();
        Iterator<String> it = jsonMap.keys();  
        while(it.hasNext()) {  
            String key = (String) it.next();  
            String u = jsonMap.get(key).toString();
            map.put(key, u);  
        }
        String access_token = map.get("access_token");
        System.out.println("access_token=" + access_token);

        //获取ticket
        params.put("access_token",access_token);
        xml = HttpXmlClient.post("https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket",params); 
        jsonMap  = JSONObject.fromObject(xml);
        map = new HashMap<String, String>();
        it = jsonMap.keys();  
        while(it.hasNext()) {  
            String key = (String) it.next();  
            String u = jsonMap.get(key).toString();
            map.put(key, u);  
        }
        String jsapi_ticket = map.get("ticket");
        System.out.println("jsapi_ticket=" + jsapi_ticket);

        //获取签名signature
        String noncestr = UUID.randomUUID().toString();
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        String url="http://mp.weixin.qq.com";
        String str = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + noncestr +
                "&timestamp=" + timestamp +
                "&url=" + url;
        //sha1加密
        String signature = SHA1(str);
        System.out.println("noncestr=" + noncestr);
        System.out.println("timestamp=" + timestamp);
        System.out.println("signature=" + signature);
        //最终获得调用微信js接口验证需要的三个参数noncestr、timestamp、signature
    }

       /** 
     * @author:罗国辉 
     * @date: 2015年12月17日 上午9:24:43 
     * @description: SHA、SHA1加密
     * @parameter:   str:待加密字符串
     * @return:  加密串
    **/
    public static String SHA1(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;
    }
}

2.2、controller代码(尽可能仔细阅读下面的每一行代码,特别是url部分)

package com.luo.controller;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.luo.util.HttpXmlClient;

@Controller  
public class UserController {  

    @RequestMapping("/")    
    public ModelAndView getIndex(HttpServletRequest request){  

        ModelAndView mav = new ModelAndView("index");  
        //获取access_token
        Map<String, String> params = new HashMap<String, String>();
        params.put("corpid","wx7099477f2de8aded");
        params.put("corpsecret","4clWzENvHVmpcyuA4toys0URkfYanIqWtxZ5plbisn6Cd5AVTF0thpaK6UAhjIvN");
        String xml = HttpXmlClient.post("https://qyapi.weixin.qq.com/cgi-bin/gettoken",params);
        JSONObject jsonMap  = JSONObject.fromObject(xml);
        Map<String, String> map = new HashMap<String, String>();
        Iterator<String> it = jsonMap.keys();  
        while(it.hasNext()) {  
            String key = (String) it.next();  
            String u = jsonMap.get(key).toString();
            map.put(key, u);  
        }
        String access_token = map.get("access_token");

        //获取ticket
        params.put("access_token",access_token);
        xml = HttpXmlClient.post("https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket",params); 
        jsonMap  = JSONObject.fromObject(xml);
        map = new HashMap<String, String>();
        it = jsonMap.keys();  
        while(it.hasNext()) {  
            String key = (String) it.next();  
            String u = jsonMap.get(key).toString();
            map.put(key, u);  
        }
        String jsapi_ticket = map.get("ticket");


        //获取签名signature
        String noncestr = UUID.randomUUID().toString();
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        //获取请求url
        String path = request.getContextPath();
        //以为我配置的菜单是http://yo.bbdfun.com/first_maven_project/,最后是有"/"的,所以url也加上了"/"
        String url = request.getScheme() + "://" + request.getServerName() +  path + "/";  
        String str = "jsapi_ticket=" + jsapi_ticket +
                "&noncestr=" + noncestr +
                "&timestamp=" + timestamp +
                "&url=" + url;
        //sha1加密
        String signature = HttpXmlClient.SHA1(str);
        mav.addObject("signature", signature);   
        mav.addObject("timestamp", timestamp);   
        mav.addObject("noncestr", noncestr);   
        mav.addObject("appId", "wx7099477f2de8aded"); 
        System.out.println("jsapi_ticket=" + jsapi_ticket);
        System.out.println("noncestr=" + noncestr);
        System.out.println("timestamp=" + timestamp);
        System.out.println("url=" + url);
        System.out.println("str=" + str);
        System.out.println("signature=" + signature);
        return mav;    

    }    
}  

2.3、前端js代码(尽可能仔细阅读下面的每一行代码)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script>
    wx.config({
        debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
        appId: '${appId}', // 必填,企业号的唯一标识,此处填写企业号corpid
        timestamp: parseInt("${timestamp}",10), // 必填,生成签名的时间戳
        nonceStr: '${noncestr}', // 必填,生成签名的随机串
        signature: '${signature}',// 必填,签名,见附录1
        jsApiList: ['getLocation'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
    });
    wx.ready(function(){
    });

    wx.error(function(res){
    });
</script>
</head>
<body>
<button id="getBBS" style="width:1000px;height:600px;font-size:150px;" onclick="submitOrderInfoClick();">获取地理位置</button>
</body>
<script type="text/javascript">
function submitOrderInfoClick(){
  wx.getLocation({
        success: function (res) {
            alert("小宝鸽获取地理位置成功,经纬度为:(" + res.latitude + "," + res.longitude + ")" );
        },
        fail: function(error) {
            AlertUtil.error("获取地理位置失败,请确保开启GPS且允许微信获取您的地理位置!");
        }
    });
}
</script>
</html>

三、源码下载

http://download.csdn.net/detail/u013142781/9400470

加上这篇文章,博主微信相关文章就有5篇,将会点亮博主微信开发博客专栏(左侧可看到),欢迎订阅。

欢迎相互关注交流,博主会不断将工作上遇到的技术点写成博客分享给大家。

2017-07-27 12:00:01 qq_17635843 阅读数 14963
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27810 人正在学习 去看看 秦子恒

 

调用微信地理位置接口,需要用到微信的JSSDK,这是微信的介绍:

 

微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。

通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。

JSSDK使用步骤:

 

步骤一:绑定域名

先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

备注:登录后可在“开发者中心”查看对应的接口权限。

步骤二:引入JS文件

在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js

备注:支持使用 AMD/CMD 标准模块加载方法加载

步骤三:通过config接口注入权限验证配置

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。

wx.config({

    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。

    appId: '', // 必填,公众号的唯一标识

    timestamp: , // 必填,生成签名的时间戳

    nonceStr: '', // 必填,生成签名的随机串

    signature: '',// 必填,签名,见附录1

    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2

});

步骤四:通过ready接口处理成功验证

wx.ready(function(){

    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。

});

步骤五:通过error接口处理失败验证

wx.error(function(res){

    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。

});

微信文档大概意思是,如果想调微信JSSDK,然后必须引入http://res.wx.qq.com/open/js/jweixin-1.2.0.js,而这个js需要配置成功才能够使用,成功就自动走ready方失败则error。

这里调用地图接口,是wx.openLocation和wx.getLocation,对wx.config进行配置,  jsApiList: []中填这两个接口,其中签名需要在后台进行。

下面介绍如何配置config,一定要注意参数名的大小写,不能错!:

1、appId就不用说了,就是公众号的appId,timestamp是时间戳,生成签名用,这里单位是秒。

 

	    /**
	     * 获取当前时间戳,单位秒
	     * @return
	     */
	    public static long getCurrentTimestamp() {
	        return System.currentTimeMillis()/1000;
	    }

	    /**
	     * 获取当前时间戳,单位毫秒
	     * @return
	     */
	    public static long getCurrentTimestampMs() {
	        return System.currentTimeMillis();
	    }

2、nonceStr,生成签名的随机字符串

 

 

 /**
	     * 获取随机字符串 Nonce Str
	     *
	     * @return String 随机字符串
	     */
	    public static String generateNonceStr() {
	        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
	    }


3、signature,按照微信的签名算法,签名需要的参数noncestr-随机串,jsapi_ticket-临时票据,timestamp-时间戳,url-调用js接口的页面地址,绝对路径,形成签名的方法,分为二步

 

(1)获取access_token,这个access_token有一个过时的问题,有效时间7200秒,而获取access_token每天限制为100000次,所以,我是把access_token存到数据库里,每次用的时候查询一下上次更新的时间是否有超过7200秒,这个时间可以设置的小一些,用来避免临界7200秒的问题,如果超过7200秒再重新请求一次,再更新数据库存入更新的时间。获取到access_token后,再用access_token获取临时票据ticket,就是上面的jsapi_ticket。

 

public static Map<String,String> getTicket() throws ClientProtocolException, IOException{
		Map<String,String> map = new HashMap<String,String>();
		String turl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ConfigUtil.APPID
				+"&secret="+ConfigUtil.APP_SECRECT;
		JSONObject jsonObject = AuthUtil.doGetJson(turl);
		String access_token = jsonObject.optString("access_token");
	    String expires_in = String.valueOf(jsonObject.optInt("expires_in"));
		String turl2 = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+access_token
				+"&type=jsapi";
		JSONObject jsonObject1 = AuthUtil.doGetJson(turl2);
		String ticket = jsonObject1.optString("ticket");
		map.put("expires_in", expires_in);
		map.put("access_token", access_token);
		map.put("ticket", ticket);
		return map;
	}
public static JSONObject doGetJson(String url) throws ClientProtocolException, IOException{
		JSONObject jsonObject = null;
		DefaultHttpClient client =  new DefaultHttpClient();
		HttpGet get = new HttpGet(url);
		HttpResponse response = client.execute(get);
		HttpEntity entity = response.getEntity();
		if(entity!=null){
			String result = EntityUtils.toString(entity, "UTF-8");
			jsonObject = JSONObject.fromObject(result);
		}
		get.releaseConnection();
		return jsonObject;
	}

 

(2)四个参数形成签名,把四个参数用key=value形成四个字符串,然后对其字典序排序,按照顺序用‘&’连接起来,形成一个字符串对其sha1加密,形成签名signature。

 

public static String getSign(String timestamp,String noncestr,String jsapi_ticket,String url){
		
		
		String arr[] =new String[] {"jsapi_ticket="+jsapi_ticket,"noncestr="+noncestr,"timestamp="+timestamp,"url="+url};
		Arrays.sort(arr);//字典序排序
    	String str = "";
		str = arr[0]+"&"+arr[1]+"&"+arr[2]+"&"+arr[3];
	    System.out.println(str);
		String mParms = null;//sha1加密
	    MessageDigest digest = null;
	    try {
	      digest = java.security.MessageDigest.getInstance("SHA");
	    } catch (NoSuchAlgorithmException e) {
	      // TODO Auto-generated catch block
	      e.printStackTrace();
	    }
	    digest.update(str.getBytes());
	    byte messageDigest[] = digest.digest();
	    // Create Hex String
	    StringBuffer hexString = new StringBuffer();
	    for (int i = 0; i < messageDigest.length; i++) {
	      String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
	      if (shaHex.length() < 2) {
	        hexString.append(0);
	      }
	      hexString.append(shaHex);
	    }
	    mParms = hexString.toString();
	    	return mParms;
	    }
	
	
	public static String byteToStr(byte[] byteArray){
		
		String str = "";
		for(int i=0;i<byteArray.length;i++){
			str += byteToHexStr(byteArray[i]); 		
		}
		return str;
		
		
	}
	 
	
	public static String byteToHexStr(byte mbyte){
		char[] Digit = {'1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F'};
		char[] tempArr = new char[2];
		tempArr[0] = Digit[(mbyte >>> 4) & 0X0F]; 
		tempArr[1] = Digit[mbyte & 0X0F]; 
		 String s = new String(tempArr); 
		 return s; 
		
		
		
	}

 

 

 

最近在整理一些资源工具,放在网站分享 http://tools.maqway.com
欢迎关注公众号:麻雀唯伊 , 不定时更新资源文章,或许有你想看的

 

2017-08-22 01:52:25 phil_jing 阅读数 11898
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27810 人正在学习 去看看 秦子恒

本部分需要用到微信的JS-SDK,微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。

通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。

官方文档

一、JS-SDK引入

1.先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”,和网页授权一样只是个域名。

2.在需要调用JS接口的页面引入如下JS文件之一

<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<script src="https://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>

二、通过config接口注入权限验证配置

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名
    jsApiList: [] // 必填,需要使用的JS接口列表
});

 

首先生成这个signature之前需要获取到一个临时票据jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,同样也需要个中控服务器控制刷新。

1、获取临时票据

封装返回结果
package com.phil.wechatauth.model.resp;

import com.phil.common.result.ResultState;

/**
 * jsapi_ticket是公众号用于调用微信JS接口的临时票据
 * @author phil
 * @date  2017年8月21日
 *
 */
public class JsapiTicket extends ResultState {

	/**
	 * 
	 */
	private static final long serialVersionUID = -357009110782376503L;
	
	private String ticket; //jsapi_ticket
	
	private String expires_in;

	public String getTicket() {
		return ticket;
	}

	public void setTicket(String ticket) {
		this.ticket = ticket;
	}

	public String getExpires_in() {
		return expires_in;
	}

	public void setExpires_in(String expires_in) {
		this.expires_in = expires_in;
	}
}
获取方法
	/**
	 * 获取jsapi_ticket 调用微信JS接口的临时票据
	 * @return
	 */
	public String getTicket(String accessToken) {
		JsapiTicket jsapiTicket = null;
		Map<String,String> params = new TreeMap<String,String>();
		params.put("access_token",accessToken);
		params.put("type", "jsapi");
		String result = HttpReqUtil.HttpDefaultExecute(HttpReqUtil.GET_METHOD, WechatConfig.GET_TICKET_URL, params,"");
		if(StringUtils.isNotBlank(result)){
			jsapiTicket = JsonUtil.fromJson(result, JsapiTicket.class);
		}
		if(jsapiTicket.getErrcode()==0){
			return jsapiTicket.getTicket();
		}
		return null;
	}

2、生成签名并返回参数

signature生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。

string1示例如下

jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value

这里有个坑,页面是nonceStr,但是签名的字段是noncestr,注意大小写

简单封装下JS-SDK config配置信息

package com.phil.wechatauth.model.resp;

/**
 * JS-SDK的页面配置信息
 * @author phil
 * @date 2017年8月22日
 *
 */
public class JsWechatConfig {

	private String appId;

	private long timestamp;

	private String noncestr;

	private String signature;

	public String getAppId() {
		return appId;
	}

	public void setAppId(String appId) {
		this.appId = appId;
	}

	public long getTimestamp() {
		return timestamp;
	}

	public void setTimestamp(long timestamp) {
		this.timestamp = timestamp;
	}

	public String getNoncestr() {
		return noncestr;
	}

	public void setNoncestr(String noncestr) {
		this.noncestr = noncestr;
	}

	public String getSignature() {
		return signature;
	}

	public void setSignature(String signature) {
		this.signature = signature;
	}
}

添加配置信息到页面

/**
 * 
 */
package com.phil.wechatauth.controller;

import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.phil.common.config.SystemConfig;
import com.phil.common.config.WechatConfig;
import com.phil.common.util.DateTimeUtil;
import com.phil.common.util.PayUtil;
import com.phil.common.util.SignatureUtil;
import com.phil.wechatauth.model.resp.JsWechatConfig;
import com.phil.wechatauth.service.WechatAuthService;

/**
 * JS-SDK
 * @author phil
 * @date  2017年8月21日
 *
 */
@Controller
@RequestMapping("/auth")
public class WechatAuthController {
	
	@Autowired
	private WechatAuthService wechatAuthService;
	
	/**
	 * 获取地理位置
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@RequestMapping("/getLocation")
	public String getLocation(HttpServletRequest request) throws Exception{
		JsWechatConfig jsWechatConfig = new JsWechatConfig();
		jsWechatConfig.setAppId(WechatConfig.APP_ID);
		jsWechatConfig.setTimestamp(DateTimeUtil.currentTime());
		jsWechatConfig.setNoncestr(PayUtil.createNonceStr());
		SortedMap<Object,Object> map = new TreeMap<Object,Object>();
		map.put("jsapi_ticket", wechatAuthService.getTicket(wechatAuthService.findlastestToken()));
		map.put("noncestr", jsWechatConfig.getNoncestr());
		map.put("timestamp", jsWechatConfig.getTimestamp());
		map.put("url", request.getRequestURL().toString());
		String signature = SignatureUtil.createSha1Sign(map, null, SystemConfig.CHARACTER_ENCODING);
		jsWechatConfig.setSignature(signature);
		request.setAttribute("jsWechatConfig", jsWechatConfig);
		return "wechatauth/getLocation";
	}
}

签名方法

	/**
	 * 通过Map<SortedMap,Object>中的所有元素参与签名
	 * 
	 * @param map 待参与签名的map集合
	 * @params apikey apikey中 如果为空则不参与签名,如果不为空则参与签名
	 * @return
	 */
	public static String createSha1Sign(SortedMap<Object, Object> map, String apiKey, String characterEncoding) {
		String result = notSignParams(map, apiKey);
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("SHA-1");
			byte[] digest = md.digest(result.getBytes());
			result = byteToStr(digest);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return result;
	}

其他的签名方法

三、通过ready接口处理成功验证

以上执行完成,进入的完整的页面

<%@ 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">
<title>获取地理位置</title>
<!-- 微信 js-sdk -->
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="http://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
</head>
<body>
	<br>
	<div class="container">
		<div class="form-group">
			<label for="firstname" class="col-sm-2 control-label">地址:</label>
			<div class="col-sm-10" id="item-ifo">
				<input type="text" value="" class="form-control"
					name="location.address" id="address" placeholder="正在获取地理位置" tabindex="1" autocomplete="off" />
				<div class="i-name ico" id="i-name"></div>
			</div>
		</div>
	</div>

</body>
<script type="text/javascript">
	wx.config({
	    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
	    appId: '${jsWechatConfig.appId}', // 必填,公众号的唯一标识
	    timestamp: '${jsWechatConfig.timestamp}' , // 必填,生成签名的时间戳
	    nonceStr: '${jsWechatConfig.noncestr}', // 必填,生成签名的随机串
	    signature: '${jsWechatConfig.signature}',// 必填,签名,见附录1
	    jsApiList: [ 'checkJsApi', 'openLocation', 'getLocation'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
	});
	
	wx.checkJsApi({
	    jsApiList: ['getLocation'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
	    success: function(res) {
	    	if (res.checkResult.getLocation == false) {  
                alert('你的微信版本太低,不支持微信JS接口,请升级到最新的微信版本!');  
                return;  
         }
	    }
	});
	var latitude;  
    var longitude;  
    var speed;  
    var accuracy; 
	wx.ready(function(){
	    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
		wx.getLocation({  
            success : function(res) {  
                latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90  
                longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。  
                speed = res.speed; // 速度,以米/每秒计  
                accuracy = res.accuracy; // 位置精度  
                alert(latitude);  
                alert(accuracy);
            },  
            cancel : function(res) {  
                alert('未能获取地理位置');  
            }
        });  
	});
	
	wx.error(function(res){
	    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
		alert("验证出错");  
	});
</script>
</html>

可以通过微信官方提供的微信web开发者工具调试

扫一扫加群

 

2017-06-08 09:24:09 bj123467 阅读数 15407
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27810 人正在学习 去看看 秦子恒

思路分析:

   1、在微信公众号内获取用户地理位置

    需要js-sdk签名包(关于如何获取文档有介绍)

   2、根据获取的地理位置ajax去后台请求,通过sql语句,查询中距离最近的门店(sql语句在网上搜的,位置是通过后台添加的)

   3、根据城市查询门店列表,使用通过表单提交事件,ajax请求后台获取列表

  4、百度地图导航页面要注意引入地址

一、开始开发

       1、该功能的实现需要调用微信公众号的js-sdk接口实现

             简介:

           微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。

          通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信           分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。

       2、调用微信js-sdk的步骤:官方的网址:https://mp.weixin.qq.com/wiki

               步骤一:绑定域名

         先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。

         步骤二:引入JS文件

         在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js

         备注:支持使用 AMD/CMD 标准模块加载方法加载

         步骤三:通过config接口注入权限验证配置

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)

具体的使用可以查看官方的文档

wx.config({

    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。

    appId: '', // 必填,公众号的唯一标识

    timestamp: , // 必填,生成签名的时间戳

    nonceStr: '', // 必填,生成签名的随机串

    signature: '',// 必填,签名,见附录1

    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2

});

步骤四:通过ready接口处理成功验证

wx.ready(function(){

    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。

});

步骤五:通过error接口处理失败验证

wx.error(function(res){

    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。

})


自己的程序代码附上(我做的是获取用户的地理位置,就是出现一个获取地理位置的弹窗):

html页面:

//引入微信js文件

<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<script type="text/javascript">
//配置信息验证接口
wx.config({
   debug: false,
   appId: '<?php echo $signPackage["appId"];?>',
   timestamp: '<?php echo $signPackage["timestamp"];?>',
   nonceStr: '<?php echo $signPackage["nonceStr"];?>',
   signature: '<?php echo $signPackage["signature"];?>',
   jsApiList: [
       // 所有要调用的 API 都要加到这个列表中
       'checkJsApi',
       'openLocation',
       'getLocation'
     ]
           });
//验证之后进入该函数,所有需要加载页面时调用的接口都必须写在该里面
wx.ready(function () {
//基础接口判断当前客户端版本是否支持指定JS接口
wx.checkJsApi({
   jsApiList: [
       'getLocation'
   ],
   success: function (res) {
       // alert(JSON.stringify(res));
       // alert(JSON.stringify(res.checkResult.getLocation));
       if (res.checkResult.getLocation == false) {
           alert('你的微信版本太低,不支持微信JS接口,请升级到最新的微信版本!');
           return;
       }
   }
});
                 //微信获取地理位置并拉取用户列表(用户允许获取用户的经纬度)
wx.getLocation({
   success: function (res) {
       var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90
       var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。

               //去数据库查询获取附近的门店
                        $.ajax({
                        type: 'post',
                        url: '__CONTROLLER__/shopList',
                        dataType: 'json',
                        data: {"latitude": latitude,"longitude":longitude},
                        success:function(shopInfo){
                        //index是下表,el是值
                               $(shopInfo).each(function(index,el){
                                    $("#list").append('<div class="item-store"> <a class="s-top ui-width-100 ui-flex" href="__CONTROLLER__/shopDetail/shop_id/'+el.shop_id+'"> <img src="'+el.shop_logo.substring(1)+'" class="s-img"/> <div class="s-message"> <h4>'+el.shop_name+'</h4> <div class="s-address">'+el.shop_position+'</div> </div> </a> <div class="s-bottom-block ui-width-100"> <ul>  <li> <a href="__CONTROLLER__/daohang/shop_id/'+el.shop_id+'" class="db-block"> <i class="icon iconfont">&#xe66c;</i> 一键导航 <span class="kilemiter"> '+el.distance/1000+'km </span> </a> </li> </ul> </div> </div>');
                               })                        
                          }
                        });
   },
   cancel: function (res) {
    $(".city").triggerHandler("focus");
   }
                });
            });
</script>

控制器中获取门店通过sql语句获取距离一定距离的门店的列表:

if(IS_AJAX){
    $post = I('post.');
    //纬度小,经度大
    // 5公里范围是5000
    $longitude = $post['longitude'];//经度信息
    $latitude = $post['latitude'];//纬度信息

               //通过sql语句查询距离5公里之内的门店
    $sql = "select * from (select shop_id,shop_name,shop_tel,shop_position,shop_logo,  ROUND(6378.138*2*ASIN(SQRT(POW(SIN(($latitude*PI()/180-`shop_wei`*PI()/180)/2),2)+COS($latitude*PI()/180)*COS(`shop_wei`*PI()/180)*POW(SIN(($longitude*PI()/180-`shop_jing`*PI()/180)/2),2)))*1000) AS distance from sp_shop order by distance ) as a where a.distance<=5000";
    // $sql = "select * from (select shop_id,shop_name,shop_tel,shop_position,shop_logo, ROUND(6378.138*2*ASIN(SQRT(POW(SIN((36.09297*PI()/180-`shop_wei`*PI()/180)/2),2)+COS(36.09297*PI()/180)*COS(`shop_wei`*PI()/180)*POW(SIN((120.3743*PI()/180-`shop_jing`*PI()/180)/2),2)))*1000) AS distance from sp_shop order by distance ) as a where a.distance<=5000";
    $shopInfo = M()->query($sql);
    echo json_encode($shopInfo);exit;
    }else{
            if(session('openid')){
                //获取微信签名包信息(用户地理位置的获取)填写的配置信息中,需要写入的东西(调用签名包封装的类:http://blog.csdn.net/bj123467/article/details/72910160)
                $jssdk = new \Home\Model\WechatModel();
                $signPackage = $jssdk->GetSignPackage();
                $this->assign('signPackage', $signPackage);
            $this->display();
            }else{
                //判断该用户是否存在
                 $model = new \Home\Model\WechatModel();
                 $openid_accesstoken = $model->openId();
                 $rst = M('user')->where(array('user_openid' => $openid_accesstoken['openid']))->find();
                 if($rst){
                    session('openid',$openid_accesstoken['openid']);
                    session('user_id', $rst['user_id']);
                    $jssdk = new \Home\Model\WechatModel();
                    $signPackage = $jssdk->GetSignPackage();
                    $this->assign('signPackage', $signPackage);
                    $this->display();exit;
                }else{
                    //如果不存在获取微信用户的基本信息
                    $userInfo = $model->getOpenId($openid_accesstoken['openid'],$openid_accesstoken['access_token']);
                    $data = array(
                        'user_img' => $userInfo['headimgurl'],
                        'user_openid' => $userInfo['openid'],
                        'user_name' => filter($userInfo['nickname']),
                        'user_register_time' => time(),
                        'city' => $userInfo['province'].'-'.$userInfo['city'],
                    );
                    $id = M('user')->add($data);
                    session('openid', $userInfo['openid']);
                    session('user_id',$id);
                    $jssdk = new \Home\Model\WechatModel();
                    $signPackage = $jssdk->GetSignPackage();
                    $this->assign('signPackage', $signPackage);
                    $this->display();
                }
            }
    }

2018-07-17 09:36:41 qq_41620704 阅读数 1335
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27810 人正在学习 去看看 秦子恒

小程序需要获取城市名,通过wx.getLocation()获取经纬度,调用腾讯地图qqmapsdk.reverseGeocoder()获取城市名称,在开发者工具上能成功,但在真机上报错:fail url not in domin list ,找到原因是

实际上是

所以最后解决办法是设置合法域名,这样就ok了

没有更多推荐了,返回首页