java微信分享_java微信分享前后端实现 - CSDN
精华内容
参与话题
  • Java微信分享接口开发

    2018-04-24 21:25:38
    Java微信分享,步骤是1、根据当前的url,获取signature,nonceStr,timestamp 和appId。 2、通过signature,nonceStr,timestamp 和appId来配置微信 wx.config。 3、通过wx.ready实现微信分享功能。1、html端引入...

    Java微信分享,步骤是

    1、根据当前的url,获取signature,nonceStr,timestamp 和appId。 
    2、通过signature,nonceStr,timestamp 和appId来配置微信 wx.config。 
    3、通过wx.ready实现微信分享功能。

    1、html端

    引入微信JS-SDK.

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

    //分享核心js代码
    $(document).ready(function () {
        //通过ajax,在页面加载的时候获取微信分享接口signature,nonceStr,timestamp 和appId
        $.ajax({
            type: "post",
            url: "/weixin/share",
            dataType: "json",
            data:"url="+window.location.href,
            success: function (data) {
                wx.config({
                    debug: false,
                    appId: data.appId,
                    timestamp: data.timestamp,
                    nonceStr: data.nonceStr,
                    signature: data.signature,
                    jsApiList: ['onMenuShareAppMessage', 'onMenuShareTimeline', 'hideAllNonBaseMenuItem', 'showMenuItems']
                    // 功能列表,我们要使用JS-SDK的什么功能
                });
                wx.ready(function () {
                    // 获取“分享给朋友”按钮点击状态及自定义分享内容接口
                    wx.onMenuShareAppMessage({
                        title: "分享自定义标题", // 分享标题
                        desc: "分享自定义描述", // 分享描述
                        link: "http://localhost/weixin/share?openId=1",//分享点击之后的链接
                        imgUrl:'/images/photo/1.jpg', // 分享图标
                        type: 'link', // 分享类型,music、video或link,不填默认为link
                        success: function () {
                            //成功之后的回调
                        }
                    });
                    wx.hideAllNonBaseMenuItem();
                    wx.showMenuItems({
                        menuList: ['menuItem:share:appMessage', 'menuItem:share:timeline'] // 要隐藏的菜单项,只能隐藏“传播类”和“保护类”按钮,所有menu项见附录3
                    });
                    wx.onMenuShareTimeline({
                        title: "分享自定义标题", // 分享标题
                        desc: "分享自定义描述", // 分享描述
                        link: "http://localhost/weixin/share?openId=1",//分享点击之后的链接
                        imgUrl:'/images/photo/1.jpg', // 分享图标
                        type: 'link', // 分享类型,music、video或link,不填默认为link
                        success: function () {
                            //成功之后的回调
                        }
                        cancel: function () {
                            // 用户取消分享后执行的回调函数
                        }
                    });
                });
                wx.error(function (res) {
                    //打印错误消息。及把 debug:false,设置为debug:ture就可以直接在网页上看到弹出的错误提示
                });
            }
        })
    });
    

    2、Java代码,获取 signature,nonceStr,timestamp 和appId

        @RequestMapping(value = "/share", method = RequestMethod.POST)
        @ResponseBody
        public Map<String, Object> share(HttpServletRequest request) {
            String urlTemp = "http://" + request.getServerName() + request.getContextPath();
            String urlpath = "http://" + request.getServerName();
            String appUrl = request.getParameter("url");
            if (request.getParameter("code") != null) {
                appUrl += "&code=" + request.getParameter("code");
            }
            if (request.getParameter("state") != null) {
                appUrl += "&state=" + request.getParameter("state");
            }
            return WxConfigUtil.getSignature(appUrl, ContentValues.APPID, ContentValues.SECRET, urlTemp, urlpath);
        }

    工具类我就把整个贴上来了,其中有些方法是没有用到的。

    getSignature()整个方法是微信分享中的核心方法,用来获取signature,nonceStr,timestamp 和appId这几个核心参数。

    package com.blog.common.util;
    
    import com.alibaba.fastjson.JSONObject;
    import com.blog.common.model.Token;
    
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.ConnectException;
    import java.net.URL;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    
    
    /**
     * 公众平台通用接口工具类
     *
     * @author james
     * @date 2015-02-27
     */
    public class WxConfigUtil {
        // 获取access_token的接口地址(GET) 限2000(次/天)
        public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
        // 获取jsapi_ticket的接口地址(GET) 限2000(次/天)
        public final static String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
        // 缓存添加的时间
        public static String cacheAddTime = null;
        // token,ticket缓存
        public static Map<String, Token> TOKEN_TICKET_CACHE = new HashMap<String, Token>();
        // token对应的key
        private static final String TOKEN = "token";
        // ticket对应的key
        private static final String TICKET = "ticket";
    
        /**
         * 外部获取签名入口类
         *
         * @param appUrl    应用的url
         * @return
         */
        public static Map<String, Object> getSignature(String appUrl, String appId, String secret, String url, String urlpath) {
            // 生成签名的随机串
            String noncestr = RandomUtil.getStringRandom(4);
            if (appUrl == null || "".equals(appUrl)) {
                return null;
            }
            String signature = null;
            Token accessTocken = getToken(appId, secret, System.currentTimeMillis() / 1000);
            Token accessTicket = getTicket(accessTocken.getToken(), System.currentTimeMillis() / 1000);
            signature = signature(accessTicket.getTicket(), cacheAddTime, noncestr, appUrl);
            System.out.println("-=-=-=-=-=-=-=-=appUrl:" + appUrl);
            System.out.println("-=-=-=-=-=-=-=-=token:" + accessTocken.getToken());
            System.out.println("-=-=-=-=-=-=-=-=ticket:" + accessTicket.getTicket());
            System.out.println("-=-=-=-=-=-=-=-=signature:" + signature);
            System.out.println("-=-=-=-=-=-=-=-=timestamp:" + cacheAddTime);
            Map<String, Object> map = new HashMap<>();
            map.put("appId", appId);
            map.put("timestamp", cacheAddTime);
            map.put("nonceStr", noncestr);
            map.put("appUrl", appUrl);
            map.put("signature", signature);
            map.put("url", url);
            map.put("urlpath", urlpath);
            return map;
        }
    
        /**
         * 获得Token
         *
         * @return
         */
        public static String getToken(String appId, String secret) {
            Token accessTocken = getToken(appId, secret, System.currentTimeMillis() / 1000);
            return accessTocken.getToken();
        }
    
        /**
         * 签名
         *
         * @param timestamp
         * @return
         */
        private static String signature(String jsapi_ticket, String timestamp, String noncestr, String url) {
            jsapi_ticket = "jsapi_ticket=" + jsapi_ticket;
            timestamp = "timestamp=" + timestamp;
            noncestr = "noncestr=" + noncestr;
            url = "url=" + url;
            String[] arr = new String[]{jsapi_ticket, noncestr, timestamp, url};
            // 将token、timestamp、nonce,url参数进行字典序排序
            Arrays.sort(arr);
            StringBuilder content = new StringBuilder();
            for (int i = 0; i < arr.length; i++) {
                content.append(arr[i]);
                if (i != arr.length - 1) {
                    content.append("&");
                }
            }
            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;
            return tmpStr;
        }
    
        /**
         * 获取access_token
         *
         * @param appid     凭证
         * @param appsecret 密钥
         * @return
         */
        public static Token getToken(String appid, String appsecret, long currentTime) {
            Token tockenTicketCache = getTokenTicket(TOKEN);
            Token Token = null;
    
            if (tockenTicketCache != null && (currentTime - tockenTicketCache.getAddTime() <= tockenTicketCache.getExpiresIn())) {// 缓存存在并且没过期
                System.out.println("==========缓存中token已获取时长为:" + (currentTime - tockenTicketCache.getAddTime()) + "毫秒,可以重新使用");
                return tockenTicketCache;
            }
            System.out.println("==========缓存中token不存在或已过期===============");
            String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
            JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
            // 如果请求成功
            if (null != jsonObject) {
                Token = new Token();
                Token.setToken(jsonObject.getString("access_token"));
                Token.setExpiresIn(jsonObject.getIntValue("expires_in") / 2);// 正常过期时间是7200秒,此处设置3600秒读取一次
                System.out.println("==========tocket缓存过期时间为:" + Token.getExpiresIn() + "毫秒");
                Token.setAddTime(currentTime);
                updateToken(TOKEN, Token);
            }
            return Token;
        }
    
        /**
         * 获取ticket
         *
         * @param token
         * @return
         */
        private static Token getTicket(String token, long currentTime) {
            Token tockenTicketCache = getTokenTicket(TICKET);
            Token Token = null;
            if (tockenTicketCache != null && (currentTime - tockenTicketCache.getAddTime() <= tockenTicketCache.getExpiresIn())) {// 缓存中有ticket
                System.out.println("==========缓存中ticket已获取时长为:" + (currentTime - tockenTicketCache.getAddTime()) + "毫秒,可以重新使用");
                return tockenTicketCache;
            }
            System.out.println("==========缓存中ticket不存在或已过期===============");
            String requestUrl = jsapi_ticket_url.replace("ACCESS_TOKEN", token);
            JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
            // 如果请求成功
            if (null != jsonObject) {
                Token = new Token();
                Token.setTicket(jsonObject.getString("ticket"));
                Token.setExpiresIn(jsonObject.getIntValue("expires_in") / 2);// 正常过期时间是7200秒,此处设置3600秒读取一次
                System.out.println("==========ticket缓存过期时间为:" + Token.getExpiresIn() + "毫秒");
                Token.setAddTime(currentTime);
                updateToken(TICKET, Token);
            }
            return Token;
        }
    
        /**
         * 发起https请求并获取结果
         *
         * @param requestUrl    请求地址
         * @param requestMethod 请求方式(GET、POST)
         * @param outputStr     提交的数据
         * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
         */
        private static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
            JSONObject jsonObject = null;
            StringBuffer buffer = new StringBuffer();
            try {
                // 创建SSLContext对象,并使用我们指定的信任管理器初始化
                TrustManager[] tm = {new MyX509TrustManager()};
                SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
                sslContext.init(null, tm, new java.security.SecureRandom());
                // 从上述SSLContext对象中得到SSLSocketFactory对象
                SSLSocketFactory ssf = sslContext.getSocketFactory();
    
                URL url = new URL(requestUrl);
                HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
                httpUrlConn.setSSLSocketFactory(ssf);
    
                httpUrlConn.setDoOutput(true);
                httpUrlConn.setDoInput(true);
                httpUrlConn.setUseCaches(false);
                // 设置请求方式(GET/POST)
                httpUrlConn.setRequestMethod(requestMethod);
    
                if ("GET".equalsIgnoreCase(requestMethod))
                    httpUrlConn.connect();
    
                // 当有数据需要提交时
                if (null != outputStr) {
                    OutputStream outputStream = httpUrlConn.getOutputStream();
                    // 注意编码格式,防止中文乱码
                    outputStream.write(outputStr.getBytes("UTF-8"));
                    outputStream.close();
                }
    
                // 将返回的输入流转换成字符串
                InputStream inputStream = httpUrlConn.getInputStream();
                InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
    
                String str = null;
                while ((str = bufferedReader.readLine()) != null) {
                    buffer.append(str);
                }
                bufferedReader.close();
                inputStreamReader.close();
                // 释放资源
                inputStream.close();
                inputStream = null;
                httpUrlConn.disconnect();
                jsonObject = JSONObject.parseObject(buffer.toString());
                // jsonObject = JSONObject.fromObject(buffer.toString());
            } catch (ConnectException ce) {
                System.out.println("Weixin server connection timed out.");
            } catch (Exception e) {
                System.out.println("https request error:{}" + e.getMessage());
            }
            return jsonObject;
        }
    
        /**
         * 将字节数组转换为十六进制字符串
         *
         * @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;
        }
    
        /**
         * 将字节转换为十六进制字符串
         *
         * @param mByte
         * @return
         */
        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;
        }
    
        /**
         * 从缓存中读取token或者ticket
         *
         * @return
         */
        private static Token getTokenTicket(String key) {
            if (TOKEN_TICKET_CACHE != null && TOKEN_TICKET_CACHE.get(key) != null) {
                System.out.println("==========从缓存中获取到了" + key + "成功===============");
                return TOKEN_TICKET_CACHE.get(key);
            }
            return null;
        }
    
        /**
         * 更新缓存中token或者ticket
         *
         * @return
         */
        private static void updateToken(String key, Token accessTocken) {
            if (TOKEN_TICKET_CACHE != null && TOKEN_TICKET_CACHE.get(key) != null) {
                TOKEN_TICKET_CACHE.remove(key);
                System.out.println("==========从缓存中删除" + key + "成功===============");
            }
            TOKEN_TICKET_CACHE.put(key, accessTocken);
            cacheAddTime = String.valueOf(accessTocken.getAddTime());// 更新缓存修改的时间
            System.out.println("==========更新缓存中" + key + "成功===============");
        }
    
    

    }

    友情链接:https://blog.csdn.net/shrmuscles/article/details/77987185https://blog.csdn.net/qq_29057491/article/details/61191566

    展开全文
  • 微信分享 java

    2019-12-19 11:38:21
    之前很少接触微信开发,最近让做分享有点蒙,下面是自己做分享的一些经验仅供参考 1、通过appId和secret获取access_token public static String getAccessToken(String appid, String secret) { String url = ...

    之前很少接触微信开发,最近让做分享有点蒙,下面是自己做分享的一些经验仅供参考

    1、通过appId和secret获取access_token

    public static String getAccessToken(String appid, String secret) {
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
        JSONObject jsonObject = httpRequest(url, "GET", null);
        RTLogger.getLogger("WechatLog").debug("重新获取微信接口token返回:"+jsonObject);
        try {
            if(jsonObject.getString("errcode")!=null){
                RTLogger.getLogger("WechatLog").debug("重新获取微信接口errcode返回:"+jsonObject.getString("errcode"));
                return "false";
            }
        }catch (Exception e) {
        }
        return jsonObject.getString("access_token");
    }

    2、通过access_token获取jsappticket

    public static String getJsapiTicket(String  token) {
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+token+"&type=jsapi";
        JSONObject jsonObject = httpRequest(url, "GET", null);
        log.info("获得 jsonObject{}------:"+jsonObject);
        try {
            if(!"0".equals(jsonObject.getString("errcode"))){
                return "false";
            }
        }catch (Exception e) {
        }
        return jsonObject.getString("ticket");
    }

    3、注意点token和ticket都是有默认有效期的,为了提高效率最好放到redis里面,过去时间比默认时间稍小

    4、完成关键的两步,就是对数据的封装和编码了

    @ModelAttribute("wechatInfo")
    public WechatInfo prepareShareInfo(HttpServletRequest request){
        String isshare = request.getParameter("isshare");
        if(StringUtils.isBlank(isshare)){
            return null;
        }
        WechatInfo wechatInfo =new WechatInfo();
        String fullUrl = getFullRequestUrl(request);
        // 生成微信签名信息
        String appId = WxPayConstant.APP_ID;
        if (WxPayConstant.getIsUseTestWx()) {
            appId = WxPayConstant.TEST_APP_ID;
        }
        wechatInfo.setAppId(appId);
        wechatInfo.setUrl(fullUrl);
        long timestamp = System.currentTimeMillis() / 1000;
        wechatInfo.setTimestamp(timestamp);
        String nonceStr = UUIDUtil.genUUIDString();
        wechatInfo.setNonceStr(nonceStr);
        String jsapiTicket = WeiXinUtil.getTicket(jedisClient);
        String signParam = "jsapi_ticket=" + jsapiTicket + "&noncestr=" + nonceStr + "&timestamp=" + timestamp + "&url=" + fullUrl; //参数一定按照这个字典循序排序,否者验签无法通过
        log.info("未编码前:"+signParam);
        String signature = Sha.encodeSha1(signParam);
        log.info("编码后:"+signature);
        wechatInfo.setSignature(signature);
        return wechatInfo;
    }

    5、java获取get请求全参数方法封装:

    public static String getFullRequestUrl(HttpServletRequest request){
        String queryStr=request.getQueryString();
        String furl= String.valueOf(request.getRequestURL());
        if(StringUtils.isNotBlank(queryStr)){
            furl+="?"+queryStr;
        }
        return furl;
    }

    到现在后台的配置结束。

    前端只需要导入微信jssdk进行相关配置即可

    <#--微信公众号JSSDK-->
    <script type="text/javascript" src="/js/ustore-api/jweixin-1.4.0.js"></script>

     

    function weixin() {
        alert(appId)
        // 微信JSSDK配置
        wx.config({
            debug: false,
            appId:appId,
            timestamp:timestamp,
            nonceStr: nonceStr,
            signature:signature,
            jsApiList: [
                'checkJsApi',
                'onMenuShareWeibo',
                'onMenuShareTimeline',
                'onMenuShareAppMessage',
                'onMenuShareQQ',
                'onMenuShareQZone'
            ]
        });
    }
    
    wx.ready(function () {
        wx.checkJsApi({
            jsApiList: [
                'onMenuShareWeibo',
                'onMenuShareTimeline',
                'onMenuShareAppMessage',
                'onMenuShareQQ',
                'onMenuShareQZone'
            ],
            success: function (res) {
                console.log(res);
            }
        });
        wx.onMenuShareWeibo({
           title: "测试", desc: '测试', link: url, imgUrl: 链接
        });
        wx.onMenuShareTimeline({
             title: "测试", desc: '测试', link: url, imgUrl: 链接
        });
        wx.onMenuShareAppMessage({
           title: "测试", desc: '测试', link: url, imgUrl: 链接
        });
        wx.onMenuShareQQ({
             title: "测试", desc: '测试', link: url, imgUrl: 链接
        });
        wx.onMenuShareQZone({
             title: "测试", desc: '测试', link: url, imgUrl: 链接
        });
    });

     

    展开全文
  • 点击上方[全栈开发者社区]→右上角[...]→[设为星标⭐]先上官方文档:http://mp.weixin.qq.com/wiki/home/index.html做之前建...
        

    点击上方[全栈开发者社区]右上角[...][设为星标⭐]

    640?

    先上官方文档:http://mp.weixin.qq.com/wiki/home/index.html

    做之前建议先过遍文档,文档都说的清晰明了。

    如果已经看过文档,那我们一起整理下JSSDK的流程步骤: 

    绑定域名

            登陆微信公众号,根据下列路径找到添加页面:

            微信公众号 - 公众号设置 - 功能设置 - JS接口安全域名

            添加步骤:

                1.下载txt文件(MP_verify_0HU5eN6Tzfwovxxx.txt),放到项目根目录下;

                2.添加项目访问域名地址,点击保存。在需要调用JS接口的页面引入js文件(页面不支持https的换成http://):

                https://res.wx.qq.com/open/js/jweixin-1.0.0.js

    config接口权限验证

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

     这里着重说下jsApiList参数:

            将要用到的接口用引号形式写进去,逗号隔开('','');

            这里添加的js接口名称要跟下面的wx.ready()里面的接口顺序对应。

             js接口名称见官方文档。

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

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

     备注:

          里面的js接口顺序一定要按照config()接口中的参数jsApiList中的js接口顺序排列。

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

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

    Over...

        额,当然,只是前端的流程步骤结束了。接下来我们看后台(java)是怎么处理config()接口中需要的那些参数的。

        这里需要用到公众号的几个参数:   appid、secret 。

        直接上后台代码:

    public class WeixinShareController extends Controller{	
      	
      public void index(){	
        	
        // 微信appid	
        String appid = "xxx";	
        // 微信secret	
        String secret = "xxx";	
        // 初始化access_token	
        String access_token = "";	
        //  获取URL 这里的URL指的是需要分享的那个页面地址,建议这里不要写成固定地址,而是获取当前地址.	
        String url = getPara("url");	
        	
        // 创建通过Api获取Token的链接与参数	
        String requestTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&amp;appid=APPID&amp;secret=SECRET";	
        requestTokenUrl = requestTokenUrl.replace("APPID", appid);	
        requestTokenUrl = requestTokenUrl.replace("SECRET", secret);	
            	
        JSONObject jsonObjectToken = CommonUtil.httpsRequest(requestTokenUrl, "GET", null);	
        if(StrKit.notNull(jsonObjectToken)){	
          // 创建日期赋值为当前日期	
          createDate = new Date().getTime()/1000;	
          // 获取Token值	
          access_token = jsonObjectToken.getString("access_token");	
          // 获取Token有效期值	
          expires_in = jsonObjectToken.getLong("expires_in");	
        }	
        	
        String requestUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&amp;type=jsapi";	
        requestUrl = requestUrl.replace("ACCESS_TOKEN", access_token);	
        // 获取凭证	
        JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);	
        if(StrKit.notNull(jsonObject)){	
          try {	
            String ticket = jsonObject.getString("ticket");	
            String noncestr = WebUtils.getRandom(7);	
            long timestamp = new Date().getTime()/1000;	
            	
            String param = "jsapi_ticket="+ticket+"&amp;noncestr="+noncestr+"×tamp="+timestamp+"&amp;url="+url;	
            String signature = DigestUtils.shaHex(param);	
            	
            WeixinShare weixinShare = new WeixinShare();	
            weixinShare.setWxNoncestr(noncestr);	
            weixinShare.setWxTimestamp(timestamp);	
            weixinShare.setWxSignature(signature);	
            setAttr("weixinShare",weixinShare);	
            setAttr("appid",appid);	
          } catch (Exception e) {	
            e.printStackTrace();	
            setAttr("errorMessage","服务器异常!");	
          }	
        }	
        renderJson();	
      }	
    }

    前端代码:

        这里建议ur参数不要写成固定地址,用提供的获取当前路径的方法获取,可以保证该js的重用:

    var url    = location.href.split('#')[0];

    代码:

    
    	
    $(function(){	
      var title        = $("#title").val();	
      var desc      = $("#desc").val();	
      var name      = $("#program_name").val();	
      var imgUrl       = $("#imgurl").val();	
      var path   = $("#path").val();	
      var url    = location.href.split('#')[0];	
      	
      var signature,timestamp,noncestr,appid;	
     	
      /*微信分享*/	
       $.ajax({	
             url:path+"/weixinshare",	
             type:'GET',	
             data:{	
               url : url	
             },	
             success:function (data) {	
               signature = data.weixinShare.wx_signature;	
               timestamp = data.weixinShare.wx_timestamp;	
               noncestr = data.weixinShare.wx_noncestr;	
               appid = data.appid;	
               wx.config({	
                    debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。	
                    appId: appid, // 必填,公众号的唯一标识	
                    timestamp: timestamp, // 必填,生成签名的时间戳	
                    nonceStr: noncestr, // 必填,生成签名的随机串	
                    signature: signature,// 必填,签名	
                    jsApiList: ['onMenuShareAppMessage','onMenuShareTimeline'] // 必填,需要使用的JS接口列表	
                });	
               	
               wx.ready(function(){	
                //分享给朋友	
                 wx.onMenuShareAppMessage({	
                   title: title, // 分享标题	
                   desc: desc, // 分享描述	
                   link: path, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致	
                   imgUrl:imgUrl, // 分享图标s	
                   type: 'link', // 分享类型,music、video或link,不填默认为link	
                   dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空	
                   success: function () {	
                   // 用户确认分享后执行的回调函数	
    //                 alert("OK");	
                   },	
                   cancel: function () {	
                   // 用户取消分享后执行的回调函数	
    //                 alert("fail");	
                   }	
                   });	
                 //分享给朋友圈	
                 wx.onMenuShareTimeline({	
                      title: title, // 分享标题	
                      link: path, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致	
                      imgUrl: imgUrl, // 分享图标	
                      success: function () {	
                      // 用户确认分享后执行的回调函数	
                  },	
                 });	
               });	
             },	
             error:function(error){	
                 console.log(error);	
             }	
      });   	
    })

    以上就是整个功能的全部代码了。

    原文链接:https://blog.csdn.net/IbelieveSmile/article/details/80176563

    留言打卡30天,祝贺第一批坚持打卡的小伙伴们满月啦,继续努力!smiley_57.png

    觉得本文对你有帮助?请分享给更多人

    关注「全栈开发者社区」加星标,提升全栈技能

    本公众号会不定期给大家发福利,包括送书、学习资源等,敬请期待吧!

    如果感觉推送内容不错,不妨右下角点个在看转发朋友圈或收藏,感谢支持。

    好文章,我在看❤️

    展开全文
  • 今天踩了一个很大的坑。。我发现微信坑真多啊。...这个时候就说了为什么变成这个样子,因为他分享H5没有写微信的二次分享。 二次分享操作流程: 打开某app然后分享到朋友某一个篇文章。 然后朋友打开,觉...

    今天踩了一个很大的坑。。我发现微信坑真多啊。微信做的东西真的不屑于评论啊。刚开始坑公众号开发,然后坑微信支付开发,然后坑小程序开发。我真的走不出来了。。。。关键还没办法。

    今天给大家分享一下app的二次分享问题吧。

    file

    是不是挺好玩的。这个时候就说了为什么变成这个样子,因为他分享H5没有写微信的二次分享。

    二次分享操作流程:

    1. 打开某app然后分享到朋友某一个篇文章。
    2. 然后朋友打开,觉得写得不错,然后呢也分享了,然后就出现了下图的现象。。
    3. 所有参数都暴露了不说,关键是难看啊。你看上图。

    画个图图告诉你什么是二次分享:

    file

    代码流程炒鸡简单。我给你们也画一个流程图。
    

    file

    老规矩:

    点我快速进入分享sdk官方文档

    直接上代码吧。代码有些糙 不喜欢勿喷。

    	前段需要引入的js
    		<!--微信分享js  -->
    		<script src="http://res2.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
    		<script src="static/js/wx_share.js"></script
    
    		前端的代码:我用的el表达式,jsp页面。别的可根据自己进行修改。
    		<input type="hidden"value="${shareDate.nonceStr }" id="nonceStr">
    		<input type="hidden"value="${shareDate.timestamp }" id="timestamp">
    		<input type="hidden"value="${shareDate.signature }" id="signature">
    		<input type="hidden"value="${shareDate.appid }" id="appid">
    		<input type="hidden"value="${shareDate.share_title }" id="share_title">
    		<input type="hidden"value="${shareDate.share_detail }" id="share_detail">
    		<input type="hidden"value="${shareDate.share_image }" id="share_image">
    		<input type="hidden"value="${shareDate.share_url }" id="share_url">	
    		
    		自己的封装的wx_share.js
    		$(function() {
    			var timestamp = $("#timestamp").val();
    			var nonceStr = $("#nonceStr").val();//随机串
    			var signature = $("#signature").val();//签名
    			var appid = $("#appid").val();
    			var title = $("#share_title").val();
    			var desc = $("#share_detail").val();
    			var link = $("#share_url").val();
    			var imgUrl = $("#share_image").val();
    			wx.config({
    				debug : true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    				appId : appid, // 必填,公众号的唯一标识
    				timestamp : timestamp, // 必填,生成签名的时间戳
    				nonceStr : nonceStr, // 必填,生成签名的随机串
    				signature : signature,// 必填,签名,见附录1
    				jsApiList : [ 'onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo' ]
    			// 必填,需要使用的JS接口列表,所有JS接口列表见附录2
    			});
    
    			wx.ready(function(){
    				wx.onMenuShareTimeline({
    						title: title,
    					link: link,
    					imgUrl: imgUrl,
    					success: function () { 
    						// 用户确认分享后执行的回调函数
    						 alert('分享到朋友圈成功');
    					},
    					cancel: function () { 
    						// 用户取消分享后执行的回调函数
    						 alert('你没有分享到朋友圈');
    					}
    				});
    				wx.onMenuShareAppMessage({
    					  title: title,
    					  desc: desc,
    					  link: link,
    					  imgUrl: imgUrl,
    					  success: function (res) {
    						  alert('分享给朋友成功');
    					  },
    					  cancel: function (res) {
    						alert('你没有分享给朋友');
    					  },
    				});
    				wx.onMenuShareQQ({
    						title: title,
    					desc: desc,
    					link: link,
    					imgUrl: imgUrl,
    					success: function () { 
    					   // 用户确认分享后执行的回调函数
    						alert('分享给朋友成功');
    					},
    					cancel: function () { 
    					   // 用户取消分享后执行的回调函数
    					}
    				});
    				wx.onMenuShareWeibo({
    						title: title,
    					desc: desc,
    					link: link,
    					imgUrl: imgUrl,
    					success: function () { 
    					   // 用户确认分享后执行的回调函数
    						alert('分享给朋友成功');
    					},
    					cancel: function () { 
    						// 用户取消分享后执行的回调函数
    					}
    				});
    				wx.onMenuShareQZone({
    						title: title,
    					desc: desc,
    					link: link,
    					imgUrl: imgUrl,
    					success: function () { 
    					   // 用户确认分享后执行的回调函数
    						alert('分享给朋友成功');
    					},
    					cancel: function () { 
    						// 用户取消分享后执行的回调函数
    					}
    				});
    			});
    		});
    		
    		
    		 
    /**
    	 * 分享数据test
    	 * 
    	 * @return
    	 * @throws Exception
    	 */
    	@RequestMapping(value = "/share_date", method = RequestMethod.GET)
    	public ModelAndView share_date() throws Exception {
    		ModelAndView modelAndView = this.getModelAndView();
    		PageData pd = new PageData();
    		pd = this.getPageData();
    		try {
    				PageData shareDate = commonService.wx_share_date("test", "hehe", "xxxx.img", "xxx");
    				modelAndView.addObject("shareDate", shareDate);				
    		     	modelAndView.setViewName("xx/xxx/xxx");
    
    		} catch (Exception e) {
    			e.printStackTrace();
    			logBefore(logger, e.toString());
    			throw e;
    		}
    		return modelAndView;
    	}
    	/**
    	 * 封装二次分享数据返回前台
    	 * 
    	 * @param share_title  分享标题
    	 * @param share_detail 分享描述
    	 * @param share_image  分享图片
    	 * @param share_url    分享打开连接
    	 * @return
    	 * @throws Exception
    	 */
    	public PageData wx_share_date(String share_title, String share_detail, String share_image, String share_url)
    			throws Exception {
    		
    		//微信所需要的数据
    		PageData wxDate = Sign.retSign(wechatShareUtil.getJsapiTicket(), share_url);
    		wxDate.put("appid", WeChatUtil.WEIXIN_APPID);
    		
    		//分享所需要数据
    		wxDate.put("share_title", share_title);
    		wxDate.put("share_detail", share_detail);
    		wxDate.put("share_image", share_image);
    		wxDate.put("share_url", share_url);
    		return wxDate; 
    	}
    	
    	package cn.cnbuilder.util;
    
    import javax.annotation.Resource;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    import cn.cnbuilder.dao.redis.RedisDao;
    import cn.cnbuilder.entity.AccessToken;
    import cn.cnbuilder.entity.TicketJson;
    import cn.cnbuilder.util.weixin.WeChatUtil;
    
    import net.sf.json.JSONException;
    import net.sf.json.JSONObject;
    
    @Component
    public class WechatShareUtil {
    
    	@Resource(name = "redisDaoImpl")
    	private RedisDao redisDaoImpl;
    
    	private static Logger log = LoggerFactory.getLogger(WeChatUtil.class);
    
    	/**
    	 * 获取微信jsapi_ticket
    	 * 
    	 * 
    	 * @param pd
    	 * @throws Exception
    	 */
    	public String getJsapiTicket() {
    
    		// 先获取jsapi_ticket在redis中是否存在
    		String gzh_jsapiTicket = redisDaoImpl.get("jsapiTicket");
    		if (Tools.isEmpty(gzh_jsapiTicket)) {
    			String accessToken = getAccessToken();
    			// 获取jsapi_ticket并保存到redis中
    			TicketJson ticketJson = getJsapiTicket(accessToken);
    			gzh_jsapiTicket = ticketJson.getTicket();
    			if (Tools.notEmpty(gzh_jsapiTicket)) {
    				redisDaoImpl.addString("jsapiTicket", gzh_jsapiTicket, ticketJson.getExpires_in());
    			}
    		}
    		return gzh_jsapiTicket;
    	}
    
    	/**
    	 * 获取微信accessToken
    	 * 
    	 * @param pd
    	 * @throws Exception
    	 */
    	public String getAccessToken() throws JSONException {
    		// 先获取accessToken在redis中是否存在
    		String gzh_accessToken = redisDaoImpl.get("accessToken");
    		if (Tools.isEmpty(gzh_accessToken)) {
    			// 获取accessToken并保存到redis中
    			AccessToken accessToken = getAccessTokenByWechat();
    			if (accessToken != null) {
    				gzh_accessToken = accessToken.getToken();
    				redisDaoImpl.addString("accessToken", gzh_accessToken, accessToken.getExpiresIn());
    			}
    		}
    		return gzh_accessToken;
    	}
    
    	/**
    	 * @Description: 通过微信获取token
    	 */
    	public AccessToken getAccessTokenByWechat() throws JSONException {
    		String requestUrl = WeChatUtil.access_Token_Url.replace("APPID", WeChatUtil.WEIXIN_APPID).replace("APPSECRET",
    				WeChatUtil.WEIXIN_APPSECRET);
    		JSONObject jsonObject = WeChatUtil.httpRequest(requestUrl, "GET", null);
    		AccessToken accessToken = new AccessToken();
    		// 如果请求成功
    		if (null != jsonObject) {
    			try {
    				accessToken.setToken(jsonObject.getString("access_token"));
    				accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
    				log.info("获取access_token成功,有效时长{}秒 token:{}", accessToken.getExpiresIn(), accessToken.getToken());
    			} catch (JSONException e) {
    				// 获取token失败
    				log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"),
    						jsonObject.getString("errmsg"));
    			}
    		}
    		return accessToken;
    	}
    
    	/**
    	 * @Description: 不通过判断,直接生成锌的token
    	 */
    	public TicketJson getJsapiTicket(String token) throws JSONException {
    		String requestUrl = WeChatUtil.get_jsticket.replace("ACCESS_TOKEN", token);
    		JSONObject jsonObject = WeChatUtil.httpRequest(requestUrl, "GET", null);
    		TicketJson ticketJson = new TicketJson();
    		// 如果请求成功
    		if (null != jsonObject) {
    			try {
    				ticketJson.setErrcode(jsonObject.getInt("errcode"));
    				ticketJson.setErrmsg(jsonObject.getString("errmsg"));
    				ticketJson.setExpires_in(jsonObject.getInt("expires_in"));
    				ticketJson.setTicket(jsonObject.getString("ticket"));
    				log.info("获取jsapi_ticket成功,有效时长{}秒 token:{}", ticketJson.getExpires_in(), ticketJson.getTicket());
    			} catch (JSONException e) {
    				// 获取token失败
    				log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"),
    						jsonObject.getString("errmsg"));
    			}
    		}
    		return ticketJson;
    	}
    }
    package cn.cnbuilder.entity;
    
    import java.io.Serializable;
    
    /**
     * 微信通用接口凭证
     * 
     * @author KingYiFan
     * @date 2015-12-13
     */
    public class AccessToken implements Serializable{
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = -553323547802220881L;
    	// 获取到的凭证
    	private String token;
    	// 凭证有效时间,单位:秒
    	private int expiresIn;
    
    	public String getToken() {
    		return token;
    	}
    
    	public void setToken(String token) {
    		this.token = token;
    	}
    
    	public int getExpiresIn() {
    		return expiresIn;
    	}
    
    	public void setExpiresIn(int expiresIn) {
    		this.expiresIn = expiresIn;
    	}
    }
    
    package cn.cnbuilder.entity;
    
    import java.io.Serializable;
    
    /**
     * 微信通用接口凭证
     * 
     * @author KingYiFan
     * @date 2015-12-13
     */
    public class TicketJson implements Serializable{
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	private int errcode;  
        private String errmsg;  
        private String ticket;  
        private int expires_in;  
        public int getErrcode() {  
            return errcode;  
        }  
        public void setErrcode(int errcode) {  
            this.errcode = errcode;  
        }  
        public String getErrmsg() {  
            return errmsg;  
        }  
        public void setErrmsg(String errmsg) {  
            this.errmsg = errmsg;  
        }  
        public String getTicket() {  
            return ticket;  
        }  
        public void setTicket(String ticket) {  
            this.ticket = ticket;  
        }  
        public int getExpires_in() {  
            return expires_in;  
        }  
        public void setExpires_in(int expires_in) {  
            this.expires_in = expires_in;  
        }
    }
    
    。。。wechatUtils
    
    package cn.cnbuilder.util.weixin;
    
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.UnsupportedEncodingException;
    import java.net.ConnectException;
    import java.net.URL;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Formatter;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    
    import javax.annotation.Resource;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import cn.cnbuilder.dao.redis.RedisDao;
    import cn.cnbuilder.entity.AccessToken;
    import cn.cnbuilder.entity.TicketJson;
    import cn.cnbuilder.util.MyX509TrustManager;
    import cn.cnbuilder.util.PageData;
    import cn.cnbuilder.util.Tools;
    import cn.cnbuilder.util.wxpay.Sign;
    
    import net.sf.json.JSONException;
    import net.sf.json.JSONObject;
    
    /**
     * 公众平台通用接口工具类
     */
    public class WeChatUtil {
    	
    	@Resource(name = "redisDaoImpl")
    	private RedisDao redisDaoImpl;
    	
    	private static Logger log = LoggerFactory.getLogger(WeChatUtil.class);
    
    	 
    	public static String WEIXIN_APPID = "xxxx";
    	public static String WEIXIN_APPSECRET = "xxxx";
    
    	// 获取access_token的接口地址(GET) 限200(次/天)
    	public final static String access_Token_Url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="
    + WEIXIN_APPID + "&secret=" + WEIXIN_APPSECRET;
    	// 拉取用户信息(需scope为 snsapi_userinfo) ACCESS_TOKEN 是网页授权的ACCESS_TOKEN
    	public final static String user_Info_Url_login = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID";
    
    	// 获取用户基本信息(包括UnionID机制)
    	public final static String user_Info_Url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
    
    	// 用户同意授权,获取code
    	public final static String scope_Code_Url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="
    			+ WEIXIN_APPID
    			+ "&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect";
    	// 通过code换取网页授权access_token
    	public final static String scope_OpenId_Url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="
    			+ WEIXIN_APPID + "&secret=" + WEIXIN_APPSECRET + "&code=CODE&grant_type=authorization_code";
    	// 由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权。
    	public final static String refresh_token_Url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid="
    			+ WEIXIN_APPID + "&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";
    
    	// 获取用户code值
    	public final static String get_code_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="
    			+ WEIXIN_APPID
    			+ "&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
    
    	//获取jsticket
    	public final static String get_jsticket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
    
    	
    	
    	/**
    	 * 通过code获取网页授权 和用户openid
    	 * 
    	 * @param code
    	 * @return
    	 */
    	public static Map<String, Object> getOpenId(String code) {
    		Map<String, Object> resMap = new HashMap<>();
    		String openId = null;
    		String accessToken = null;
    		String refreshToken = null;
    		String url = scope_OpenId_Url.replace("CODE", code);
    		JSONObject jsonObject = httpRequest(url, "POST", null);
    		log.info("WeChatUtil getOpenId=" + jsonObject);
    		if (null != jsonObject) {
    			if (!jsonObject.containsKey("errcode")) {
    				openId = jsonObject.getString("openid");
    				accessToken = jsonObject.getString("access_token");
    				refreshToken = jsonObject.getString("refresh_token");
    				resMap.put("openId", openId);
    				resMap.put("accessToken", accessToken);
    				resMap.put("refresh_token", refreshToken);
    				return resMap;
    			} else {
    				int errorCode = jsonObject.getInt("errcode");
    				String errorMsg = jsonObject.getString("errmsg");
    				log.info("通过code换取网页授权失败errorCode:{" + errorCode + "},errmsg:{" + errorMsg + "}");
    				System.out.println("通过code换取网页授权失败errorCode:{" + errorCode + "},errmsg:{" + errorMsg + "}");
    			 
    			}
    		}
    		return resMap;
    		
    	}
    
    	/**
    	 * 通过openId和accessToken获取当前用户的基本信息
    	 * 
    	 * @param openId
    	 * @param accessToken
    	 * @return
    	 */
    	public static JSONObject getUserInfo2(String openId, String accessToken) {
    		String url = user_Info_Url.replace("OPENID", openId).replace("ACCESS_TOKEN", accessToken);
    		JSONObject jsonObject = httpRequest(url, "POST", null);
    		log.info("WeChatUtil getUserInfo=" + jsonObject);
    		return jsonObject;
    	}
    
    	/**
    	 * 通过appId和appSecretId获取accessToken
    	 * 
    	 * @date 2018年3月6日
    	 * @return
    	 */
    	public static String getAccessToken() {
    		String url = access_Token_Url.replace("WEIXIN_APPID", WEIXIN_APPID).replace("WEIXIN_APPSECRET",
    				WEIXIN_APPSECRET);
    		JSONObject jsonObject = httpRequest(url, "GET", null);
    		log.info("WeChatUtil getAccessToken=" + jsonObject);
    		return jsonObject.getString("access_token");
    	}
    
    	/**
    	 * 获取用户code值
    	 */
    	public static String getCodeUrl(String redirect_uri) {
    		String url = get_code_url.replace("REDIRECT_URI", redirect_uri);
    		return url;
    
    	}
    
    	/**
    	 * 刷新token有效期
    	 * 
    	 * @date 2018年3月6日
    	 * @return
    	 */
    	public static String refreshToken(String REFRESH_TOKEN) {
    		String url = refresh_token_Url.replace("REFRESH_TOKEN", REFRESH_TOKEN);
    		JSONObject jsonObject = httpRequest(url, "GET", null);
    		log.info("WeChatUtil refreshToken=" + jsonObject);
    		return jsonObject.getString("access_token");
    	}
    	
    	/**
    	 * 获取jsticket
    	 * 
    	 * @date 2018年3月6日
    	 * @return
    	 */
    	public static String getJsTicket(String accessToken) {
    		String url = get_jsticket.replace("ACCESS_TOKEN", accessToken);
    		JSONObject jsonObject = httpRequest(url, "GET", null);
    		return jsonObject.getString("ticket");
    	}
    	
    	/**
    	 * URL编码(utf-8)
    	 * 
    	 * @param source
    	 * @return
    	 */
    	public static String urlEncodeUTF8(String source) {
    		String result = source;
    		try {
    			result = java.net.URLEncoder.encode(source, "utf-8");
    		} catch (UnsupportedEncodingException e) {
    			e.printStackTrace();
    			log.error("urlEncodeUTF8出现异常!\n" + e.getMessage());
    		}
    		return result;
    	}
    
    	public static String getWEIXIN_APPID() {
    		return WEIXIN_APPID;
    	}
    
    	public static void setWEIXIN_APPID(String wEIXIN_APPID) {
    		WEIXIN_APPID = wEIXIN_APPID;
    	}
    
    	public static String getWEIXIN_APPSECRET() {
    		return WEIXIN_APPSECRET;
    	}
    
    	public static void setWEIXIN_APPSECRET(String wEIXIN_APPSECRET) {
    		WEIXIN_APPSECRET = wEIXIN_APPSECRET;
    	}
    
    	/**
    	 * 发起https请求并获取结果
    	 * 
    	 * @param requestUrl    请求地址
    	 * @param requestMethod 请求方式(GET、POST)
    	 * @param outputStr     提交的数据
    	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
    	 */
    	public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
    		JSONObject jsonObject = null;
    		StringBuffer buffer = new StringBuffer();
    		try {
    			// 创建SSLContext对象,并使用我们指定的信任管理器初始化
    			TrustManager[] tm = { new MyX509TrustManager() };
    			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
    			sslContext.init(null, tm, new java.security.SecureRandom());
    			// 从上述SSLContext对象中得到SSLSocketFactory对象
    			SSLSocketFactory ssf = sslContext.getSocketFactory();
    			URL url = new URL(requestUrl);
    			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
    			httpUrlConn.setSSLSocketFactory(ssf);
    			httpUrlConn.setDoOutput(true);
    			httpUrlConn.setDoInput(true);
    			httpUrlConn.setUseCaches(false);
    			// 设置请求方式(GET/POST)
    			httpUrlConn.setRequestMethod(requestMethod);
    			if ("GET".equalsIgnoreCase(requestMethod))
    				httpUrlConn.connect();
    			// 当有数据需要提交时
    			if (null != outputStr) {
    				OutputStream outputStream = httpUrlConn.getOutputStream();
    				// 注意编码格式,防止中文乱码
    				outputStream.write(outputStr.getBytes("UTF-8"));
    				outputStream.close();
    			}
    			// 将返回的输入流转换成字符串
    			InputStream inputStream = httpUrlConn.getInputStream();
    			InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
    			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
    			String str = null;
    			while ((str = bufferedReader.readLine()) != null) {
    				buffer.append(str);
    			}
    			bufferedReader.close();
    			inputStreamReader.close();
    			// 释放资源
    			inputStream.close();
    			inputStream = null;
    			httpUrlConn.disconnect();
    			jsonObject = JSONObject.fromObject(buffer.toString());
    		} catch (ConnectException ce) {
    			ce.printStackTrace();
    			log.error("Weixin server connection timed out.");
    		} catch (Exception e) {
    			e.printStackTrace();
    			log.error("https request error:{}", e);
    		}
    		return jsonObject;
    	}
    
    	public static Map<String, String> sign(String jsapi_ticket, String url) {
    		Map<String, String> ret = new HashMap<String, String>();
    		String nonce_str = create_nonce_str();
    		String timestamp = create_timestamp();
    		String string1;
    		String signature = "";
    
    		// 注意这里参数名必须全部小写,且必须有序
    		string1 = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonce_str + "&timestamp=" + timestamp + "&url=" + url;
    		System.out.println(string1);
    
    		try {
    			MessageDigest crypt = MessageDigest.getInstance("SHA-1");
    			crypt.reset();
    			crypt.update(string1.getBytes("UTF-8"));
    			signature = byteToHex(crypt.digest());
    		} catch (NoSuchAlgorithmException e) {
    			e.printStackTrace();
    		} catch (UnsupportedEncodingException e) {
    			e.printStackTrace();
    		}
    
    		ret.put("url", url);
    		ret.put("jsapi_ticket", jsapi_ticket);
    		ret.put("nonceStr", nonce_str);
    		ret.put("timestamp", timestamp);
    		ret.put("signature", signature);
    
    		return ret;
    	}
    
    	private static String byteToHex(final byte[] hash) {
    		Formatter formatter = new Formatter();
    		for (byte b : hash) {
    			formatter.format("%02x", b);
    		}
    		String result = formatter.toString();
    		formatter.close();
    		return result;
    	}
    
    	private static String create_nonce_str() {
    		return UUID.randomUUID().toString();
    	}
    
    	private static String create_timestamp() {
    		return Long.toString(System.currentTimeMillis() / 1000);
    	}
    
    }
    
    加密
    
    package cn.cnbuilder.util.wxpay;
    
    import java.util.UUID;
    
    import cn.cnbuilder.util.PageData;
    
    import java.util.Map;
    import java.util.Formatter;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.io.UnsupportedEncodingException;  
    
    public class Sign {
        public static void main(String[] args) {
            String jsapi_ticket = "jsapi_ticket";
    
            // 注意 URL 一定要动态获取,不能 hardcode
            String url = "http://baidu.com";
            Map<String, String> ret = retSign(jsapi_ticket, url);
            
        };
    
        public static PageData retSign(String jsapi_ticket, String url) {
        		PageData ret = new PageData();
            String nonce_str = create_nonce_str();
            String timestamp = create_timestamp();
            String string1;
            String signature = "";
    
            //注意这里参数名必须全部小写,且必须有序
            string1 = "jsapi_ticket=" + jsapi_ticket +
                      "&noncestr=" + nonce_str +
                      "×tamp=" + timestamp +
                      "&url=" + url;
            try
            {
                MessageDigest crypt = MessageDigest.getInstance("SHA-1");
                crypt.reset();
                crypt.update(string1.getBytes("UTF-8"));
                signature = byteToHex(crypt.digest());
            }
            catch (NoSuchAlgorithmException e)
            {
                e.printStackTrace();
            }
            catch (UnsupportedEncodingException e)
            {
                e.printStackTrace();
            }
            ret.put("jsapi_ticket", jsapi_ticket);
            ret.put("nonceStr", nonce_str);
            ret.put("timestamp", timestamp);
            ret.put("signature", signature);
    
            return ret;
        }
    
        private static String byteToHex(final byte[] hash) {
            Formatter formatter = new Formatter();
            for (byte b : hash)
            {
                formatter.format("%02x", b);
            }
            String result = formatter.toString();
            formatter.close();
            return result;
        }
    
        private static String create_nonce_str() {
            return UUID.randomUUID().toString();
        }
    
        private static String create_timestamp() {
            return Long.toString(System.currentTimeMillis() / 1000);
        }
    }
    

    微信的签名算法逻辑。 file

    微信分享-常见错误及解决方法
    
    调用config 接口的时候传入参数 debug: true 可以开启debug模式,页面会alert出错误信息。以下为常见错误及解决方法:
    
    1.invalid url domain当前页面所在域名与使用的appid没有绑定,请确认正确填写绑定的域名,仅支持80(http)和443(https)两个端口,因此不需要填写端口号(一个appid可以绑定三个有效域名,见 ]目录1.1.1)。
    
    2.invalid signature签名错误。建议按如下顺序检查:
    
    1.确认签名算法正确,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。
    
    2.确认config中nonceStr(js中驼峰标准大写S), timestamp与用以签名中的对应noncestr, timestamp一致。
    
    3.确认url是页面完整的url(请在当前页面alert(location.href.split('#')[0])确认),包括'http(s)://'部分,以及'?'后面的GET参数部分,但不包括'#'hash后面的部分。
    
    4.确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。
    
    5.确保一定缓存access_token和jsapi_ticket。
    
    6.确保你获取用来签名的url是动态获取的,动态页面可参见实例代码中php的实现方式。如果是html的静态页面在前端通过ajax将url传到后台签名,前端需要用js获取当前页面除去'#'hash部分的链接(可用location.href.split('#')[0]获取,而且需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。
    
    3.the permission value is offline verifying这个错误是因为config没有正确执行,或者是调用的JSAPI没有传入config的jsApiList参数中。建议按如下顺序检查:
    
    1.确认config正确通过。
    
    2.如果是在页面加载好时就调用了JSAPI,则必须写在wx.ready的回调中。
    
    3.确认config的jsApiList参数包含了这个JSAPI。
    
    4.permission denied该公众号没有权限使用这个JSAPI,或者是调用的JSAPI没有传入config的jsApiList参数中(部分接口需要认证之后才能使用)。
    
    5.function not exist当前客户端版本不支持该接口,请升级到新版体验。
    
    6.为什么6.0.1版本config:ok,但是6.0.2版本之后不ok(因为6.0.2版本之前没有做权限验证,所以config都是ok,但这并不意味着你config中的签名是OK的,请在6.0.2检验是否生成正确的签名以保证config在高版本中也ok。)
    
    7.在iOS和Android都无法分享(请确认公众号已经认证,只有认证的公众号才具有分享相关接口权限,如果确实已经认证,则要检查监听接口是否在wx.ready回调函数中触发)
    
    8.服务上线之后无法获取jsapi_ticket,自己测试时没问题。(因为access_token和jsapi_ticket必须要在自己的服务器缓存,否则上线后会触发频率限制。请确保一定对token和ticket做缓存以减少2次服务器请求,不仅可以避免触发频率限制,还加快你们自己的服务速度。目前为了方便测试提供了1w的获取量,超过阀值后,服务将不再可用,请确保在服务上线前一定全局缓存access_token和jsapi_ticket,两者有效期均为7200秒,否则一旦上线触发频率限制,服务将不再可用)。
    
    9.uploadImage怎么传多图(目前只支持一次上传一张,多张图片需等前一张图片上传之后再调用该接口)
    
    10.没法对本地选择的图片进行预览(chooseImage接口本身就支持预览,不需要额外支持)
    
    11.通过a链接(例如先通过微信授权登录)跳转到b链接,invalid signature签名失败(后台生成签名的链接为使用jssdk的当前链接,也就是跳转后的b链接,请不要用微信登录的授权链接进行签名计算,后台签名的url一定是使用jssdk的当前页面的完整url除去'#'部分)
    
    12.出现config:fail错误(这是由于传入的config参数不全导致,请确保传入正确的appId、timestamp、nonceStr、signature和需要使用的jsApiList)
    
    13.如何把jsapi上传到微信的多媒体资源下载到自己的服务器(请参见文档中uploadVoice和uploadImage接口的备注说明)
    
    14.Android通过jssdk上传到微信服务器,第三方再从微信下载到自己的服务器,会出现杂音(微信团队已经修复此问题,目前后台已优化上线)
    
    15.绑定父级域名,是否其子域名也是可用的(是的,合法的子域名在绑定父域名之后是完全支持的)
    
    16.在iOS微信6.1版本中,分享的图片外链不显示,只能显示公众号页面内链的图片或者微信服务器的图片,已在6.2中修复
    
    17.是否需要对低版本自己做兼容(jssdk都是兼容低版本的,不需要第三方自己额外做更多工作,但有的接口是6.0.2新引入的,只有新版才可调用)
    
    18.该公众号支付签名无效,无法发起该笔交易(请确保你使用的jweixin.js是官方线上版本,不仅可以减少用户流量,还有可能对某些bug进行修复,拷贝到第三方服务器中使用,官方将不对其出现的任何问题提供保障,具体支付签名算法可参考 JSSDK微信支付一栏)
    
    19.目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题已在Android6.2中修复
    
    20.uploadImage在chooseImage的回调中有时候Android会不执行,Android6.2会解决此问题,若需支持低版本可以把调用uploadImage放在setTimeout中延迟100ms解决
    
    21.require subscribe错误说明你没有订阅该测试号,该错误仅测试号会出现
    
    22.getLocation返回的坐标在openLocation有偏差,因为getLocation返回的是gps坐标,openLocation打开的腾讯地图为火星坐标,需要第三方自己做转换,6.2版本开始已经支持直接获取火星坐标
    
    23.查看公众号(未添加): "menuItem:addContact"不显示,目前仅有从公众号传播出去的链接才能显示,来源必须是公众号
    
    24.ICP备案数据同步有一天延迟,所以请在第二日绑定
    

    今天我踩的坑是这样的,我用的redis然后保存到根据正式的token和ticket 然后我appid换成测试了 一直报签名错误,对比了很长时间,自己生成的和官网的一模一样就是报错。提示就是签名报错 他也不说哪里错了。

    前几天有人问我怎么申请测试公众号,只能用于开发。

    我把微信官方的地址给大家一下:https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index 直接用微信登录就可以 只能用于微信公众号开发。

    下面我给你大家截图一下我的测试号。 filefilefile

    微信公众号必不可少的工具。 下载地址:https://mp.weixin.qq.com/wiki?action=doc&id=mp1455784140&t=0.20035047813405238#5 file

    由于有公司信息我部分打码,请大家理解。


    这就是微信二次分享,哪里不懂可以私信我哦!


    鼓励作者写出更好的技术文档,就请我喝一瓶哇哈哈哈哈哈哈哈。。

    微信:

    支付宝:


    感谢一路支持我的人。。。。。
    
    Love me and hold me
    QQ:69673804(16年老号)
    EMAIL:69673804@qq.com
    友链交换
    如果有兴趣和本博客交换友链的话,请按照下面的格式在评论区进行评论,我会尽快添加上你的链接。
    

    网站名称:KingYiFan’S Blog
    网站地址:http://blog.cnbuilder.cn
    网站描述:年少是你未醒的梦话,风华是燃烬的彼岸花。
    网站Logo/头像:[头像地址](https://blog.cnbuilder.cn/upload/2018/7/avatar20180720144536200.jpg)
    
    展开全文
  • java后台生成微信中用的分享图片

    千次阅读 2018-12-29 10:31:07
    案例:   底图:     色值转换工具:http://www.atool.org/colorpicker.php ...public interface ActivityShareImageServise { ... /**生成活动分享图*/ String generateActivityShareImage(Activity...
  • 这篇文章给大家分享一下微信的web第三方登录 首先说明一下,此处登录时微信开放平台的第三方登录,和微信公众平台不一样,两个平台貌似是两拨人开发的,虽然双方最后的用户唯一标识都是openId,但是是不互通的。...
  • 该功能我在程自己在学习时候尝试搭建的,可能会有很多问题,在这里只是做一下记录。直接上代码。如有不懂请联系楼主或者加群725395843 这里是技术讨论群。供大家讨论。   此文档做回顾。 ...做之前建议先过遍文档,...
  • java微信分享源码

    2020-07-30 23:32:16
    我在网上看到没有java写的,我也下了很多但是都不能用,然后我就自己写了一份让大家看看,是用SERVLET实现的只要改一下appid和APPSECRET就可以用了。特别注意:一定要用微信已经认证后的服务号才能用。要不会一直...
  • 基于springBoot2.0以上的微信分享接口后端实现,代码绝对可复用,稍加修改就可以为您所用
  • 微信小程序java开发流程分享

    万次阅读 2017-06-05 09:49:46
    前段时间,我接触了微信的开发小程序,在开发过程中,我不得不承认微信小程序开发的简单粗暴,不多说,直接hight。 微信小程序可以去公众平台下载。有64位和32位的。在这里我就不多哔哔了。 下载完微信小程序后,...
  • Java后端技术》专注Java相关技术:SSM、Spring全家桶、微服务、MySQL、MyCat、集群、分布式、中间件、Linux、网络、多线程,偶尔讲点运维Jenkins、Nexus、Docker、ELK,偶尔分享些技术干货,致力于Java全栈开发!...
  • java 微信分享签名生成方法

    万次阅读 2015-03-30 13:47:24
    public static String getSign(String noncestrs, String jsapi_tickets, String timestamps, String urls){ String[] arr = new String[] { "jsapi_ticket="+jsapi_tickets, "noncestr="+noncestrs, "timestamp="+
  • JAVA后台实现微信自定义分享

    千次阅读 2018-06-28 20:31:50
    最近在公司接到需求实现页面在微信浏览器实现自定义分享功能,中间遇到了许多小坑,特地记录下来本人的实现过程主要参考 https://www.cnblogs.com/liuhongfeng/p/5101561.html 这篇文章,大家看的时候互为参考一下 ...
  • 从公众号,点击菜单进入一个web网站,网站某个页面加了个【分享】按钮,如何点击分享按钮,出发微信分享功能!
  • 微信小程序+java后台

    万次阅读 多人点赞 2018-03-21 21:30:58
    博主是大四学生,毕业设计做的是微信小程序+java后台。陆陆续续经历了三个月(因为白天要实习又碰上过年玩了一阵子),从对微信小程序一无所知到完成毕设,碰到许多问题,在跟大家分享一下自己的经历和一个小程序...
  • 微信公众平台开发之公众号JSSDK开发是子恒老师《微信公众平台开发》视频教程的第9部。详细讲解了用php开发微信公众号,对微信公众平台中的JSSDK开发。内容包含用JSSDK获取网络状态,地理位置,分享到朋友圈,QQ,...
  • 微信退款demo--Java

    千次阅读 2016-03-21 08:51:20
    最近开发了一个微信项目,将自己的一点经历分享给大家: 代码在csdn的资源里面: http://download.csdn.net/detail/petershusheng/9467584 修改这两个配置即可(出于安全性考虑,跟项目的相关配置都已经使用”...
  • 4、后端语言采用 JAVA 开发 5、体验此微信小程序 扫描下方二维码 6、如何联系我或需要源码进行联系 最新版表白墙博客地址 https://blog.csdn.net/huyande123/article/details/90701402 1、微信小程序前台展示 ...
  • java 微信支付 demo

    千次阅读 2019-01-29 19:30:13
    首先我只想说微信能把文档写清楚点吗?超级无敌巨坑 首先进入 微信开发者平台 https://open.weixin.qq.com/cgi-bin/index?t=home/index&amp;lang=zh_CN 点击打开链接,   然后找到 微信APP支付接入商户...
  • 微信小程序实战项目——点餐系统

    万人学习 2018-10-22 21:38:06
    实现角度出发,以“点餐系统”作为课程案例,讲解微信小程序开发的相关知识点,分享小程序开发经验。 全套课程共2个阶段:微信小程序开发教程(第1阶段)——微信小程序开发基础知识讲解,重点讲解小程序开发工具,视...
1 2 3 4 5 ... 20
收藏数 54,087
精华内容 21,634
关键字:

java微信分享