springboot+H5实现微信分享

准备工作:

1.得有一个公众号,且实名认证通过

2.配置js安全域名

配置js安全域名

3.配置APPID和AppSecret

配置APPID和AppSecret

4.配置IP白名单

配置IP白名单

微信分享需要后端支持,先上后端代码:

controller

import com.cyy.model.dto.common.ResultVo;
import com.cyy.utils.ResultVoUtil;
import io.swagger.annotations.Api;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
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;

/**
 * @Description 微信分享
 * @author cyy
 * @date 2021/2/12 21:13
 * @Param 
 * @return 
 */
@RestController
@RequestMapping("/wechat")
@CrossOrigin
@Api(value = "WechatController", tags = "微信分享")
public class WechatController {

    private static final Logger logger = LoggerFactory.getLogger(WechatController.class);

    // 公众号appid
    private static final String APPID = "这里改成你自己的";
    // 公众号开发者秘钥
    private static final String APPSECRET = "这里改成你自己的";
    private static final String GETACCESSTOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    private static final String GETTICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
    private Long TICKET_TIMESTAMP;
    private String JSAPI_TICKET;

    /**
     * @Description h5微信分享数据准备
     * @author cyy
     * @date 2021/2/12 21:16
     * @Param [url] 前端分享页面服务器路径(一定要前端获取分享页面地址,不要后端写死,写死容易造成签名错误问题出现)
     * @return UniformResultTemplate<Map<String,String>>
     */
    @RequestMapping(value = "/getShareData")
    @ResponseBody
    public ResultVo<Map<String, String>> getShareData(String url) throws IOException {
        long currentTimestamp = System.currentTimeMillis() / 1000;
        if ((StringUtils.isEmpty(JSAPI_TICKET) && TICKET_TIMESTAMP == null) || (StringUtils.isNotEmpty(JSAPI_TICKET) && TICKET_TIMESTAMP != null && TICKET_TIMESTAMP + 7200 < currentTimestamp)) {
            JSAPI_TICKET = getTicket(url);
            TICKET_TIMESTAMP = System.currentTimeMillis() / 1000;
        }
        Map<String, String> ret = sign(JSAPI_TICKET, url);
        return ResultVoUtil.success(ret);
    }

    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;

        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("app_id", APPID);
        ret.put("nonceStr", nonce_str);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);

        return ret;
    }

    private static String create_nonce_str() {
      String uuid = UUID.randomUUID().toString().replace("-","");
        return uuid.substring(0, 15).toUpperCase();
    }

    private static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

    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 getTicket(String url) throws IOException {
        // 获取“access_token”,建议放于缓存或者数据库中,定时刷新
        logger.error("参数url: {}", url);
        String getAccessTokenPath = GETACCESSTOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET);
        logger.error("参数getAccessTokenPath: {}", getAccessTokenPath);
        com.alibaba.fastjson.JSONObject jsonObject = doGetStr(getAccessTokenPath);
        logger.error("参数jsonObject: {}", jsonObject);
        String access_token = jsonObject.getString("access_token");
        logger.error("参数access_token: {}", access_token);
        // 根据“access_token”获取“jsapi_ticket”
        String getTicketPath = GETTICKET_URL.replace("ACCESS_TOKEN", access_token);
        logger.error("参数getTicketPath: {}", getTicketPath);
        com.alibaba.fastjson.JSONObject jsonObject1 = doGetStr(getTicketPath);
        logger.error("参数jsonObject1: {}", jsonObject1);
        String ticket = jsonObject1.getString("ticket");
        logger.error("参数ticket: {}", ticket);
        return ticket;
    }

    /**
     * 编写Get请求的方法。但没有参数传递的时候,可以使用Get请求
     *
     * @param url 需要请求的URL
     * @return 将请求URL后返回的数据,转为JSON格式,并return
     */
    public static JSONObject doGetStr(String url) throws IOException {
      DefaultHttpClient client = new DefaultHttpClient();//获取DefaultHttpClient请求
      HttpGet httpGet = new HttpGet(url);//HttpGet将使用Get方式发送请求URL
      JSONObject jsonObject = null;
      HttpResponse response = client.execute(httpGet);//使用HttpResponse接收client执行httpGet的结果
      HttpEntity entity = response.getEntity();//从response中获取结果,类型为HttpEntity
      if (entity != null) {
          String result = EntityUtils.toString(entity, "UTF-8");//HttpEntity转为字符串类型
          jsonObject = JSONObject.parseObject(result);//字符串类型转为JSON类型
      }
      return jsonObject;
  }

}

再来编写前端的

<script type="text/javascript" src="https://res2.wx.qq.com/open/js/jweixin-1.4.0.js"></script>

async setUpWechatShared () {
        let that = this;
        await this.$get('/wechat/getShareData?url=' + window.location.href)
          .then((res) => {
            wx.config({
              debug: false,
              appId: res.data.data.app_id,
              timestamp: res.data.data.timestamp,
              nonceStr: res.data.data.nonceStr,
              signature: res.data.data.signature,
              jsApiList: [
                'checkJsApi',
                'onMenuShareTimeline',
                'onMenuShareAppMessage'
              ]
            });
            wx.ready(function() {
              let url = window.location.href.indexOf('?') ? window.location.href.split('?')[0] : window.location.href;
              wx.onMenuShareTimeline({
                title: that.newsDetail.title || '', // 分享标题
                link: url, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                imgUrl: 'https://www.tootootool.com/wp-content/uploads/2020/10/cropped-logo-1.png', // 分享图标
                success: function() {
                  // 用户确认分享后执行的回调函数
                }
              });
              wx.onMenuShareAppMessage({
                title: that.newsDetail.title || '', // 分享标题
                desc: that.newsDetail.summary || '', // 分享描述
                link: url, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                imgUrl: 'https://www.tootootool.com/wp-content/uploads/2020/10/cropped-logo-1.png', // 分享图标
                success: function() {
                  // 用户确认分享后执行的回调函数
                }
              });
            });
          }).catch(error => {
            console.error('接口:/api/wechat/config,' + error)
          })
      }

页面加载时,请求接口

页面加载时,请求接口

可以在微信这里校验我们生产的和微信的是否一致

https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

可以在微信这里校验我们生产的和微信的是否一致

最终,在微信里分享会如下:

springboot+H5实现微信分享
原文链接:,转发请注明来源!

发表评论