java微信分享

微信参考文档https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html

微信官方文档

步骤一:绑定域名

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

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

        添加步骤:

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

            2.添加项目访问域名地址,点击保存。
 

步骤二:引入JS文件

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

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.4.0.js (支持https)。

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

 

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

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

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

签名算法见文末的附录1,所有JS接口列表见文末的附录2

 

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

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

 

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

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

 代码:

前端页面  

需要引入http://res.wx.qq.com/open/js/jweixin-1.4.0.js

<script>
    
     $(function(){
            $.ajax({
                type : "post",
                url : "/wx/wxShare",
                dataType : "json",
                async : true,
                data:{url:'需要分享页面的url'},
                success : function(data) {
                wx.config({
                        debug: false,生产环境需要关闭debug模式
                        appId: data.appid,//appId通过微信服务号后台查看
                        timestamp: data.timestamp,//生成签名的时间戳
                        nonceStr: data.nonceStr,//生成签名的随机字符串
                        signature: data.signature,//签名
                        jsApiList: [//需要调用的JS接口列表
                            'checkJsApi',//判断当前客户端版本是否支持指定JS接口
                            'onMenuShareTimeline',//分享给好友
                            'onMenuShareAppMessage'//分享到朋友圈
                        ]
                    });
                },
                error: function(xhr, status, error) {
                   // alert(status);
                    //alert(xhr.responseText);
                }
            })
            wx.ready(function () {
                wx.onMenuShareTimeline({
                   title: '',//分享的标题
                    desc: '朋友圈都被这个刷屏了,你也来晒一晒吧~', // 分享描述
                    link:'',  //注意这里最好是http访问全路径 要不容易出问题 
                    imgUrl: '', // 分享图标 http访问全路径
                    success: function () { 
                        // 用户确认分享后执行的回调函数
                        //alert("分享成功");

                    }
                    cancel: function () { 
                        // 用户取消分享后执行的回调函数
                        //alert("取消分享");
                    }  
                });
              //分享给朋友
              wx.onMenuShareAppMessage({
                     title: '',
                    desc: '朋友圈都被这个刷屏了,你也来晒一晒吧~', // 分享描述
                    link:'',
                    imgUrl: '', // 分享图标 // 分享图标
                    type: '', // 分享类型,music、video或link,不填默认为link
                    dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
                    success: function () { 
                        // 用户确认分享后执行的回调函数
                    },
                    cancel: function () { 
                        // 用户取消分享后执行的回调函数
                    }
                });
                wx.error(function (res) {
                   // alert(res.errMsg);
                });
            });
        });
  </script>

后台


import com.ljzforum.base.enums.APIResponseCode;
import com.ljzforum.base.vo.APIResultVo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author : 恒果果
 * create at:  2019-12-09  10:48
 * @description: 微信分享等
 */
@RestController
public class WxController {

    @Resource
    private WXIConfig wxiConfig;

    @RequestMapping("/wxShare")
    public ModelAndView wxShare(String url){
    ModelAndView  view = new ModelAndView();
    view.addObject("data",wxShareN(url))
    return view ;
    }
}



    /**
     * 微信分享
     */
    public LinkedHashMap<String,Object> wxShareN(String url) {
        //微信分享
        LinkedHashMap<String,Object> map = new LinkedHashMap<>();

        try {
            String ticket = wxService.getJssdkTicketN();
            String shareUrl = url;
            map.put("appId", wxiConfig.getAppId());
            Map<String, String> signMap = WxJSSDKSign.sign(ticket, shareUrl);
            map.put("signMap",signMap);
        } catch (Exception e) {
            log.error("获取微信的JSSDK接口失败........", e);
        }
        return map;
    }

WXIConfig 


import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ljzforum.common.constant.RedisContent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 微信接口的服务信息
 *
 * @author
 */
@Service
@Slf4j
public class WxService {
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private WXIConfig wxiConfig;

    /**
     * 获取JSSDK的秘钥
     */
    public String getJssdkTicket(String access_token) {
        String ticket = (String) redisTemplate.opsForValue().get(RedisContent.WX_OPEN_TOKEN_TICKET + access_token);
        if (ticket == null) {
            Map<String, Object> params = new LinkedHashMap<String, Object>();
            params.put("access_token", access_token);
            params.put("type", "jsapi");
            JSONObject result = JSONUtil.parseObj(HttpUtil.get(WXIConfig.WX_JS_SDK_GET_TICKET, params));
            if (result.containsKey("errcode") && !result.getStr("errmsg").equals("ok")) {
                log.error("获取ticket出错:" + result.toString());
                return null;
            }
            ticket = result.getStr("ticket");
            redisTemplate.opsForValue().set(RedisContent.WX_OPEN_TOKEN_TICKET + access_token, ticket, 30, TimeUnit.MINUTES);
        }
        return ticket;
    }

