当前位置: 首页 > news >正文

java实现微信小程序获取手机号(htts接口实现)

这篇文章记录一下自己写小程序后台时,如何通过https接口获取到用户手机号。大概流程如下:
1、获取通过认证的appId和secret;
2、利用appId和secret获取accessToken;
3、前端获取到用户的code;
4、通过code和accessToken获取手机号。
appId和secret是在微信公众平台上各种验证之后得到的。

一、小程序端获取code

参考来源: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
使用说明:
需要将 button 组件 open-type 的值设置为 getPhoneNumber,当用户点击并同意之后,可以通过 bindgetphonenumber 事件回调获取到动态令牌code,然后把code传到开发者后台,并在开发者后台调用微信后台提供的 phonenumber.getPhoneNumber 接口,消费code来换取用户手机号。每个code有效期为5分钟,且只能消费一次。
注: getPhoneNumber 返回的 code 与 wx.login 返回的 code 作用是不一样的,不能混用。
代码示例:

<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
Page({
  getPhoneNumber (e) {
    console.log(e.detail.code)
  }
})

二、java获取accessToken和phone

参考:
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/phonenumber/phonenumber.getPhoneNumber.html
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
我这里直接上代码:

1、http调用代码

/**
 * HTTP/HTTPS 请求封装: GET / POST
 * 默认失败重试3次
 * @author admin
 */
@Slf4j
public class HttpClientSslUtils {

	/**
	 * 默认的字符编码格式
	 */
	private static final String DEFAULT_CHAR_SET = "UTF-8";
	/**
	 * 默认连接超时时间 (毫秒)
	 */
	private static final Integer DEFAULT_CONNECTION_TIME_OUT = 2000;
	/**
	 * 默认socket超时时间 (毫秒)
	 */
	private static final Integer DEFAULT_SOCKET_TIME_OUT = 3000;

	/** socketTimeOut上限 */
	private static final Integer SOCKET_TIME_OUT_UPPER_LIMIT = 10000;

	/** socketTimeOut下限 */
	private static final Integer SOCKET_TIME_OUT_LOWER_LIMIT = 1000;

	private static CloseableHttpClient getHttpClient() {
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(DEFAULT_SOCKET_TIME_OUT)
			.setConnectTimeout(DEFAULT_CONNECTION_TIME_OUT).build();
		return HttpClients.custom().setDefaultRequestConfig(requestConfig)
			.setRetryHandler(new DefaultHttpRequestRetryHandler()).build();
	}

	private static CloseableHttpClient getHttpClient(Integer socketTimeOut) {
		RequestConfig requestConfig =
			RequestConfig.custom().setSocketTimeout(socketTimeOut).setConnectTimeout(DEFAULT_CONNECTION_TIME_OUT)
				.build();
		return HttpClients.custom().setDefaultRequestConfig(requestConfig)
			.setRetryHandler(new DefaultHttpRequestRetryHandler()).build();
	}

	public static String doPost(String url, String requestBody) throws Exception {
		return doPost(url, requestBody, ContentType.APPLICATION_JSON);
	}

	public static String doPost(String url, String requestBody, Integer socketTimeOut) throws Exception {
		return doPost(url, requestBody, ContentType.APPLICATION_JSON, null, socketTimeOut);
	}

	public static String doPost(String url, String requestBody, ContentType contentType) throws Exception {
		return doPost(url, requestBody, contentType, null);
	}

	public static String doPost(String url, String requestBody, List<BasicHeader> headers) throws Exception {
		return doPost(url, requestBody, ContentType.APPLICATION_JSON, headers);
	}

	public static String doPost(String url, String requestBody, ContentType contentType, List<BasicHeader> headers)
		throws Exception {
		return doPost(url, requestBody, contentType, headers, getHttpClient());
	}

	public static String doPost(String url, String requestBody, ContentType contentType, List<BasicHeader> headers,
                                Integer socketTimeOut) throws Exception {
		if (socketTimeOut < SOCKET_TIME_OUT_LOWER_LIMIT || socketTimeOut > SOCKET_TIME_OUT_UPPER_LIMIT) {
			log.error("socketTimeOut非法");
			throw new Exception();
		}
		return doPost(url, requestBody, contentType, headers, getHttpClient(socketTimeOut));
	}


