手把手教你使用java对接微信公众号-获取地理位置信息 - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 公众号相关 >

手把手教你使用java对接微信公众号-获取地理位置信息

发表时间:2020-10-19

发布人:葵宇科技

浏览次数:70

公众号需要定位当前用户的地址位置,需要通过签名后返回的数据,前端将参数回调到微信服务器获取地理位置信息,官方文档说明(https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html)。

这里会告诉你对接JSSDK使用步骤

可以看出调用JSSDK需要后端提供四个参数:

  appId: '', // 必填,公众号的唯一标识
  timestamp: , // 必填,生成签名的时间戳
  nonceStr: '', // 必填,生成签名的随机串
  signature: '',// 必填,签名

1、编写后端的签名接口SysWxUserController

前端的url需要encodeURIComponent),因为页面一旦分享,微信客户端会在你的链接末尾加入其它参数,如果不是动态获取当前链接,将导致分享后的页面签名失败。

package com.sx.local.govern.controller;


import com.sx.common.result.RestResponse;
import com.sx.common.result.ResultGenerator;
import com.sx.local.govern.service.SysWxUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;


/**
 * <p>
 * 微信用户信息表 前端控制器
 * </p>
 *
 * @author lst
 * @since 2020-08-29
 */
@RestController
@RequestMapping("/wx-user")
@Api(value = "SysWxUserController", tags = "微信用户")
public class SysWxUserController {

    @Autowired
    private SysWxUserService sysWxUserService;

    /**
     * @Description 获取微信地理位置需要的签名信息
     * @author lst
     * @date 2020-9-25 17:34
     * @param url 当前网页的URL,不包含#及其后面部分
     * @return com.sx.common.result.RestResponse
     */
    @GetMapping(value = "/get-config", produces = "application/json; charset=utf-8")
    @ApiOperation(value = "获取微信地理位置需要的签名信息", notes = "获取微信地理位置需要的签名信息", code = 200, produces = "application/json")
    @ApiImplicitParam(paramType = "query", dataType = "string", name = "url",required = true ,value = "当前网页的URL,不包含#及其后面部分")
    public RestResponse getConfig(@RequestParam("url") String url) {
        return  ResultGenerator.genSuccessResult(sysWxUserService.getConfig(url));
    }

}

2、SysWxUserServiceImpl

package com.sx.local.govern.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sx.common.config.GlobalConfig;
import com.sx.common.constants.Constant;
import com.sx.common.constants.SymbolConstants;
import com.sx.common.exception.SxException;
import com.sx.common.util.HttpClientUtil;
import com.sx.common.util.RedisUtil;
import com.sx.common.util.StringUtil;
import com.sx.local.govern.constants.WxCommonConstants;
import com.sx.local.govern.entity.SysWxUser;
import com.sx.local.govern.exceptionhandler.GovernExceptionEnum;
import com.sx.local.govern.form.WxUserForm;
import com.sx.local.govern.mapper.SysWxUserMapper;
import com.sx.local.govern.service.SysWxUserService;
import com.sx.local.govern.utils.ShaUtil;
import com.sx.system.constants.SystemCommonConstants;
import com.sx.system.entity.SysArea;
import com.sx.system.exceptionhandler.SysExceptionEnum;
import com.sx.system.mapper.SysAreaMapper;
import com.sx.system.shiro.jwt.JwtUtil;
import com.sx.system.vo.WxUserVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 微信用户信息表 服务实现类
 * </p>
 *
 * @author lst
 * @since 2020-08-29
 */
@Service
@Slf4j
public class SysWxUserServiceImpl extends ServiceImpl<SysWxUserMapper, SysWxUser> implements SysWxUserService {


    @Autowired
    private RedisUtil redisUtil;

    /**
     * @Description 获取微信地理位置需要的签名信息
     * 微信 JS 接口签名校验工具: http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
     * @author lst
     * @date 2020-9-25 17:29
     * @param url 当前网页的URL,不包含#及其后面部分
     * @return java.util.Map<java.lang.String,java.lang.Object>
     */
    @Override
    public Map<String,Object> getConfig(String url){
        Map<String,Object> resultMap = new HashMap<String,Object>();
        String timeStamp = String.valueOf(ShaUtil.getCurrentTimestamp());
        String nonceStr = ShaUtil.generateNonceStr();
        String jsapiTicket = getTicket();
        String signature = getSign(timeStamp,nonceStr,jsapiTicket,url);
        resultMap.put("appId",GlobalConfig.getConfig("wx.appid"));
        resultMap.put("timestamp",timeStamp);
        resultMap.put("nonceStr",nonceStr);
        resultMap.put("signature",signature);
        return resultMap;
    }

