微信开发

刚刚写了一个微信开发的项目,今天就来讲一讲微信开发的内容。

微信登录

首先微信开发最开始的部分当然是微信登录

需要注意的地方,一定要把白名单开了,该配置的东西配置好。

	微信登录流程:
		1、引导用户进入授权页面同意授权,获取code
		2、通过code换取网页授权access_token(与基础支持中的access_token不同)
		3、如果需要,开发者可以刷新网页授权access_token,避免过期
		4、通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)
		步骤1为前端处理,前端将获取的code调用后端写好的登录接口,在这个接口中
接口如下
 		// 获取当前登录人的openid officialAppId和officialAppSecret为项目公众号唯一标识和公众号的appsecret
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+officialAppId+"&secret="+officialAppSecret+
                "&code="+code+"&grant_type=authorization_code";
        String result = HttpUtils.get(url);
        OfficialVO wxCodeResponse = JSONObject.parseObject(result, OfficialVO.class);
        // 公众号登录token获取错误信息
        if(StringUtils.isNotBlank(wxCodeResponse.getErrmsg())){
            return GeneralResult.error(ErrorCode.NOT_TOKEN);
        }
        String path = "https://api.weixin.qq.com/sns/userinfo?access_token="+wxCodeResponse.getAccess_token()+"&openid="+wxCodeResponse.getOpenid()+"&lang=zh_CN";
        String s = HttpUtils.get(path);
        // 用户信息
        UserinformationVO userinfoVO = JSONObject.parseObject(s, UserinformationVO.class);
        // 用户信息获取的错误信息
        if(StringUtils.isNotBlank(userinfoVO.getErrmsg())){
            return GeneralResult.error(ErrorCode.NOT_USER);
        }
        // 后面就是项目中用微信表关联用户表的信息详细步骤了

OfficialVO类封装的字段

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class OfficialVO {
    private String access_token;
    private Integer expires_in;
    private String refresh_token;
    private String openid;
    private String scope;
    private Integer errcode;
    private String errmsg;
    private String subscribe;
    private String unionid;
}

UserinformationVO封装的字段

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class UserinformationVO {
    private String openid;
    private String nickname;
    private Integer sex;
    private String province;
    private String city;
    private String country;
    private String headimgurl;
    private String unionid;
    private String errmsg;
    private Integer errcode;
}

上面就是微信登录整体功能,具体开发文档点击查看
因为这个项目功能是进行投票功能,为了防止恶意的调用该接口,进行浏览器类型判断

	/**
     * 通过请求头判断是否是微信内置浏览器,是否是在微信内打开
     * @param request
     * @return
     */
    @RequestMapping(value = "/hello")
    public String hello(HttpServletRequest request){
        String ua = request.getHeader("user-agent")
                .toLowerCase();
        if (ua.indexOf("micromessenger") <= 0){
            return "不是微信内置浏览器";
        }
        return "微信内置浏览器";
    }

这样就可以将不是微信内置浏览器的请求拦截下来。

微信开发批量获取关注的用户列表(缺陷)

文档详情

该方法上限是10000条数据,并且其中参数next_openid是第一个拉取的OPENID,不填默认从头开始拉取
https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
当看到这个方法,正常人都会觉得这个openid是按创建时间排序的,直接用最后一个openid获取看有没有新的关注用户就可以,其实这个不是按创建时间排序,并且官方文档没有任何的提示。
在拉取关注用户时需要从头拉去关注的用户,如果用户存在则更新,用户不存在则保存。
配合该接口https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN,可以获取更加全的用户信息,方便操作