	/**
	 * 通用Post远程服务请求
	 * @param url
	 * 	请求url地址
	 * @param requestBody
	 * 	请求体body
	 * @param contentType
	 * 	内容类型
	 * @param headers
	 * 	请求头
	 * @return String 业务自行解析
	 * @throws Exception
	 */
	public static String doPost(String url, String requestBody, ContentType contentType, List<BasicHeader> headers,
                                CloseableHttpClient client) throws Exception {

		// 构造http方法,设置请求和传输超时时间,重试3次
		CloseableHttpResponse response = null;
		long startTime = System.currentTimeMillis();
		try {
			HttpPost post = new HttpPost(url);
			if (!CollectionUtils.isEmpty(headers)) {
				for (BasicHeader header : headers) {
					post.setHeader(header);
				}
			}
			StringEntity entity =
				new StringEntity(requestBody, ContentType.create(contentType.getMimeType(), DEFAULT_CHAR_SET));
			post.setEntity(entity);
			response = client.execute(post);
			if (response.getStatusLine().getStatusCode() != HttpStatus.OK.value()) {
				log.error("业务请求返回失败:{}", EntityUtils.toString(response.getEntity()));
				throw new Exception();
			}
			String result = EntityUtils.toString(response.getEntity());
			return result;
		} finally {
			releaseResourceAndLog(url, requestBody, response, startTime);
		}
	}

	/**
	 * 暂时用于智慧园区业务联调方式
	 * @param url 业务请求url
	 * @param param 业务参数
	 * @return
	 * @throws Exception
	 */
    public static String doPostWithUrlEncoded(String url,
                                              Map<String, String> param) throws Exception {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = getHttpClient();
        CloseableHttpResponse response = null;
        long startTime = System.currentTimeMillis();
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表
            if (param != null) {
                List<org.apache.http.NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList, DEFAULT_CHAR_SET);
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() != HttpStatus.OK.value()) {
				log.error("业务请求返回失败:{}" , EntityUtils.toString(response.getEntity()));
				throw new Exception();
            }
            String resultString = EntityUtils.toString(response.getEntity(), DEFAULT_CHAR_SET);
            return resultString;
        } finally {
            releaseResourceAndLog(url, param == null ? null : param.toString(), response, startTime);
        }
    }

	private static void releaseResourceAndLog(String url, String request, CloseableHttpResponse response, long startTime) {
		if (null != response) {
			try {
				response.close();
				recordInterfaceLog(startTime, url, request);
			} catch (IOException e) {
				log.error(e.getMessage());
			}
		}
	}

	public static String doGet(String url) throws Exception {
		return doGet(url, ContentType.DEFAULT_TEXT);
	}

	public static String doGet(String url, ContentType contentType) throws Exception {
		return doGet(url, contentType, null);
	}

	public static String doGet(String url, List<BasicHeader> headers) throws Exception {
		return doGet(url, ContentType.DEFAULT_TEXT, headers);
	}

	/**
	 * 通用Get远程服务请求
	 * @param url
	 * 	请求参数
	 * @param contentType
	 * 	请求参数类型
	 * @param headers
	 * 	请求头可以填充
	 * @return String 业务自行解析数据
	 * @throws Exception
	 */
	public static String doGet(String url, ContentType contentType, List<BasicHeader> headers) throws Exception {
		CloseableHttpResponse response = null;
		long startTime = System.currentTimeMillis();
		try {
			CloseableHttpClient client = getHttpClient();
			HttpGet httpGet = new HttpGet(url);
			if (!CollectionUtils.isEmpty(headers)) {
				for (BasicHeader header : headers) {
					httpGet.setHeader(header);
				}
			}
			if(contentType != null){
				httpGet.setHeader("Content-Type", contentType.getMimeType());
			}
			response = client.execute(httpGet);
			if (response.getStatusLine().getStatusCode() != HttpStatus.OK.value()) {
				log.error("业务请求返回失败:{}", EntityUtils.toString(response.getEntity()));
				throw new Exception();
			}
			String result = EntityUtils.toString(response.getEntity());
			return result;
		} finally {
			releaseResourceAndLog(url, null, response, startTime);
		}
	}

	private static void recordInterfaceLog(long startTime, String url, String request) {
		long endTime = System.currentTimeMillis();
		long timeCost = endTime - startTime;
		MDC.put("totalTime", String.valueOf(timeCost));
		MDC.put("url", url);
		MDC.put("logType", "third-platform-service");
		log.info("HttpClientSslUtils 远程请求:{} 参数:{} 耗时:{}ms", url, request, timeCost);
	}
}

2、json转换工具类

@Slf4j
public class JsonUtil {

    /**
     * 定义映射对象
     */
    public static ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 日期格式化
     */
    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    static {
        //对象的所有字段全部列入
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        //取消默认转换timestamps形式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //忽略空Bean转json的错误
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        //所有的日期格式都统一为以下的样式,即yyyy-MM-dd HH:mm:ss
        objectMapper.setDateFormat(new SimpleDateFormat(DATE_FORMAT));
        //忽略 在json字符串中存在,但是在java对象中不存在对应属性的情况。防止错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    }

    /**
     * string转JsonNode
     *
     * @param jsonString
     * @return com.fasterxml.jackson.databind.JsonNode
     */
    public static JsonNode stringToJsonNode(String jsonString) throws JsonProcessingException {

        return objectMapper.readTree(jsonString);

    }

    /**
     * 对象转json字符串
     *
     * @param obj
     * @param <T>
     */
    public static <T> String objToString(T obj) {

        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.warn("Parse Object to String error : {}", e.getMessage());
            return null;
        }
    }

