微信jsapi 调用分享接口(完整版)

1.测试环境

申请测试账号

地址: https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

填写内容:

    ①:接口配置信息

        url:配置http://+域名或者http://+外网ip也可以

        token:自定义(任意)

        js安全域名(要和url的中的域名)

  提交配置信息时微信会先进行验证所以你需要在能访问的url对应的服务上面进行验证代码如下:  能够打印出System.out.println("echostr:"+echostr);的值验证成功.

微信会通过你配置的url+代码中(/) 在你提交接口配置信息时,微信服务会请求到前面叙述的那个路径,来验证成功即能打印出echostr值(关键的一步,如果验证不通过,后续开发没办法进行)

/**
* 微信消息接收和token验证
*
* @param reqDate
* @param request
* @param response
* @throws IOException
value的值你可以自定义,但是要保证和url的一致性
*/
@RequestMapping(value = {"/"}, method = {RequestMethod.POST, RequestMethod.GET})
public void get(@RequestBody(required = false) String reqDate, HttpServletRequest request,
                HttpServletResponse response) throws Exception {
    boolean isGet = request.getMethod().toLowerCase().equals("get");
    PrintWriter print;
    if (isGet) {
        // 微信加密签名
        String signature = request.getParameter("signature");
        // 时间戳
        String timestamp = request.getParameter("timestamp");
        // 随机数
        String nonce = request.getParameter("nonce");
        // 随机字符串
        String echostr = request.getParameter("echostr");
        // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
        if (signature != null && CheckoutUtil.checkSignature(signature, timestamp, nonce)) {
            try {
                print = response.getWriter();
                print.write(echostr);
                print.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("echostr:"+echostr);
    }
}
public class CheckoutUtil {
    private static String token = "weixin"; //与在后台配置的Token一样
    /**
     * 验证签名
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] arr = new String[] { token, timestamp, nonce };
        // 将token、timestamp、nonce三个参数进行字典序排序
        // Arrays.sort(arr);
        sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;
        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        content = null;
        // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }
    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }


    /**
     * 将字节转换为十六进制字符串
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '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;
    }
    public static void sort(String a[]) {
        for (int i = 0; i < a.length - 1; i++) {
            for (int j = i + 1; j < a.length; j++) {
                if (a[j].compareTo(a[i]) < 0) {
                    String temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                }
            }
        }
    }
}

 

②:JS接口安全域名(注意:是域名不是url不要携带 http://,直接填写域名否侧报错:invalid url domain)

2.关注测试号二维码(不重要)

url/token/js域名配置都成功之后就可以开始开发了

 

3.前端页面代码如下:

$.ajax({
    type: "POST",
    url: 'http://www.innshine.com/wechat/token',
    // contentType: "application/json; charset=utf-8",
    dataType: "JSON",
    data:{"url":location.href.split('#')[0]},//url一定要是当前的页面的路径而且出去#后面的(微信规定),后台加需要url
    success: function (res) {
        console.log('res', res)
        wx.config({
            debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: 'wxae743829eed54eaa', // 必填,公众号的唯一标识
            timestamp: res.timestamp, // 必填,生成签名的时间戳
            nonceStr: res.noncestr, // 必填,生成签名的随机串
            signature: res.signature,// 必填,签名
            jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'] // 必填,需要使用的JS接口列表
        });

        wx.ready(function () {   //需在用户可能点击分享按钮前就先调用
            wx.updateAppMessageShareData({
                title: 'test', // 分享标题
                desc: 'test列表', // 分享描述
                link: 'http://www.innshine.com/wechat/index.html', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                imgUrl: 'http://www.innshine.com/wechat/images/down.jpg', // 分享图标
            }, function (res) {
                console.info("success")
            });
            

            wx.updateTimelineShareData({
                title: 'test', // 分享标题
                link: 'http://www.innshine.com/wechat/index.html', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                imgUrl: 'http://www.innshine.com/wechat/images/down.jpg', // 分享图标
            }, function (res) {
                console.info("success")
            });
           



        });
        wx.error(function (res) {
            //打印错误消息。及把 debug:false,设置为debug:ture就可以直接在网页上看到弹出的错误提示
            alert("错误error" + JSON.stringify(res));
        });
    }
})

4.后端代码:

controller

@Autowired
WxJsApiServer wxJsApiServer;
@Autowired
Properties properties;


@RequestMapping("token")
public  Map<String, String> getJsapiTicket(String url)throws DigestException {
     String token = wxJsApiServer.getAccessTokenByAppIdAndSecret(properties.getAPPID(),properties.getAPPSECRET());
     String ticket = wxJsApiServer.getJsApiTicketByToken(token);
     return  getSign(url,ticket);
}


//url:去掉不包含#之后的路径
public  Map<String, String> getSign(String url,String ticket ) throws DigestException {
//注意哥哥蚕食都是小写的不要有大写(微信加密参数规则要求)
   HashMap<String,String> map = new HashMap<String,String>();
   map.put("jsapi_ticket",ticket);
   map.put("noncestr",SHA1.generateNonceStr());
   map.put("timestamp",String.valueOf(SHA1.getCurrentTimestamp()));//注意:一定要重视这一点参加加密的时间戳是秒级的值 不要使用毫秒值
   map.put("url",url);
   //生成signature
   String signature=SHA1.getSha1Encode(map);
   map.put("signature",signature);
   logger.info("signature:{}",signature);
   return map;
}

properties:参数实体类

@Component
@Data
public class Properties {
/**
* 获取token接口
*/
@Value("${wx.token}")
private String GetPageAccessTokenUrl;
/**
* 获取ticket接口
*/
@Value("${wx.ticket}")
private String GetJsapiTicketUrl;
/**
* 公众号标识
*/
@Value("${wx.appid}")
private String APPID;
/**
* 公众号验证所需参数(必须)
*/
@Value("${wx.secret}")
private String APPSECRET;
}

server

@Autowired
Properties properties;
@Override
public String getAccessTokenByAppIdAndSecret(String APPID, String SECRET) {
   String wxUrl = properties.getGetPageAccessTokenUrl().replace("APPID", properties.getAPPID()).replace("SECRET", properties.getAPPSECRET());
    HttpClient client = null;
    String accessToken = null;
    try {
        client = new DefaultHttpClient();
        HttpGet httpget = new HttpGet(wxUrl);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        String response = client.execute(httpget, responseHandler);
        JSONObject OpenidJSONO = JSONObject.parseObject(response);
        if (OpenidJSONO.get("access_token")==null){
            return "FALSE";
        }
        accessToken = String.valueOf(OpenidJSONO.get("access_token"));
        //缓存
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //关闭连接
        client.getConnectionManager().shutdown();
    }
    return accessToken;
}
@Override
public String getJsApiTicketByToken(String accessToken) {
    String requestUrl = properties.getGetJsapiTicketUrl().replace("ACCESS_TOKEN", accessToken);
    HttpClient client = null;
    String ticket = null;
    try {
        client = new DefaultHttpClient();
        HttpGet httpget = new HttpGet(requestUrl);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        String response = client.execute(httpget, responseHandler);
        JSONObject OpenidJSONO = JSONObject.parseObject(response);
        if (OpenidJSONO.get("ticket") == null) {
            return "FALSE";
        }
        ticket = String.valueOf(OpenidJSONO.get("ticket"));
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        client.getConnectionManager().shutdown();
    }
    return ticket;
}

sha1加密

public class    SHA1 {
    private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final Random RANDOM = new SecureRandom();
    /**
     * Takes the raw bytes from the digest and formats them correct.
     *
     * @param bytes the raw bytes from the digest.
     * @return the formatted bytes.
     */
    private static String getFormattedText(byte[] bytes) {
        int len = bytes.length;
        StringBuilder buf = new StringBuilder(len * 2);
        // 把密文转换成十六进制的字符串形式
        for (int j = 0; j < len; j++) {
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
        }
        return buf.toString();
//            Formatter formatter = new Formatter();
//            for (byte b : bytes)
//            {
//                formatter.format("%02x", b);
//            }
//            String result = formatter.toString();
//            formatter.close();
//            return result;
    }
    public static String encode(String str) {
        if (str == null) {
            return null;
        }
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
            messageDigest.update(str.getBytes("UTF-8"));
            byte[]  bytes= messageDigest.digest();
            int len = bytes.length;
            StringBuilder buf = new StringBuilder(len * 2);
            // 把密文转换成十六进制的字符串形式
            for (int j = 0; j < len; j++) {
                buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0xf]);
                buf.append(HEX_DIGITS[bytes[j] & 0xf]);
            }
            return buf.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static String getSha1(String str){
        if(str == null || str.length()==0){
            return null;
        }
        char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
            mdTemp.update(str.getBytes("UTF-8"));
            byte[] md = mdTemp.digest();
            int j = md.length;
            char buf[] = new char[j*2];
            int k = 0;
            for(int i=0;i<j;i++){
                byte byte0 = md[i];
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf);
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * 获取随机字符串 Nonce Str
     *
     * @return String 随机字符串
     */
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }
    /**
     * 获取当前时间戳,单位秒
     * @return
     */
    public static long getCurrentTimestamp() {
        return System.currentTimeMillis()/1000;
    }
    /**
     * 获取当前时间戳,单位毫秒
     * @return
     */
    public static long getCurrentTimestampMs() {
        return System.currentTimeMillis();
    }
    /**
     * SHA1 安全加密算法
     *
     * @return
     * @throws DigestException
     */
    public static String getSha1Encode(Map<String, String> map)  {
        String encode = encode(getOrderByLexicographic(map));
        return encode;
    }




    public static String getOrderByLexicographic(Map<String, String> map) {
        return splitParams(lexicographicOrder(getParamsName(map)), map);
    }
    /**
     * 拼接参数
     *
     * @param paramNames
     * @param maps
     * @return
     */
    public static String splitParams(List<String> paramNames, Map<String, String> maps) {
        StringBuilder params = new StringBuilder();
        for (String paramName : paramNames) {
            params.append(paramName);
            for (Map.Entry<String, String> entry : maps.entrySet()) {
                if (paramName.equals(entry.getKey())) {
                    params.append("=" + String.valueOf(entry.getValue()) + "&");
                }
            }
        }
        params.deleteCharAt(params.length() - 1);
        return params.toString();
    }
    /**
     * 参数按字典顺序排序
     *
     * @param paramNames 参数集合
     * @return 返回排序集合
     */
    public static List<String> lexicographicOrder(List<String> paramNames) {
        Collections.sort(paramNames);
        return paramNames;
    }
    /**
     * 获取参数名称 key
     *
     * @param maps
     * @return
     */
    public static List<String> getParamsName(Map<String, String> maps) {
        List<String> paramNames = new ArrayList<String>();
        for (Map.Entry<String, String> entry : maps.entrySet()) {
            paramNames.add(entry.getKey());
        }
        return paramNames;
    }

httputile:

public class HttpUtils {
    /**
     * get请求,参数拼接在地址上
     * @param url 请求地址加参数
     * @return 响应
     */
    public static String get(String url,String AccessToken)
    {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        url = url.replaceAll(" ","%20");
        HttpGet get = new HttpGet(url);
        if(AccessToken != null && !AccessToken.equals("")){
            get.addHeader("Authorization",AccessToken);
        }
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(get);
            if(response != null && response.getStatusLine().getStatusCode() == 200)
            {
                HttpEntity entity = response.getEntity();
                result = entityToString(entity);
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
                if(response != null)
                {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * get请求,参数放在map里
     * @param url 请求地址
     * @param map 参数map
     * @return 响应
     */
    public static String getMap(String url,String AccessToken,Map<String,String> map)
    {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        List<NameValuePair> pairs = new ArrayList<NameValuePair>();
        for(Map.Entry<String,String> entry : map.entrySet())
        {
            pairs.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
        }
        CloseableHttpResponse response = null;
        try {
            URIBuilder builder = new URIBuilder(url);
            builder.setParameters(pairs);
            HttpGet get = new HttpGet(builder.build());
            if(AccessToken != null && !AccessToken.equals("")){
                get.addHeader("Authorization",AccessToken);
            }
            response = httpClient.execute(get);
            if(response != null && response.getStatusLine().getStatusCode() == 200)
            {
                HttpEntity entity = response.getEntity();
                result = entityToString(entity);
            }
            return result;
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
                if(response != null)
                {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * 发送post请求,参数用map接收
     * @param url 地址
     * @param map 参数
     * @return 返回值
     */
    public static  String postMap(String url,Map<String,String> map) {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost post = new HttpPost(url);
        post.addHeader("Content-Type", "application/json");
        List<NameValuePair> pairs = new ArrayList<NameValuePair>();
        if (map != null){
            for(Map.Entry<String,String> entry : map.entrySet())
            {
                pairs.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
            }
        }
        CloseableHttpResponse response = null;
        try {
            post.setEntity(new UrlEncodedFormEntity(pairs,"UTF-8"));
            response = httpClient.execute(post);
            if(response != null && response.getStatusLine().getStatusCode() == 200)
            {
                HttpEntity entity = response.getEntity();
                result = entityToString(entity);
            }
            return result;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
                if(response != null)
                {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * 发送post请求,参数用map<String object>接收
     * @param url
     * @param map
     * @param encoding
     * @return
     */
    public static String mapPost(String url, Map<String,Object> map, String encoding){
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = null;
        String result = null;
        try{
             httpClient = HttpClients.createDefault();
            httpPost = new HttpPost(url);
            //设置参数
            List<NameValuePair> list = new ArrayList<NameValuePair>();
            Iterator iterator = map.entrySet().iterator();
            while(iterator.hasNext()){
            Map.Entry<String,String> elem = (Map.Entry<String, String>) iterator.next();
            list.add(new BasicNameValuePair(elem.getKey(),String.valueOf(elem.getValue())));
            }
            if(list.size() > 0){
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list,encoding);
            httpPost.setEntity(entity);
            }
            HttpResponse response = httpClient.execute(httpPost);
            if(response != null){
            HttpEntity resEntity = response.getEntity();
            if(resEntity != null){
            result = EntityUtils.toString(resEntity,encoding);
            }
            }
            }catch(Exception ex){
            ex.printStackTrace();
            }
            System.out.println(result);
        return result;
    }
    /**
     * post请求,参数为json字符串
     * @param url 请求地址
     * @param jsonString json字符串
     * @return 响应
     */
    public static String postJson(String url,String jsonString,String AccessToken)
    {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost post = new HttpPost(url);
        post.addHeader("Content-Type", "application/json");
        if(AccessToken != null && !AccessToken.equals("")){
            post.addHeader("Authorization",AccessToken);
        }
        CloseableHttpResponse response = null;
        try {
            if(jsonString != null && !jsonString.equals("")){
                post.setEntity(new ByteArrayEntity(jsonString.getBytes("UTF-8")));
            }
            response = httpClient.execute(post);
            if(response != null && response.getStatusLine().getStatusCode() == 200)
            {
                HttpEntity entity = response.getEntity();
                result = entityToString(entity);
            }
            return result;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
                if(response != null)
                {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    private static String entityToString(HttpEntity entity) throws IOException {
        String result = null;
        if(entity != null)
        {
            long lenth = entity.getContentLength();
            if(lenth != -1 && lenth < 2048)
            {
                result = EntityUtils.toString(entity,"UTF-8");
            }else {
                InputStreamReader reader1 = new InputStreamReader(entity.getContent(), "UTF-8");
                CharArrayBuffer buffer = new CharArrayBuffer(2048);
                char[] tmp = new char[1024];
                int l;
                while((l = reader1.read(tmp)) != -1) {
                    buffer.append(tmp, 0, l);
                }
                result = buffer.toString();
            }
        }
        return result;
    }


}

正式环境开发:

        登录公众号平台:

                配置两处:

                    1.导航"基础配置"中配置url/token,配置要求和测试配置一样.

                    2.再在"基础配置"的"ip白名单"添加项目所要部署到的服务器的ip.

                    3.导航"公众号设置"中再点击"功能设置"然后配置"js安全域配置,注意此时需要下载一个文件MP_verify_gt5yNwRcoQWm4SIk.txt,文件可在弹出窗口中的提示出获取,文件下载以后*(springboot项目为例)放在static目录下,然后通过上面配置的url+文件名,页面响应一串字符串即代表成功.

 

正是开发代码和测试代码一样.

 

微信 JS 接口签名校验工具: https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

 

nginx配置

  安装和配置过程可以自己百度:

注意点给大家说一下:nginx.conf文件

server {
       listen       8089;//只是服务器开放的端口并不是项目端口号,但是却要和项目的端口号保持一致.默认是80端口
       server_name  www.innshines.com;//你自己的域名
       location /wxshare {
           # root   html;
           # index  index.html index.htm;
            proxy_pass   http://127.0.0.1:8089;//项目部署所在的服务器的本地ip,端口记得要开放而且要在防火墙的白名单中放行端口
        }
    }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值