springboot实现微信分享接口

去微信官方文档了解。

概述 | 微信开放文档

 首先:去微信公众号平台测试系统拿到appID和appsecret,并且配置js域名

 如果测试暂时没有域名可以参考下面链接教程

外网映射Sunny-Ngrok_小小舍的博客-优快云博客

根据文档描述准备签名等数据

微信相关配置 :

package io.lease.common.config;

/**
 * Created by xxs on 2021/11/18 20:12
 *
 * @Description
 */
public class WxShareConfig {

    /**
     *  微信appid
     */
    public static final String appid = "wx8d1eab965e66105a";

    /**
     *  微信appsecret
     */
    public static final String appsecret = "8e9bc82ce46195795a8a5950859679b4";

    /**
     *  获取token请求地址
     */
    public static final String getTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?";

    /**
     *  获取jsapi_ticket请求地址
     */
    public static final String getTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?";
}

请求封装:

package io.lease.modules.weixin.wxShare;

import com.alibaba.fastjson.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by xxs on 2021/11/18 17:04
 *
 * @Description
 */
public class WeixinUtil {

    public static JSONObject doGet(String httpurl) {
        HttpURLConnection connection = null;
        InputStream is = null;
        BufferedReader br = null;
        String result = null;// 返回结果字符串
        try {
            // 创建远程url连接对象
            URL url = new URL(httpurl);
            // 通过远程url连接对象打开一个连接,强转成httpURLConnection类
            connection = (HttpURLConnection) url.openConnection();
            // 设置连接方式:get
            connection.setRequestMethod("GET");
            // 设置连接主机服务器的超时时间:15000毫秒
            connection.setConnectTimeout(15000);
            // 设置读取远程返回的数据时间:60000毫秒
            connection.setReadTimeout(60000);
            // 发送请求
            connection.connect();
            // 通过connection连接,获取输入流
            if (connection.getResponseCode() == 200) {
                is = connection.getInputStream();
                // 封装输入流is,并指定字符集
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                // 存放数据
                StringBuffer sbf = new StringBuffer();
                String temp = null;
                while ((temp = br.readLine()) != null) {
                    sbf.append(temp);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            connection.disconnect();// 关闭远程连接
        }
        JSONObject jsonObject = JSONObject.parseObject(result);
        return jsonObject;
    }
}

签名数据返回对象封装:

package io.lease.modules.sys.vo;

import lombok.Data;

/**
 * Created by xxs on 2021/11/18 16:03
 *
 * @Description 分享信息
 */
@Data
public class ShareInfoVO {

    private String appId;
    private String nonceStr;
    private String timeStamp;
    private String sign;
}
package io.lease.modules.weixin.wxShare;

import com.alibaba.fastjson.JSONObject;
import io.lease.common.config.WxShareConfig;
import io.lease.modules.sys.vo.ShareInfoVO;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.UUID;

/**
 * Created by xxs on 2021/11/18 17:01
 *
 * @Description
 */
public class WXShare {

   

     public static String byteToHex(final byte[] hash) {
        StringBuffer stringBuffer = new StringBuffer();
        for (int i=0; i<hash.length;i++){
            String hexString = Integer.toHexString(hash[i] & 0xFF);
            if (hexString.length() < 2){
                stringBuffer.append(0);
            }
            stringBuffer.append(hexString);
        }

        return stringBuffer.toString();

    }
}

签名数据获取,封装service接口

package io.lease.modules.weixin.wxShare;

import io.lease.modules.sys.dto.ShareInfoDTO;
import io.lease.modules.sys.vo.ShareInfoVO;

/**
 * Created by xxs on 2021/11/18 20:16
 *
 * @Description
 */
public interface WXShareService {


    /**
    * @param shareInfoDTO
    * @Description:  获取微信配置
    */
    ShareInfoVO getWxConfig(ShareInfoDTO shareInfoDTO);
}

实现接口(核心):

package io.lease.modules.weixin.wxShare;

import com.alibaba.fastjson.JSONObject;
import io.lease.common.config.WxShareConfig;
import io.lease.modules.sys.dto.ShareInfoDTO;
import io.lease.modules.sys.vo.ShareInfoVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;

/**
 * Created by xxs on 2021/11/18 20:17
 *
 * @Description
 */
@Service
public class WXShareServiceImpl implements WXShareService {


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

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String ACCESS_TOKEN = "ACCESS_TOKEN";

    private static final String JS_API_TICKET = "JS_API_TICKET";

    @Override
    public ShareInfoVO getWxConfig(ShareInfoDTO shareInfoDTO) {
        ShareInfoVO shareInfoVO = new ShareInfoVO();

        String timestamp = getTimestamp(); // 必填,生成签名的时间戳
        String nonceStr = getNonceStr(); // 必填,生成签名的随机串

        //获取jsapi_ticket
        String jsApiTicket = getJsApiTicket();

        //生成JS-SDK权限验证的签名
        String signature = "";
        //注意这里参数名必须全部小写,且必须有序
        String sign = "jsapi_ticket=" + jsApiTicket
                +"&noncestr=" + nonceStr
                + "&timestamp=" + timestamp
                +"&url=" + shareInfoDTO.getUrl();
        try{
            //进行sha1签名
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(sign.getBytes("UTF-8"));
            signature = WXShare.byteToHex(crypt.digest());
        }catch (NoSuchAlgorithmException e){
            e.printStackTrace();
        }catch (UnsupportedEncodingException e){
            e.printStackTrace();
        }
        shareInfoVO.setAppId(WxShareConfig.appid);
        shareInfoVO.setTimeStamp(timestamp);
        shareInfoVO.setNonceStr(nonceStr);
        shareInfoVO.setSign(signature);
        return shareInfoVO;
    }


    /**
    * @param
    * @Description:  获取token
    */
    private String getAccessToken() {
        String accessToken = redisTemplate.opsForValue().get(ACCESS_TOKEN);
        if (!StringUtils.isNotBlank(accessToken)){
            //缓存无,重新获取token
            String url = WxShareConfig.getTokenUrl
                    + "grant_type=client_credential&appid=" + WxShareConfig.appid + "&secret=" + WxShareConfig.appsecret;
            JSONObject json = WeixinUtil.doGet(url);
            if (json != null) {
                accessToken = json.getString("access_token");
                Integer time = Integer.parseInt(json.getString("expires_in"));
                redisTemplate.opsForValue().set(ACCESS_TOKEN,accessToken,time - 3600);
            }
        }
        logger.info("getAccessToken access_token: {}", accessToken);
        return accessToken.trim();
    }


    /**
     * @param
     * @Description:  获取ticket
     */
    private String getJsApiTicket() {
        String jsApiTicket = redisTemplate.opsForValue().get(JS_API_TICKET);
        if (!StringUtils.isNotBlank(jsApiTicket)){
            //获取全局的access_token,唯一票据
            String accessToken = getAccessToken();
            if (StringUtils.isNotBlank(accessToken)) {
                //获取jsapi_ticket
                String url = WxShareConfig.getTicketUrl+"access_token="+accessToken+"&type=jsapi";
                JSONObject json = WeixinUtil.doGet(url);
                if (json != null) {
                    jsApiTicket = json.getString("ticket");
                    Integer time = Integer.parseInt(json.getString("expires_in"));
                    redisTemplate.opsForValue().set(JS_API_TICKET,jsApiTicket,time - 3600);
                }
            }
        }
        logger.info("getJsApiTicket jsApiTicket: {}", jsApiTicket);
        return jsApiTicket.trim();
    }


    /**
    * @param
    * @Description:  获取随机字符串
    */
    private static String getNonceStr() {
        return UUID.randomUUID().toString();
    }


    /**
    * @param
    * @Description:  获取时间戳
    */
    private static String getTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

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

controller:

package io.lease.controller;


@RestController
@RequestMapping("/api/goods")
@Api(tags = "商品接口")
public class ApiGoodsController {
    private static final Logger log = LoggerFactory.getLogger(ApiGoodsController.class);


    @Autowired
    private WXShareService wxShareService;

    

    @PostMapping("getShareInfo")
    @ApiOperation("获取分享配置信息 - H5")
    public R getShareInfo(@RequestBody ShareInfoDTO shareInfoDTO){
        log.info("getShareInfo  shareInfoDTO: {}", JSONObject.toJSONString(shareInfoDTO));
        return R.ok(wxShareService.getWxConfig(shareInfoDTO));
    }

}

写一个页面测试:

<!doctype html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport"
			content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title>分享</title>
	</head>
	<body></body>
</html>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="http://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script>

	/* 获取微信配置并注入 */
	(function getWxConfig(){
		let data = {
			url: location.href
		}
		$.ajax({
			url:"http://xxs.free.idcfengye.com/lease-api/api/goods/getShareInfo",
			type:"post",
			dataType:"json",
			data:JSON.stringify(data),
			headers:{
				"Content-Type":"application/json"
			},
			success:res=>{
			const { data } = res
			wx.config({
				debug: true,
				appId: data.appId,
				timestamp: data.timeStamp,
				nonceStr: data.nonceStr,
				signature: data.sign,
				jsApiList: ["updateAppMessageShareData","updateTimelineShareData"]
			});
	}
	})
	})()
	
	wx.ready(()=>{
		let shareConfig = {
			title:"分享标题",
			desc:"分享内容",

			link:"http://xxs.free.idcfengye.com/h5Share.html", //必须是JS接口安全域名
			imgUrl:"https://img2.baidu.com/it/u=3989369665,3150123550&fm=253&fmt=auto&app=120&f=JPEG?w=690&h=460"
		}
		/* 分享给朋友 */
		wx.updateAppMessageShareData(shareConfig)
		/* 分享到朋友圈 */
		wx.updateTimelineShareData(shareConfig)
	})
	
	
</script>

添加依赖:

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

写测试接口访问页面:

package io.lease.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletResponse;

/**
 * Created by xxs on 2021/11/18 17:57
 *
 * @Description
 */
@Controller
public class TestController {


    @RequestMapping("/test")
    public String test(HttpServletResponse response)  {
        return "H5Share";
    }
}

访问测试接口即可。

http://xxs.free.idcfengye.com/lease-api/test

综合文档及下图可知,成功了。

若页面url拼接多个参数时,会出现的问题及解决方案:

微信分享url带多个参数问题解决_小小舍的博客-优快云博客

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值