JAVA调用微信接口实现页面分享功能(分享到朋友圈显示图片,分享给朋友)

 

钉钉提供的内网穿透之HTTP穿透:https://www.cnblogs.com/pxblog/p/13862376.html

 

网页分享到微信中如何显示标题图,如果自定义标题图,描述,显示效果如下

 

 

 

 

官网接口地址;https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

 

加入maven依赖

    <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>[4.1.12,)</version>
        </dependency>

    <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20171018</version>
        </dependency>

 

 

 

HttpClientUtil.java
package com.test.cms.share;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;



public class HttpClientUtil {

    private static class SingletonHolder{
        private final static  HttpClientUtil INSTANCE=new HttpClientUtil();
    }

    private HttpClientUtil(){}

    public static HttpClientUtil getInstance(){
        return SingletonHolder.INSTANCE;
    }

    public  String get(String url){
        CharsetHandler handler = new CharsetHandler("UTF-8");
        CloseableHttpClient client = null;
        try {
            HttpGet httpget = new HttpGet(new URI(url));
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
            client= httpClientBuilder.build();
            client = (CloseableHttpClient) wrapClient(client);
            return client.execute(httpget, handler);
        } catch (Exception e) {
            //e.printStackTrace();
            return "";
        }finally {
            try {
                if(client!=null){
                    client.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static String post(String url, String params,String contentType)
    {

        //创建HttpClientBuilder
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        //HttpClient
        CloseableHttpClient client = httpClientBuilder.build();
        client = (CloseableHttpClient) wrapClient(client);


        HttpPost post = new HttpPost(url);
        CloseableHttpResponse res = null;
        try
        {
            StringEntity s = new StringEntity(params,"UTF-8");
            if(StringUtils.isBlank(contentType)){
                s.setContentType("application/json");
            }
            s.setContentType(contentType);
            s.setContentEncoding("utf-8");
            post.setEntity(s);
            res = client.execute(post);
            HttpEntity entity = res.getEntity();
            return EntityUtils.toString(entity, "utf-8");
        }
        catch (Exception e)
        {
            e.printStackTrace();
        } finally {
            try {
                res.close();
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return "";
    }

    public static String post(String urlStr,String xmlInfo) {
        String line1 = "";
        try {
            URL url = new URL(urlStr);
            URLConnection con = url.openConnection();
            con.setDoOutput(true);
            //con.setRequestProperty("Pragma:", "no-cache");
            con.setRequestProperty("Cache-Control", "no-cache");
            con.setRequestProperty("Content-Type", "text/xml");

            OutputStreamWriter out = new OutputStreamWriter(con
                    .getOutputStream());
            out.write(new String(xmlInfo.getBytes("utf-8")));
            out.flush();
            out.close();
            BufferedReader br = new BufferedReader(new InputStreamReader(con
                    .getInputStream()));
            String line = "";
            for (line = br.readLine(); line != null; line = br.readLine()) {
                line1+=line;
            }
            return new String(line1.getBytes(),"utf-8");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private class CharsetHandler implements ResponseHandler<String> {
        private String charset;

        public CharsetHandler(String charset) {
            this.charset = charset;
        }

        public String handleResponse(HttpResponse response)
                throws ClientProtocolException, IOException {
            StatusLine statusLine = response.getStatusLine();
            if (statusLine.getStatusCode() >= 300) {
                throw new HttpResponseException(statusLine.getStatusCode(),
                        statusLine.getReasonPhrase());
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                if (!StringUtils.isBlank(charset)) {
                    return EntityUtils.toString(entity, charset);
                } else {
                    return EntityUtils.toString(entity);
                }
            } else {
                return null;
            }
        }
    }

    private static  HttpClient wrapClient(HttpClient base) {
        try {
            SSLContext ctx = SSLContext.getInstance("TLSv1");
            X509TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] xcs,
                                               String string) throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] xcs,
                                               String string) throws CertificateException {
                }

                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(ctx, new String[] { "TLSv1" }, null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            return httpclient;

        } catch (Exception ex) {
            return null;
        }
    }

}

 

RandomStr.java
package com.test.cms.share;

import java.util.Random;

public class RandomStr {

    private static char ch[] = { '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', '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', '0', '1' };//最后又重复两个0和1,因为需要凑足数组长度为64

    private static Random random = new Random();

    //生成指定长度的随机字符串
    public static String createRandomString(int length) {
        if (length > 0) {
            int index = 0;
            char[] temp = new char[length];
            int num = random.nextInt();
            for (int i = 0; i < length % 5; i++) {
                temp[index++] = ch[num & 63];//取后面六位,记得对应的二进制是以补码形式存在的。
                num >>= 6;//63的二进制为:111111
                // 为什么要右移6位?因为数组里面一共有64个有效字符。为什么要除5取余?因为一个int型要用4个字节表示,也就是32位。
            }
            for (int i = 0; i < length / 5; i++) {
                num = random.nextInt();
                for (int j = 0; j < 5; j++) {
                    temp[index++] = ch[num & 63];
                    num >>= 6;
                }
            }
            return new String(temp, 0, length);
        }
        else if (length == 0) {
            return "";
        }
        else {
            throw new IllegalArgumentException();
        }
    }

    public static void main(String[] args) {
        System.out.println(createRandomString(16));
    }
}

 

 

Sha1.java
package com.test.cms.share;


import java.security.MessageDigest;

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'};

    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();
    }

    public static String encode(String str) {
        if (str == null) {
            return null;
        }
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
            messageDigest.update(str.getBytes());
            return getFormattedText(messageDigest.digest());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

 

控制器类

ShareController.java

package com.test.cms.share;

import cn.hutool.json.JSONUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.URI;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

@Controller
public class ShareController {

    /**
     * 微信公众号的appid
     */
    private String appid="wxd";

    /**
     * 微信公众号的appSecret
     */
    private String secret="ebded33";

    /**
     * 这是跳转到分享的页面
     * @return
     */
    @RequestMapping(value = "/to_detail")
    public String share(){
        return "/index/share";
    }


    /**
     * 获取微信分享配置的请求  方法只写了主要方法,需要根据自己的要求 完善代码
     * @param url 前台传过来的当前页面的请求地址
     * @return
     */
    @RequestMapping(value = "/get_wx_config")
    @ResponseBody
    public String share(String url){
        long timestamp = System.currentTimeMillis() / 1000;
        String noncestr = RandomStr.createRandomString(16);
        String ticket =getJsapiTicket();
        String str = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + url;
        System.out.println("签名str:" + str);
        String signature = Sha1.encode(str);

        //这只是简单写法,没有做错误判断
        Map map=new HashMap();
        map.put("appId",appid);
        map.put("timestamp",timestamp);
        map.put("nonceStr",noncestr);
        map.put("signature",signature);

        //这里使用了hutool工具将map转为String
        String json = JSONUtil.toJsonStr(map);

        return json;
    }

    /**
     * 官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62
     *
     * 获取jsapi_ticket
     *
     *
     *  生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。
     *  正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。
     *  由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。
     *
     * 参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):
     * https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html
     *
     * 用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):
     * https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
     *
     * @return
     */
    public String getJsapiTicket() {
        String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
        tokenUrl = tokenUrl + "&appid=" + appid + "&secret=" + secret;
        JSONObject tokenJson=new JSONObject();
        tokenJson=getUrlResponse(tokenUrl);
        System.out.println("tokenJson:"+tokenJson.toString());
        String token="";
        try {
            token=tokenJson.getString("access_token");
        } catch (JSONException e) {
            e.printStackTrace();
            System.out.println("报错了");
            return null;
        }

        String jsapiTicketUrl="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
        JSONObject jsapiTickeJson=new JSONObject();
        System.out.println("getJsapiTicket:获取token:"+token);
        if(StringUtils.isNotBlank(token)){
            jsapiTicketUrl = jsapiTicketUrl.replace("ACCESS_TOKEN",token);
            jsapiTickeJson=getUrlResponse(jsapiTicketUrl);
            System.out.println("tokenJson:"+jsapiTickeJson.toString());
            try {
                return (String) jsapiTickeJson.get("ticket");
            } catch (JSONException e) {
                e.printStackTrace();
                return null;
            }
        }else{
            return null;
        }
    }

    private  JSONObject getUrlResponse(String url){
        CharsetHandler handler = new CharsetHandler("UTF-8");
        try {
            HttpGet httpget = new HttpGet(new URI(url));
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
            //HttpClient
            CloseableHttpClient client = httpClientBuilder.build();
            client = (CloseableHttpClient) wrapClient(client);
            return new JSONObject(client.execute(httpget, handler));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }



    private static HttpClient wrapClient(HttpClient base) {
        try {
            SSLContext ctx = SSLContext.getInstance("TLSv1");
            X509TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] xcs,
                                               String string) throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] xcs,
                                               String string) throws CertificateException {
                }

                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(ctx, new String[] { "TLSv1" }, null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
            return httpclient;

        } catch (Exception ex) {
            return null;
        }
    }

    private class CharsetHandler implements ResponseHandler<String> {
        private String charset;

        public CharsetHandler(String charset) {
            this.charset = charset;
        }

        public String handleResponse(HttpResponse response)
                throws ClientProtocolException, IOException {
            StatusLine statusLine = response.getStatusLine();
            if (statusLine.getStatusCode() >= 300) {
                throw new HttpResponseException(statusLine.getStatusCode(),
                        statusLine.getReasonPhrase());
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                if (!StringUtils.isBlank(charset)) {
                    return EntityUtils.toString(entity, charset);
                } else {
                    return EntityUtils.toString(entity);
                }
            } else {
                return null;
            }
        }
    }

}

 

 

 

 

 

页面主要代码、这里展示的是分享给朋友、分享到朋友圈代码,其他分享可以具体看官方接口代码

share.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>分享页面给朋友,朋友圈</title>
</head>

<body>

</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<script type="text/javascript">
    $(function () {
        //当前页面的url地址
        var currUrl = decodeURIComponent(location.href.split('#')[0]);
        $.ajax({
            url: "/get_wx_config",
            dataType : "json",
            data: {
                'url': currUrl
            },
            error: function (res) {
                console.log(res);
                alert("发生错误");
            },
            success: function (res) {
                console.log(res);
                var appId = res.appId;
                var nonceStr = res.nonceStr;
                var timestamp = res.timestamp;
                var signature = res.signature;
                wx.config({
                    debug: false, //开启调试模式,开发阶段可以改成true,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
                    appId: appId, //必填,公众号的唯一标识
                    timestamp: timestamp, // 必填,生成签名的时间戳
                    nonceStr: nonceStr, //必填,生成签名的随机串
                    signature: signature, // 必填,签名,见附录1
                    jsApiList: [            //必填,需要使用的JS接口列表,所有JS接口列表 见附录2
                        'updateAppMessageShareData',
                        'updateTimelineShareData'
                    ]
                });


                wx.ready(function () {      //需在用户可能点击分享按钮前就先调用
                    //分享给朋友”及“分享到QQ”
                    wx.updateAppMessageShareData({
                        title: '朋友我是标题', // 分享标题
                        desc: '朋友 我是描述', // 分享描述
                        link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                        imgUrl: '', // 分享图标
                        success: function (res) {
                            // 设置成功
                        }
                    })

                    //分享到朋友圈”及“分享到QQ空间
                    wx.updateTimelineShareData({
                        title: '朋友圈我是标题', // 分享标题
                        link: '', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                        imgUrl: '', // 分享图标
                        success: function (res) {
                            // 设置成功
                        }
                    })


                });

                wx.error(function (res) {

                });
            }
        });

    });

</script>
</html>

 

 

设置公众号的js安全域名

 

 

 

 

 把域名放进去,不用加http的前缀,点击保存即可

 

保存之前要把文件下载下来放到项目根目录下,如果是开发环境的springboot项目可以参照这个教程做 

https://www.cnblogs.com/pxblog/p/13445128.html 

 

posted @ 2020-05-13 11:45  yvioo  阅读(6375)  评论(6编辑  收藏  举报