    /**
     * 对象转格式化的字符串字符串
     *
     * @param obj
     * @param <T>
     * @return
     */
    public static <T> String objToPrettyString(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.warn("Parse Object to String error : {}", e.getMessage());
            return null;
        }
    }

    /**
     * json字符串转对象
     *
     * @param jsonString
     * @param cls
     * @param <T>
     */
    public static <T> T stringToObj(String jsonString, Class<T> cls) {
        if (StringUtils.isEmpty(jsonString) || cls == null) {
            return null;
        }
        try {
            return cls.equals(String.class) ? (T) jsonString : objectMapper.readValue(jsonString, cls);
        } catch (JsonProcessingException e) {
            log.warn("Parse String to Object error : {}", e.getMessage());
            return null;
        }
    }

    /**
     * json字符串转对象(复杂泛型类型)
     *
     * @param jsonString
     * @param typeReference
     * @param <T>
     * @return
     */
    public static <T> T stringToObj(String jsonString, TypeReference<T> typeReference) {
        if (StringUtils.isEmpty(jsonString) || typeReference == null) {
            return null;
        }
        try {
            return typeReference.getType().equals(String.class) ? (T) jsonString : objectMapper.readValue(jsonString, typeReference);
        } catch (JsonProcessingException e) {
            log.warn("Parse String to Object error : {}", e.getMessage());
            return null;
        }
    }
}

3、获取accessToken和phone

 public JSONObject getPhoneNumber(String code) {
        JSONObject phone;
        // 获取token
        String token_url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", APPID, SECRET);
        try {
            JSONObject token = JSON.parseObject(HttpClientSslUtils.doGet(token_url));
            if (token == null) {
                log.info("获取token失败");
                return null;
            }
            String accessToken = token.getString("access_token");
            if (StringUtils.isEmpty(accessToken)) {
                log.info("获取token失败");
                return null;
            }
            log.info("token : {}", accessToken);
            //获取phone
            String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber"
                    + "?access_token=" + accessToken;
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", code);
            String reqJsonStr = JsonUtil.objToString(jsonObject);
            phone = JSON.parseObject(HttpClientSslUtils.doPost(url, reqJsonStr));

            if (phone == null) {
                log.info("获取手机号失败");
                return null;
            }
            return phone;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

记得导入jar包:

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>

到此搞定!

相关文章:

  • 亚马逊,速卖通,国际站卖家为什么要做测评
  • Centos7搭建sftp服务器,开启SFTP上报日志
  • 模式识别课程混合式教学设计
  • 基于云原生的视频管理系统设计与实现
  • AOP的使用(详细讲解)
  • DES加密算法安全吗,有哪些优点和缺点?
  • AI智能分析网关包含哪些深度学习算法?如何赋能场景应用?
  • JavaEE图书管理项目
  • SpringBoot Web开发----Thymeleaf的简单入门
  • Object Detection in 20 Years: A Survey
  • 出现次数最多的数字和次数
  • 多账号自动下单
  • opencv调整图像亮度和对比度,以及opencv种的做法
  • django之静态文件配置 请求方式 request对象方法 pycharm连接数据库 django连接MySQL 初识ORM
  • 自动控制原理6.3---串联校正
  • Android组件 - 收藏集 - 掘金
  • Elasticsearch 参考指南(升级前重新索引)
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • Flex布局到底解决了什么问题
  • Java反射-动态类加载和重新加载
  • macOS 中 shell 创建文件夹及文件并 VS Code 打开
  • nginx 配置多 域名 + 多 https
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • Odoo domain写法及运用
  • Python爬虫--- 1.3 BS4库的解析器
  • RxJS: 简单入门
  • scrapy学习之路4(itemloder的使用)
  • spring学习第二天
  • 彻底搞懂浏览器Event-loop
  • 从setTimeout-setInterval看JS线程
  • 订阅Forge Viewer所有的事件
  • 对象引论
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 十年未变!安全,谁之责?(下)
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 关于Android全面屏虚拟导航栏的适配总结
  • 如何正确理解,内页权重高于首页?
  • 说说我为什么看好Spring Cloud Alibaba
  • ​linux启动进程的方式
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (独孤九剑)--文件系统
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (附源码)计算机毕业设计ssm电影分享网站
  • (转) Android中ViewStub组件使用
  • (转)Sublime Text3配置Lua运行环境
  • (转)编辑寄语:因为爱心,所以美丽
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .NET Framework Client Profile - a Subset of the .NET Framework Redistribution
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NET 发展历程
  • .net 设置默认首页
  • .Net 应用中使用dot trace进行性能诊断
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • .net(C#)中String.Format如何使用
  • .netcore如何运行环境安装到Linux服务器