以下方法是将关注的用户信息,批量保存或更新到本地数据库中

	/**
     * 批量获取用户数据
     * @return
     */
    public void userInfos(){
        subscriptionDao.deleteUnioniid();
        LOGGER.info("开始调用订阅号接口获取用户信息:"+ DateUtils.getCurrentTimeStr());
        // 获取普通token成功
        String commonToken = null;
        try {
            commonToken = cacheService.get(SUBSCRIPTION_TOKEN, String.class);
        } catch (Exception e) {
            LOGGER.error("Redis获取公众号标识异常:{}",e);
        }
        if(commonToken == null) {
            // 调用通用token
            String url1 = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + subscriptionAppId + "&secret=" + subscriptionAppSecret;
            String result1 = HttpUtils.get(url1);
            LoginVO commonLoginVO = JSONObject.parseObject(result1, LoginVO.class);
            commonToken = commonLoginVO.getAccess_token();
            // 存储token
            try {
                cacheService.setWithExpireTime(SUBSCRIPTION_TOKEN, commonToken, HOURS, TimeUnit.HOURS);
            } catch (Exception e) {
                LOGGER.error("Redis存储异常{}",e);
            }
        }
        // 批量拉去关注用户openid,NEXT_OPENID为头openid
        String path = "https://api.weixin.qq.com/cgi-bin/user/get?access_token="+commonToken+"&next_openid=";
        String s1 = HttpUtils.get(path);
        Map map2 = JSONObject.parseObject(s1, Map.class);
        Integer count = Integer.valueOf(map2.get("count").toString());
        String o =  map2.get("data").toString();
        Map map1 = JSONObject.parseObject(o, Map.class);
        String openidS = map1.get("openid").toString();
        List<String> list1 = JSONObject.parseObject(openidS, List.class);
        List<UserInfosVO> userinfos = new ArrayList<>();
        for(String str:list1){
            userinfos.add(UserInfosVO.builder().openid(str).lang("zh_CN").build());
            if(userinfos.size()%100==0){
                setUser(userinfos);
                userinfos.clear();
            }
        }
        if(userinfos.size()!=0){
            setUser(userinfos);
        }
        // 用户数据保存完成
        if(count < 10000){
            return;
        }else{
            String nextOpenid = (String) map2.get("next_openid");
            circulation(nextOpenid);
        }
    }

	/**
     * 循环调用方法获取用户openid 关注用户大于10000时使用
     * @param nextOpenid
     */
    public void circulation(String nextOpenid){
    	// 获取普通token
        String commonToken = null;
        try {
            commonToken = cacheService.get(SUBSCRIPTION_TOKEN, String.class);
            LOGGER.info("成功:{}",commonToken);
        } catch (Exception e) {
            LOGGER.error("Redis获取公众号标识异常:{}",e);
        }
        if(commonToken == null) {
            // 获取通用token
            String url1 = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + subscriptionAppId + "&secret=" + subscriptionAppSecret;
            String result1 = HttpUtils.get(url1);
            LoginVO commonLoginVO = JSONObject.parseObject(result1, LoginVO.class);
            commonToken = commonLoginVO.getAccess_token();
            // 存储token到redis中
            try {
                cacheService.setWithExpireTime(SUBSCRIPTION_TOKEN, commonToken, HOURS, TimeUnit.HOURS);
            } catch (Exception e) {
                LOGGER.error("Redis存储异常{}",e);
            }
        }
        // 批量拉去关注用户openid,NEXT_OPENID为头openid
        // https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
        String path = "https://api.weixin.qq.com/cgi-bin/user/get?access_token="+commonToken+"&next_openid="+nextOpenid;
        String s1 = HttpUtils.get(path);
        Map map2 = JSONObject.parseObject(s1, Map.class);
        Integer count = Integer.valueOf(map2.get("count").toString());
        String o =  map2.get("data").toString();
        Map map1 = JSONObject.parseObject(o, Map.class);
        String openidS = map1.get("openid").toString();
        List<String> list1 = JSONObject.parseObject(openidS, List.class);
        List<UserInfosVO> userinfos = new ArrayList<>();
        for(String str:list1){
            userinfos.add(UserInfosVO.builder().openid(str).lang("zh_CN").build());
            if(userinfos.size()%100==0){
                setUser(userinfos);
                userinfos.clear();
            }
        }
        if(userinfos.size()!=0){
            setUser(userinfos);
        }
        // 用户数据保存完成
        if(count < 10000){
            return;
        }else{
            String Openid = (String) map2.get("next_openid");
            circulation(Openid);
        }
    }

 	/**
     * 保存用户信息
     * @param userinfos
     */
    public void setUser(List<UserInfosVO> userinfos){
        String commonToken = null;
        try {
            commonToken = cacheService.get(SUBSCRIPTION_TOKEN, String.class);
            LOGGER.info("获取普通token成功:{}",commonToken);
        } catch (Exception e) {
            LOGGER.error("Redis获取公众号标识异常:{}",e);
        }
        if(commonToken == null) {
            // 调用通用token
            String url1 = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + subscriptionAppId + "&secret=" + subscriptionAppSecret;
            String result1 = HttpUtils.get(url1);
            LoginVO commonLoginVO = JSONObject.parseObject(result1, LoginVO.class);
            commonToken = commonLoginVO.getAccess_token();
            // 存储token
            try {
                cacheService.setWithExpireTime(SUBSCRIPTION_TOKEN, commonToken, HOURS, TimeUnit.HOURS);
            } catch (Exception e) {
                LOGGER.error("Redis存储异常{}",e);
            }
        }
        Map<String,Object> map = new HashMap<>();
        map.put("user_list",userinfos);
        String paramsJson = JSON.toJSONString(map);
        // 批量获取用户数据
        String url = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token="+commonToken;
        String post = HttpUtils.post(url, paramsJson);
        Map map3 = JSONObject.parseObject(post, Map.class);
        String user_info_list = map3.get("user_info_list").toString();
        JSONObject.parseObject(post, Map.class);
        JSONArray jsonArray= JSONArray.parseArray(user_info_list);
        for(int i=0;i<jsonArray.size();i++){
            SubscriptionUserPO subscriptionUser = JSONObject.parseObject(jsonArray.get(i).toString(), SubscriptionUserPO.class);
            SubscriptionUserPO subscriptionUserPO = subscriptionDao.selectOne(new QueryWrapper<SubscriptionUserPO>().lambda().eq(SubscriptionUserPO::getOpenid, subscriptionUser.getOpenid()));
            if(subscriptionUserPO ==null){
                subscriptionUser.setCreateTime(LocalDateTime.now());
                subscriptionDao.save(subscriptionUser);
            }
//            // 更新用户数据操作
//            else{
//                subscriptionUser.setUpdateTime(LocalDateTime.now());
//                subscriptionUser.setSubscriptionUserId(subscriptionUser.getSubscriptionUserId());
//                subscriptionDao.updateById(subscriptionUser);
//            }
        }
    }