    /**
     * 获取JSSDK的秘钥
     */
    public String getJssdkTicket() {
        String access_token = getCgiBinTokenN();
        if (access_token == null) {
            return null;
        }

        String ticket;
        try {
            ticket = getJssdkTicket(access_token);
        } catch (Exception e) {
            log.error("redisL里的的token不正确,重新从接口获取token");
            access_token = getCgiBinTokenN();
            ticket = getJssdkTicket(access_token);
        }
        return ticket;
    }

    /**
     * 获取Token数据
     */
    public String getCgiBinTokenN() {
        String access_token = (String) redisTemplate.opsForValue().get(RedisContent.WX_CGI_BIN_TOKEN + wxiConfig.getAppId());
        if (access_token == null) {
            Map<String, Object> params = new LinkedHashMap<String, Object>();
            params.put("grant_type", "client_credential");
            params.put("appid", wxiConfig.getAppId());
            params.put("secret", wxiConfig.getAppSecret());
            JSONObject result = JSONUtil.parseObj(HttpUtil.get(WXIConfig.WX_CGI_BIN_GET_TOKEN, params));
            if (result.containsKey("errcode") && result.getStr("errcode") != null) {
                result = JSONUtil.parseObj(HttpUtil.get(WXIConfig.WX_CGI_BIN_GET_TOKEN, params));
            }
            access_token = result.getStr("access_token");
            redisTemplate.opsForValue().set(RedisContent.WX_CGI_BIN_TOKEN + wxiConfig.getAppId(), access_token, 30, TimeUnit.MINUTES);
        }
        return access_token;
    }

   
   

   }
   
WXIConfig


import com.ljzforum.common.util.CustomizedPropertyConfigurer;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Data
@Component
public class WXIConfig {

    //微信支付分配的商户号
    @Value("${mch_id}")
    public String mchId;
    //支付的私人秘钥
    @Value("${app_pay_key}")
    public String appPayKey;
    //获取APPID
    @Value("${app_id}")
    public String appId;
    //获取微信APP_SECRET
    @Value("${app_secret}")
    public String appSecret;
    //获取小程序APPID
    @Value("${mini_appid}")
    public String miniAppid;
    //获取小程序SECRET
    @Value("${mini_secret}")
    public String miniSecret;

    //临时的整型参数值
    public static String QR_SCENE = "QR_SCENE";
    //临时的字符串参数值
    public static String QR_STR_SCENE = "QR_STR_SCENE";
    //永久的整型参数值
    public static String QR_LIMIT_SCENE = "QR_LIMIT_SCENE";
    //永久的字符串参数值
    public static String QR_LIMIT_STR_SCENE = "QR_LIMIT_STR_SCENE";

    //统一下单
    public static String WX_UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    //获取access token
    public static String WX_TOKEN = "https://api.weixin.qq.com/cgi-bin/token";
    //获取微信服务器IP地址
    public static String WX_TOKEN_CALLBACK_IP = "https://api.weixin.qq.com/cgi-bin/getcallbackip";
    //用户同意授权,获取code
    public static String WX_GET_USERINFO_AUTHORIZE = "https://open.weixin.qq.com/connect/oauth2/authorize";
    //通过code换取网页授权access_token
    public static String WX_GET_USERINFO_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token";
    //刷新access_token(如果需要)
    public static String WX_GET_USERINFO_REFRESH_TOKEN = "https://api.weixin.qq.com/sns/oauth2/refresh_token";
    //刷新拉取用户信息(需scope为 snsapi_userinfo)
    public static String WX_GET_USERINFO = "https://api.weixin.qq.com/sns/userinfo";
    //通过access_token、openid获取用户信息
    public static String WX_GET_INFO = "https://api.weixin.qq.com/cgi-bin/user/info";
    //获取微信用户素材
    public static String WX_BATCH_GET_MATERIAL = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=";
    //获取微信用户素材总数
    public static String WX_GET_MATERIAL_COUNT = "https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=";
    //获取微信永久素材
    public static String WX_GET_MATERIAL = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=";
    //创建微信菜单
    public static String WX_CREATE_MENU = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=";
    //查询微信菜单
    public static String WX_GET_MENU = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=";
    //删除微信菜单
    public static String WX_DELETE_MENU = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=";
    //微信退款
    public static String WX_REFUND_URL = "https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=";
    //获取access_toke
    public static String WX_CGI_BIN_GET_TOKEN = "https://api.weixin.qq.com/cgi-bin/token";
    //长链接转短链接接口
    public static String WX_GET_SHORT_URL = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token=";
    //新增其他类型永久素材
    public static String WX_MATERIAL_ADD_MATERIAL = "http://api.weixin.qq.com/cgi-bin/material/add_material?access_token=%1s&type=%2s";