    /**
     * @Description 获取签名
     * @author lst
     * @date 2020-9-25 17:22
     * @param timeStamp 当前时间戳,单位毫秒
     * @param nonceStr 获取随机字符串
     * @param jsapiTicket ticket
     * @param url 当前网页的URL,不包含#及其后面部分
     * @return java.lang.String
     */
    private static String getSign(String timeStamp,String nonceStr,String jsapiTicket,String url){
        String arr[] =new String[] {"jsapi_ticket="+jsapiTicket,"noncestr="+nonceStr,"timestamp="+timeStamp,"url="+url};
        //字典序排序
        Arrays.sort(arr);
        String str = "";
        str = arr[0]+"&"+arr[1]+"&"+arr[2]+"&"+arr[3];
        log.info("str:{}",str);
        String mParms = null;//sha1加密
        MessageDigest digest = null;
        try {
            digest = java.security.MessageDigest.getInstance("SHA");
        } catch (NoSuchAlgorithmException e) {
            log.error("错误信息:{}",e);
            throw new SxException(GovernExceptionEnum.PARAM_NOT_EXIST.getCode(),e.getMessage());
        }
        digest.update(str.getBytes());
        byte messageDigest[] = digest.digest();
        // Create Hex String
        StringBuffer hexString = new StringBuffer();
        for (int i = 0; i < messageDigest.length; i++) {
            String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
            if (shaHex.length() < 2) {
                hexString.append(0);
            }
            hexString.append(shaHex);
        }
        mParms = hexString.toString();
        log.info("签名:{}",mParms);
        return mParms;
    }


    /**
     * @Description 通过access_token获取 ticket
     * @author lst
     * @date 2020-9-25 17:22
     * @return java.lang.String
     */
    private String getTicket(){
        JSONObject jsonObject = (JSONObject) redisUtil.getValue(WxCommonConstants.WX_ACCESS_TOKEN);
        Map<String,Object> resultMap = new HashMap<String,Object>();
        //access_token 获取
        if(null == jsonObject){
            Map<String,Object> params = new HashMap<String,Object>();
            String url = WxCommonConstants.GET_ACCESS_TOKEN_URL_BY_BACKSTAGE;
            String appId = GlobalConfig.getConfig("wx.appid");
            String appSecret = GlobalConfig.getConfig("wx.appsecret");
            params.put("appid",appId);
            params.put("secret",appSecret);
            params.put("grant_type","client_credential");
            jsonObject = JSONObject.parseObject(HttpClientUtil.doHttpsGet(url,params));
            if(StringUtil.isEmpty(jsonObject.get("access_token"))){
                throw new SxException(GovernExceptionEnum.WXUSER_OPENID_NOT_EXIST);
            }
            Integer expiresIn = (Integer) jsonObject.get("expires_in");
            redisUtil.setValue(WxCommonConstants.WX_ACCESS_TOKEN,jsonObject, Long.valueOf(expiresIn));
        }
        log.info("通过code换取access_token、openID:{}",jsonObject);
        //ticket 获取
        String accessToken = (String) jsonObject.get("access_token");
        JSONObject jsonTicket = (JSONObject) redisUtil.getValue(WxCommonConstants.GET_TICKET);
        if(null == jsonTicket){
            Map<String,Object> params = new HashMap<String,Object>();
            String url = WxCommonConstants.GET_TICKET_URL;
            params.put("access_token",accessToken);
            params.put("type","jsapi");
            jsonTicket = JSONObject.parseObject(HttpClientUtil.doHttpsGet(url,params));
            if(StringUtil.isEmpty(jsonTicket.get("ticket"))){
                throw new SxException(GovernExceptionEnum.WXUSER_OPENID_NOT_EXIST);
            }
            Integer expiresIn = (Integer) jsonTicket.get("expires_in");
            redisUtil.setValue(WxCommonConstants.GET_TICKET,jsonTicket,Long.valueOf(expiresIn));
        }
        log.info("获取jsonTicket:{}",jsonTicket);
        String ticket = (String) jsonTicket.get("ticket");
        return ticket;
    }

}

3、ShaUtil工具类

package com.sx.local.govern.utils;

import lombok.extern.slf4j.Slf4j;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.UUID;

/**
 * @Description: 用SHA1算法验证Token
 * @Author: lst
 * @Date 2020-08-18
 */
@Slf4j
public class ShaUtil {

    /**
     * @Description  用SHA1算法验证Token
     * @author lst
     * @date 2020-8-20 11:30
     * @param token url相关的token
     * @param timestamp 时间戳
     * @param nonce 随机数
     * @return java.lang.String
     */
    public static String getSHA1(String token, String timestamp, String nonce){

        String[] arr = new String[] { token, timestamp, nonce };
        Arrays.sort(arr);
        //TODO 2. 将三个参数字符串拼接成一个字符串进行sha1加密
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        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) {
            log.info("错误信息:{}",e.getMessage());
        }

        return tmpStr;
    }

    /**
     * @Description 将字节数组转换为十六进制字符串
     * @author lst
     * @date 2020-8-18 11:56
     * @param byteArray
     * @return java.lang.String
     */
    public static String byteToStr(byte[] byteArray) {
        StringBuilder strDigest = new StringBuilder();
        for (int i = 0; i < byteArray.length; i++) {
            strDigest.append(byteToHexStr(byteArray[i]));
        }
        return strDigest.toString();
    }

    /**
     * @Description  将字节转换为十六进制字符串
     * @author lst
     * @date 2020-8-18 11:57
     * @param mByte
     * @return java.lang.String
     */
    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;
    }

    /**
     * @Description 获取当前时间戳,单位秒
     * @author lst
     * @date 2020-9-25 16:35
     * @return long
     */
    public static long getCurrentTimestamp() {
        return System.currentTimeMillis()/1000;
    }

    /**
     * @Description 获取随机字符串 Nonce Str
     * @author lst
     * @date 2020-9-25 16:35
     * @return java.lang.String
     */
    public static String generateNonceStr() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
    }
}

4、测试

5、通过微信 JS 接口签名校验工具验证(http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

相关案例查看更多