• 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>
    
    • 1
    Page({
      getPhoneNumber (e) {
        console.log(e.detail.code)
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    二、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);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222

    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 
         */
        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 
         * @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 
         */
        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 
         * @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;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116

    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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    记得导入jar包:

    <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.76</version>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    到此搞定!

  • 相关阅读:
    ORA-09925 Unable to create audit trail file
    ceres 损失函数loss_function小结
    14种UML图(统一建模语言)
    IBM Spectrum LSF 重要的目录和配置文件
    Mybatis-plus中更新date类型数据遇到的坑
    记录一些 PostgreSQL问题分析思路
    顶级人工智能会议接收率及信息
    C# 修改打印机名称
    香港高端人才通行证计划申请(包括条件)你需要知道的这些真相!
    《计算之魂》读书笔记
  • 原文地址:https://blog.csdn.net/liwangcuihua/article/details/126620778