    /**
     * 获取JSSDK调研说需要的钥匙
     */
    public static String WX_JS_SDK_GET_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";


    //微信开放平台公众号消息加解密Key
    public static String WX_PLATFORM_ENCODING_AES_KEY = (String) CustomizedPropertyConfigurer.getContextProperty("wx_platform_encoding_aes_key");
    //微信开放平台公众号消息校验Token
    public static String WX_PLATFORM_TOKEN = (String) CustomizedPropertyConfigurer.getContextProperty("wx_platform_token");
    //微信开放平台APPID
    public static String WX_PLATFORM_APP_ID = (String) CustomizedPropertyConfigurer.getContextProperty("wx_platform_app_id");
    //微信开放平台AppSecret
    public static String WX_PLATFORM_APP_SECRET = (String) CustomizedPropertyConfigurer.getContextProperty("wx_platform_app_secret");
    //获取第三方平台component_access_token
    public static String WX_GET_COMPONENT_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";
    //获取预授权码pre_auth_code
    public static String WX_GET_PRE_AUTH_CODE = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=";
    //获取公众号的接口调用凭据和授权信息
    public static String WX_API_QUERY_AUTH = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=";

    public static String WX_API_REFRESH_TOKEN = "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token=";
    public static String WX_GET_AUTHORIZER_INFO = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token=";


    /**
     * 微信通知信息推送模版
     */
    //模版id
    public static String WX_TEMPLATE_ID_SUCCESS_SIGNUP = "w64cYpbQWD65KR6cziKipXNnBowEOSheqc7uoKUTR70";
    public static String WX_TEMPLATE_ID_ACTIVITY_MESSAGE = "jVXOi_SxSpGA9t9dHCHA7Ss50a4Y8KPLFVnCas5EaIc";
    //发送模版信息
    public static String WX_SEND_TEMPLATE = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";

    //微信短链生成接口
    public static String WX_SHORT_URL = "https://api.weixin.qq.com/cgi-bin/shorturl?access_token=";
    public static String USER_LIST_URL = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=";


    //生成带参数的二维码
    public static String WX_QRCODE_URL = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=";
    //通过ticket换取二维码
    public static String WX_CGI_BIN_QRCODE = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=";


    //客服接口-发消息
    public static String WX_SEND_MSG_CUSTOM = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=";


    //图片
    public static String WX_MATERIAL_IMAGE = "image";
    //语音
    public static String WX_MATERIAL_VOICE = "voice";
    //视频
    public static String WX_MATERIAL_VIDEO = "video";
    //缩略图
    public static String WX_MATERIAL_THUMB = "thumb";
}
WxJSSDKSign

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class WxJSSDKSign {
	public static void main(String[] args) {
		String jsapi_ticket = "jsapi_ticket";
		// 注意 URL 一定要动态获取,不能 hardcode
		String url = "http://example.com";
		Map<String, String> ret = sign(jsapi_ticket, url);
		for (Map.Entry entry : ret.entrySet()) {
			System.out.println(entry.getKey() + ", " + entry.getValue());
		}
	};

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

注意事项:

JAVA, Node, Python 部分代码只实现了签名算法,需要开发者传入 jsapi_ticket 和 url ,其中 jsapi_ticket 需要通过 http://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=ACCESS_TOKEN 接口获取 url 为调用页面的完整 url 。

PHP 部分代码包括了获取 access_token 和 jsapi_ticket 的操作,只需传入 appid 和 appsecret 即可,但要注意如果已有其他业务需要使用 access_token 的话,应修改获取 access_token 部分代码从全局缓存中获取,防止重复获取 access_token ,超过调用频率。

注意事项:
1. jsapi_ticket 的有效期为 7200 秒,开发者必须全局缓存 jsapi_ticket ,防止超过调用频率。
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值