springboot 解析微信小程序获取手机号

引用依赖包

 <dependency><groupId>bouncycastle</groupId><artifactId>bcprov-jdk14</artifactId><version>138</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.80</version></dependency><dependency><groupId>io.github.admin4j</groupId><artifactId>http</artifactId><version>0.4.6</version></dependency><!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --><!--解密依赖包--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.4.0</version></dependency><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.70</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.80</version><scope>compile</scope></dependency>

AccountInfo


public class AccountInfo {public static  String grantType="client_credential";public static String appId="";  //public static String appSecret="";  //public static String accessTokenUrl="https://api.weixin.qq.com/cgi-bin/token" ;public static  String getPhoneNumberUrl="https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=";}

接口

  if (code == null || code.length() == 0) {return  null;}String wxAppid = AccountInfo.appId;// 小程序的 app secret (在微信小程序管理后台获取)String wxSecret = AccountInfo.appSecret;// 授权(必填)String grant_type = AccountInfo.grantType;// 请求参数String params = "appid=" + wxAppid + "&secret=" + wxSecret + "&grant_type="+ grant_type;try {String sr = HttpRequest.sendGetSSL(AccountInfo.accessTokenUrl, params);JSONObject json = null;System.out.println("sr");System.out.println(sr);json = JSON.parseObject(sr);String access_token = (String) json.get("access_token");String jsonData = "{\"code\":\"" + telCode + "\"}";Object data = JSON.parse(jsonData);String sr1 = HttpRequest.sendPostSSl(AccountInfo.getPhoneNumberUrl + access_token, data);System.out.println("sr1");System.out.println(sr1);json = JSON.parseObject(sr1);Integer errcode = (Integer) json.get("errcode");if (errcode== 0) {String tel = (String) JSON.parseObject(json.get("phone_info").toString()).get("phoneNumber");//去数据库里面查询if (tel == null || tel.equals("")) {return null;}} else {}} catch (Exception e) {return  null;}

HttpRequest

public class HttpRequest {public static void main(String[] args) {//发送 GET 请求String s=HttpRequest.sendGet("http://v.qq.com/x/cover/kvehb7okfxqstmc.html?vid=e01957zem6o", "");System.out.println(s);//        //发送 POST 请求
//        String sr=HttpRequest.sendPost("http://www.toutiao.com/stream/widget/local_weather/data/?city=%E4%B8%8A%E6%B5%B7", "");
//        JSONObject json = JSONObject.fromObject(sr);
//        System.out.println(json.get("data"));}/*** 向指定URL发送GET方法的请求** @param url*            发送请求的URL* @param param*            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。* @return URL 所代表远程资源的响应结果*/public static String sendGet(String url, String param) {String result = "";BufferedReader in = null;try {String urlNameString = url + "?" + param;URL realUrl = new URL(urlNameString);// 打开和URL之间的连接URLConnection connection = realUrl.openConnection();// 设置通用的请求属性connection.setRequestProperty("accept", "*/*");connection.setRequestProperty("connection", "Keep-Alive");connection.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");// 建立实际的连接connection.connect();// 获取所有响应头字段Map<String, List<String>> map = connection.getHeaderFields();// 遍历所有的响应头字段for (String key : map.keySet()) {System.out.println(key + "--->" + map.get(key));}// 定义 BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(connection.getInputStream()));String line;while ((line = in.readLine()) != null) {result += line;}} catch (Exception e) {System.out.println("发送GET请求出现异常!" + e);e.printStackTrace();}// 使用finally块来关闭输入流finally {try {if (in != null) {in.close();}} catch (Exception e2) {e2.printStackTrace();}}System.out.println("result");System.out.println(result);return result;}/***  http get请求 请求参数在url后面拼接*  @throws Exception*/public static String sendGetSSl(String requestUrl, String param,Map<String,String> header) throws Exception{HttpsURLConnection conn = null;InputStream input = null;BufferedReader br = null;StringBuffer buffer = null;try {SSLContext sc = SSLContext.getInstance("SSL");sc.init(null, new TrustManager[] { new TrustAnyTrustManager() },new java.security.SecureRandom());HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());String urlNameString = requestUrl + "?" + param;URL url = new URL(urlNameString);conn = (HttpsURLConnection) url.openConnection();conn.setSSLSocketFactory(sc.getSocketFactory());conn.setHostnameVerifier(new TrustAnyHostnameVerifier());conn.setDoOutput(false);conn.setDoInput(true);conn.setUseCaches(false);conn.setConnectTimeout(1000 * 100);conn.setReadTimeout(1000 * 100);conn.setRequestMethod("GET");conn.setRequestProperty("Accept", "*/*");conn.setRequestProperty("Connection", "keep-alive");conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");conn.setRequestProperty("Charset", "UTF-8");conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");//添加headerif(header != null){for(Map.Entry<String, String> entry : header.entrySet()){String mapKey = entry.getKey();String mapValue = entry.getValue();conn.setRequestProperty(mapKey, mapValue);}}conn.connect();// 读取服务器端返回的内容System.out.println("======================响应体=========================");System.out.println("ResponseCode:" + conn.getResponseCode() + ",ResponseMessage:" + conn.getResponseMessage());if(conn.getResponseCode()==200){input = conn.getInputStream();}else{input = conn.getErrorStream();}br = new BufferedReader(new InputStreamReader(input, "UTF-8"));buffer = new StringBuffer();String line = null;while ((line = br.readLine()) != null) {buffer.append(line);}System.out.println("返回报文:" + buffer.toString());} catch (Exception e) {System.out.println("发送GET请求出现异常!" + e);e.printStackTrace();} finally {try {if (conn != null) {conn.disconnect();conn = null;}if (br != null) {br.close();br = null;}} catch (IOException ex) {throw new Exception(ex);}}return buffer.toString();}public static String sendGetSSL(String requestUrl,String param){String urlNameString = requestUrl + "?" + param;Response response = HttpUtil.get(urlNameString);ResponseBody responseBody = response.body();okio.BufferedSource source = responseBody.source();try {source.request(Long.MAX_VALUE); // Buffer the entire body.okio.Buffer buffer = source.buffer();Charset charset = StandardCharsets.UTF_8;MediaType contentType = responseBody.contentType();if (contentType != null) {charset = contentType.charset(StandardCharsets.UTF_8);}return buffer.clone().readString(charset);} catch (IOException e) {throw new RuntimeException(e);}}public static String sendPostSSl(String requestUrl,Object body){Response response= HttpUtil.post(requestUrl, body);ResponseBody responseBody = response.body();okio.BufferedSource source = responseBody.source();try {source.request(Long.MAX_VALUE); // Buffer the entire body.okio.Buffer buffer = source.buffer();Charset charset = StandardCharsets.UTF_8;MediaType contentType = responseBody.contentType();if (contentType != null) {charset = contentType.charset(StandardCharsets.UTF_8);}return buffer.clone().readString(charset);} catch (IOException e) {throw new RuntimeException(e);}}/*** 向指定 URL 发送POST方法的请求** @param url*            发送请求的 URL* @param param*            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。* @return 所代表远程资源的响应结果*/public static String sendPost(String url, String param) {PrintWriter out = null;BufferedReader in = null;String result = "";try {URL realUrl = new URL(url);// 打开和URL之间的连接URLConnection conn = realUrl.openConnection();// 设置通用的请求属性conn.setRequestProperty("accept", "*/*");conn.setRequestProperty("connection", "Keep-Alive");conn.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");// 发送POST请求必须设置如下两行conn.setDoOutput(true);conn.setDoInput(true);// 获取URLConnection对象对应的输出流out = new PrintWriter(conn.getOutputStream());// 发送请求参数out.print(param);// flush输出流的缓冲out.flush();// 定义BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(conn.getInputStream()));String line;while ((line = in.readLine()) != null) {result += line;}} catch (Exception e) {System.out.println("发送 POST 请求出现异常!"+e);e.printStackTrace();}//使用finally块来关闭输出流、输入流finally{try{if(out!=null){out.close();}if(in!=null){in.close();}}catch(IOException ex){ex.printStackTrace();}}return result;}
}

TrustAnyHostnameVerifier

public class TrustAnyHostnameVerifier implements HostnameVerifier {public boolean verify(String hname, SSLSession session) {return true;}
}

TrustAnyTrustManager

public class TrustAnyTrustManager implements X509TrustManager {public  void checkClientTrusted(java.security.cert.X509Certificate[] var1, String var2) throws java.security.cert.CertificateException{}public void checkServerTrusted(java.security.cert.X509Certificate[] var1, String var2) throws java.security.cert.CertificateException{}public java.security.cert.X509Certificate[] getAcceptedIssuers(){return null;}
}

WeChatUtil

public class WeChatUtil {/*** 请求微信接口服务,获取 openid,session_key,unionid,errcode,errmsg* https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html** @param jscode* @return*/public static JSONObject getSessionByCode(String jscode) {// jscode是前端请求wx.login()方法获取的code;不是getPhoneNumber接口获取的code// wx.login()方法,需要最先调用,否则可能会报错:pad block corrupted,获取不到解密的信息String baseUrl = "https://api.weixin.qq.com/sns/jscode2session";HashMap<String, Object> requestParam = new HashMap<>();// 小程序 appIdrequestParam.put("appid",  AccountInfo.appId);// 小程序 appSecretrequestParam.put("secret",  AccountInfo.appSecret);// 登录时获取的 code(小程序端返回的code)requestParam.put("js_code", jscode);// 默认参数,填“authorization_code”requestParam.put("grant_type", "authorization_code");// 发送post请求读取调用微信接口获取openid用户唯一标识String result = HttpUtil.get(baseUrl, requestParam);return JSONUtil.parseObj(result);}/*** 解密:通过加密密钥,iv偏移量来解密 encryptedData* 根据encryptedData的不同,解密出来的json数据结构不同(数据结构的详情需要看前端调用的是哪个微信的接口,获取用户哪些信息)** @param encryptData* @param sessionKey* @param iv* @return*/public static JSONObject getUserInfo(String encryptData, String sessionKey, String iv) {// 解密:被加密的数据byte[] dataByte = Base64.decode(encryptData);// 解密:加密密钥byte[] keyByte = Base64.decode(sessionKey);// 解密:偏移量byte[] ivByte = Base64.decode(iv);try {// 如果密钥不足16位,那么就补足。// 这个if中的内容很重要int base = 16;if (keyByte.length % base != 0) {int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);byte[] temp = new byte[groups * base];Arrays.fill(temp, (byte) 0);System.arraycopy(keyByte, 0, temp, 0, keyByte.length);keyByte = temp;}// 初始化Security.addProvider(new BouncyCastleProvider());KeyGenerator.getInstance("AES").init(128);// 生成ivAlgorithmParameters iv1 = AlgorithmParameters.getInstance("AES");iv1.init(new IvParameterSpec(ivByte));// 生成解密SecretKeySpec secretKeySpec = new SecretKeySpec(keyByte, "AES");Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv1);// 设置为解密模式byte[] decryptByte = cipher.doFinal(dataByte);if (null != decryptByte && decryptByte.length > 0) {String result = new String(decryptByte, "UTF-8");return JSONUtil.parseObj(result);}} catch (Exception e) {e.printStackTrace();}return null;}
}