微信页面跳转小程序

文档

需要获取一个公众号标识,一定要开通微信公众号跳转小程序的配置,血的教训

获取公众号标识方法如下

/**
     * 获取公众号标识
     * @return
     * url 请求路径
     */
    public GeneralResult jsapi(String url){
        String commonToken = null;
        try {
            commonToken = cacheService.get(OFFICIAL_TOKEN, String.class);
            LOGGER.info("获取普通token成功:{}",commonToken);
        } catch (Exception e) {
            LOGGER.error("Redis获取公众号标识异常:{}",e);
        }
        if(commonToken == null){
            // 获取普通token
            String url1 = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + officialAppId + "&secret=" + officialAppSecret;
            String result1 = HttpUtils.get(url1);
            LOGGER.info("获取公众号标识result1:{}",result1);
            LoginVO commonLoginVO = JSONObject.parseObject(result1, LoginVO.class);
            commonToken = commonLoginVO.getAccess_token();
            try {
                cacheService.setWithExpireTime(OFFICIAL_TOKEN, commonToken, HOURS, TimeUnit.HOURS);
            } catch (Exception e) {
                LOGGER.error("Redis存储公众号标识异常:{}",e);
            }
        }
        // 获取jsapi_ticket
        String url2 = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+commonToken+"&type=jsapi";
        String result = HttpUtils.get(url2);
        LOGGER.info("获取公众号标识result{}",result);
        JsapiVO jsapiVO = JSONObject.parseObject(result, JsapiVO.class);
        Map<String, String> sign = sign(jsapiVO.getTicket(), url);
        return GeneralResult.response(sign);

    }

    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);
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值