微信小程序获取用户手机号码,Java后台servlet解密(微信小程序调用微信支付也是大致的流程)

本篇记录说明

微信小程序获取用户手机号码,Java后台servlet解密(微信小程序调用微信支付也是大致的流程,详细内容可私信交流

(第一次写博客,写得不好的地方见谅,面向新手,大佬请无视,不喜勿喷)

一、前言: 

微信小程序有一个获取用户手机号码很便捷的接口,通过getPhoneNumber获取用户的已经绑定微信的手机号码。

现在微信和注重用户体验,必须要用户主动触发才可以。必须使用 open-type="getPhoneNumber" 的按钮来触发。

二、实现步骤:

1、通过wx.login获取【code】;

2、通过getPhoneNumber获取【encryptedData】 、【iv】;(ps:切记第1步和第2步的顺序不能颠倒,先调用wx.login,把wx.login写在onload方法里面;然后再通过getPhoneNumber获取【encryptedData】 、【iv】)

3、通过wx.request将【encryptedData】 、【iv】 、【code】发送到Java后台;

4、Java后台使用【code】,请求微信后台登录凭证校验接口auth.code2Session,获取【openid】和【sessionKey】返回Java后台;

5、Java后台使用【encryptedData】、【iv】、【sessionKey】解密获取用户手机号返回给微信小程序。(ps:微信给的后台解密示例代码里面没有Java,是的,你没有看错,没有Java。)

三、代码展示

1、小程序代码如下:

(1)getPhoneNumber.wxml

<view class='header'>

</view>


<view class='text_view'>
 
  <text>申请获取以下权限</text>
</view>


<view class='content'>
  <text>获得您的信息(手机号码等)</text>
</view>

<button class='bottom' type='primary' lang="zh_CN" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">
  获取手机号码
</button>

<view class='problem'>
  <text>登陆遇到问题?点此联系客服</text>
  <button class='contact-btn' open-type='contact'>a</button>
</view>




<view bindtap="cooperate" class='cooperate-phonenumber'>
  
</view>

(2)getPhoneNumber.wxss

page {
  /* background-color: #eee; */
  height: 100%;
  overflow: hidden;
}


.header {
  margin: 90rpx 0 90rpx 50rpx;
  text-align: center;
  width: 650rpx;
  height: 300rpx;
  line-height: 450rpx;
}

.header image {
  width: 180rpx;
  height: 180rpx;
}

.text_view {
  width: 750rpx;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.content {
  margin-bottom: 90rpx;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.content text {
  display: block;
  color: #9d9d9d;
  margin-top: 40rpx;
}

.bottom {
  border-radius: 80rpx;
  margin: 30rpx 20rpx;
  font-size: 35rpx;
}



.problem {
  width: 50%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items:center;
  margin-left: 50%;
}

.problem text {
  font-size: 28rpx;
  /* display: block; */
  color: #576B95; 
}

.contact-btn {
  position: absolute;
  width: 100%;
  opacity: 0;
}


.cooperate-phonenumber {
  width: 100%;
  position: fixed;
  bottom:20rpx;
  display: flex;
  /* margin-top: 30%; */
  flex-direction: column;
  justify-content: center;
  align-items:center;
  /* margin-left: 50%; */
}

.cooperate-phonenumber text {
  font-size: 28rpx;
  /* display: block; */
  color: #576B95; 
}

(3)getPhoneNumber.js

// src/pages/getPhoneNumber/getPhoneNumber.js
Page({

  /**
   * 页面的初始数据
   */
  data: {

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {

    //获取openid
    wx.login({
      success(res) {
        //获取登录凭证
        console.log("res.conde:" + res.code)


        try {
          wx.setStorageSync('code', res.code)
        } catch (e) {}



      }

    })




  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function() {

  },



  getPhoneNumber(e) {
    console.log(e)
    console.log("e.detail.errMsg:" + e.detail.errMsg)
    console.log("e.detail.iv:" + e.detail.iv)
    console.log("e.detail.encryptedData:" + e.detail.encryptedData)

    var code = wx.getStorageSync('code')
    console.log("conde:" + code)

    wx.request({
      url: 'java后台servlet链接',
      method: "POST",
      data: {
        encryptedData: e.detail.encryptedData,
        iv: e.detail.iv,
        code: code,
      },
      header: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      success: function(data) {
        console.log('data:' + data.data)

      },
      fail: function() {
        console.log('request请求错误')
      },
    })


  },




  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function() {

  }










})

2、Java后台servlet代码如下:

(1) getPhoneNumberServlet,网络请求用okhttp3


package servlet;

import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.MessageDigest;

import javax.security.sasl.SaslException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import tools.WXCore;


public class getPhoneNumberServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		String selStr;
		InputStream is = null;

		try {
			is = request.getInputStream();
			StringBuilder sb = new StringBuilder();
			byte[] b = new byte[4096];
			for (int n; (n = is.read(b)) != -1;) {
				sb.append(new String(b, 0, n));
			}

			selStr = java.net.URLDecoder.decode(sb.toString(), "UTF-8");

		} catch (IOException e) {

			e.printStackTrace();
			return;

		} finally {
			if (null != is) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		System.out.println("selStr:" + selStr);

		String encryptedData = selStr.substring(selStr.lastIndexOf("encryptedData=") + 14, selStr.lastIndexOf("&iv="));
		System.out.println("encryptedData:" + encryptedData);

		String iv = selStr.substring(selStr.lastIndexOf("iv=") + 3, selStr.lastIndexOf("&code="));
		System.out.println("iv:" + iv);

		String code = selStr.substring(selStr.lastIndexOf("code=") + 5);
		System.out.println("code:" + code);

		OkHttpClient client = new OkHttpClient();
		Request okrequest = new Request.Builder()

				.url("https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code")

				.build();
		try {

			Response okresponse = client.newCall(okrequest).execute();

			String responsedata = okresponse.body().string();
			System.out.println("responsedata:" + responsedata);

			String openid = responsedata.substring(responsedata.lastIndexOf(":") + 2,
					responsedata.lastIndexOf("\""));
			String session_key = responsedata.substring(responsedata.indexOf(":") + 2,
					responsedata.indexOf("==") + 2);


			System.out.println("原始的openid:" + openid);
			System.out.println("原始的session_key:" + session_key);


			String appId = "wx7xxxxxxxxxxxxxxxxxxxx";
			WXCore wxcore = new WXCore();
			String phonenumber = wxcore.decrypt(appId, encryptedData,                         responsedata_session_key, iv);

			System.out.println("手机号码:" + phonenumber);

			response.getWriter().write(openid + "&" + phonenumber);

		} catch (IOException e) {

			e.printStackTrace();
		}

	}



	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		doGet(request, response);

	}

}

(2) AES类、WxPKCS7Encoder类、WXCore类,用于解密,用到的包有:bcprov-jdk15on-1.52.jar,commons-codec-1.6.jar,fastjson-1.2.56.jar

<dependency>  
    <groupId>org.bouncycastle</groupId>  
    <artifactId>bcprov-jdk16</artifactId>  
    <version>1.46</version>  
</dependency>

<dependency>  
    <groupId>commons-codec</groupId>  
    <artifactId>commons-codec</artifactId>  
    <version>1.10</version>  
</dependency>  
  
<dependency>  
    <groupId>com.alibaba</groupId>  
    <artifactId>fastjson</artifactId>  
    <version>1.2.29</version>  
</dependency>  

 
  
import java.security.AlgorithmParameters;  
import java.security.InvalidAlgorithmParameterException;  
import java.security.InvalidKeyException;  
import java.security.Key;  
import java.security.NoSuchAlgorithmException;  
import java.security.NoSuchProviderException;  
import java.security.Security;  
   
import javax.crypto.BadPaddingException;  
import javax.crypto.Cipher;  
import javax.crypto.IllegalBlockSizeException;  
import javax.crypto.NoSuchPaddingException;  
import javax.crypto.spec.IvParameterSpec;  
import javax.crypto.spec.SecretKeySpec;  
import org.bouncycastle.jce.provider.BouncyCastleProvider;  
   
/** 
 * AES加密 
 */  
public class AES {  
      
    public static boolean initialized = false;  
   
    /** 
     * AES解密 
     *  
     * @param content 
     *            密文 
     * @return 
     * @throws InvalidAlgorithmParameterException 
     * @throws NoSuchProviderException 
     */  
    public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {  
        initialize();  
        try {  
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");  
            Key sKeySpec = new SecretKeySpec(keyByte, "AES");  
            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化  
            byte[] result = cipher.doFinal(content);  
            return result;  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
        } catch (NoSuchPaddingException e) {  
            e.printStackTrace();  
        } catch (InvalidKeyException e) {  
            e.printStackTrace();  
        } catch (IllegalBlockSizeException e) {  
            e.printStackTrace();  
        } catch (BadPaddingException e) {  
            e.printStackTrace();  
        } catch (NoSuchProviderException e) {  
            e.printStackTrace();  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return null;  
    }  
   
    public static void initialize() {  
        if (initialized)  
            return;  
        Security.addProvider(new BouncyCastleProvider());  
        initialized = true;  
    }  
   
    // 生成iv  
    public static AlgorithmParameters generateIV(byte[] iv) throws Exception {  
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");  
        params.init(new IvParameterSpec(iv));  
        return params;  
    }  
} 

import java.nio.charset.Charset;
import java.util.Arrays;

/**
 * 微信小程序加解密
 */
public class WxPKCS7Encoder {
	private static final Charset CHARSET = Charset.forName("utf-8");
	private static final int BLOCK_SIZE = 32;

	/**
	 * 获得对明文进行补位填充的字节.
	 * 
	 * @param count 需要进行填充补位操作的明文字节个数
	 * @return 补齐用的字节数组
	 */
	public static byte[] encode(int count) {
		// 计算需要填充的位数
		int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
		if (amountToPad == 0) {
			amountToPad = BLOCK_SIZE;
		}
		// 获得补位所用的字符
		char padChr = chr(amountToPad);
		String tmp = new String();
		for (int index = 0; index < amountToPad; index++) {
			tmp += padChr;
		}
		return tmp.getBytes(CHARSET);
	}

	/**
	 * 删除解密后明文的补位字符
	 * 
	 * @param decrypted 解密后的明文
	 * @return 删除补位字符后的明文
	 */
	public static byte[] decode(byte[] decrypted) {
		int pad = decrypted[decrypted.length - 1];
		if (pad < 1 || pad > 32) {
			pad = 0;
		}
		return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
	}

	/**
	 * 将数字转化成ASCII码对应的字符,用于对明文进行补码
	 * 
	 * @param a 需要转化的数字
	 * @return 转化得到的字符
	 */
	public static char chr(int a) {
		byte target = (byte) (a & 0xFF);
		return (char) target;
	}
}

import org.apache.commons.codec.binary.Base64;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * 封装对外访问方法
 */
public class WXCore {

	private static final String WATERMARK = "watermark";
	private static final String APPID = "appid";

	/**
	 * 解密数据
	 * 
	 * @return
	 * @throws Exception
	 */
	public static String decrypt(String appId, String encryptedData, String sessionKey, String iv) {
		String result = "";
		try {
			AES aes = new AES();
			byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey),
					Base64.decodeBase64(iv));
			if (null != resultByte && resultByte.length > 0) {
				result = new String(WxPKCS7Encoder.decode(resultByte));
				JSONObject jsonObject = JSON.parseObject(result);
				String decryptAppid = jsonObject.getJSONObject(WATERMARK).getString(APPID);
				if (!appId.equals(decryptAppid)) {
					result = "";
				}
			}
		} catch (Exception e) {
			result = "";
			e.printStackTrace();
		}
		return result;
	}

	
}

四、步骤详解:

1、通过wx.login获取【code】;

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {

    //获取openid
    wx.login({
      success(res) {
        //获取登录凭证
        console.log("res.conde:" + res.code)


        try {
          wx.setStorageSync('code', res.code)
        } catch (e) {}



      }

    })




  },

2、通过getPhoneNumber获取【encryptedData】 、【iv】;(ps:切记第1步和第2步的顺序不能颠倒,先调用wx.login,把wx.login写在onload方法里面;然后再通过getPhoneNumber获取【encryptedData】 、【iv】)

  getPhoneNumber(e) {

    console.log(e)
    console.log("e.detail.errMsg:" + e.detail.errMsg)
    console.log("e.detail.iv:" + e.detail.iv)
    console.log("e.detail.encryptedData:" + e.detail.encryptedData)
    
  },

3、通过wx.request将【encryptedData】 、【iv】 、【code】发送到Java后台;

 getPhoneNumber(e) {
    console.log(e)
    console.log("e.detail.errMsg:" + e.detail.errMsg)
    console.log("e.detail.iv:" + e.detail.iv)
    console.log("e.detail.encryptedData:" + e.detail.encryptedData)

    var code = wx.getStorageSync('code')
    console.log("conde:" + code)

    wx.request({
      url: 'Java后台servlet链接',
      method: "POST",
      data: {
        encryptedData: e.detail.encryptedData,
        iv: e.detail.iv,
        code: code,
      },
      header: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      success: function(data) {
        console.log('data:' + data.data)

      },
      fail: function() {
        console.log('request请求错误')
      },
    })


  },

4、Java后台使用【code】,请求微信后台登录凭证校验接口auth.code2Session,获取【openid】和【sessionKey】返回Java后台;(ps:本篇中不用到【openid】,后续微信小程序调用微信支付时用到)

(1)新建getPhoneNumberServlet类,获取【encryptedData】 、【iv】 、【code】


package servlet;

import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.MessageDigest;

import javax.security.sasl.SaslException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import tools.WXCore;

public class getPhoneNumberServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		String selStr;
		InputStream is = null;

		try {
			is = request.getInputStream();
			StringBuilder sb = new StringBuilder();
			byte[] b = new byte[4096];
			for (int n; (n = is.read(b)) != -1;) {
				sb.append(new String(b, 0, n));
			}

			selStr = java.net.URLDecoder.decode(sb.toString(), "UTF-8");

		} catch (IOException e) {

			e.printStackTrace();
			return;

		} finally {
			if (null != is) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		System.out.println("selStr:" + selStr);

		String encryptedData = selStr.substring(selStr.lastIndexOf("encryptedData=") + 14, selStr.lastIndexOf("&iv="));
		System.out.println("encryptedData:" + encryptedData);

		String iv = selStr.substring(selStr.lastIndexOf("iv=") + 3, selStr.lastIndexOf("&code="));
		System.out.println("iv:" + iv);

		String code = selStr.substring(selStr.lastIndexOf("code=") + 5);
		System.out.println("code:" + code);

		

	

	}



	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		doGet(request, response);

	}

}

(2)将【code】、【小程序 appId】、【小程序 appSecret】、作为参数,使用okhttp请求微信后台登录凭证校验接口auth.code2Session,获取获取【openid】和【sessionKey】。(ps:本篇中不用到【openid】,后续微信小程序调用微信支付时用到)


package servlet;

import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.MessageDigest;

import javax.security.sasl.SaslException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import tools.WXCore;


public class getPhoneNumberServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		String selStr;
		InputStream is = null;

		try {
			is = request.getInputStream();
			StringBuilder sb = new StringBuilder();
			byte[] b = new byte[4096];
			for (int n; (n = is.read(b)) != -1;) {
				sb.append(new String(b, 0, n));
			}

			selStr = java.net.URLDecoder.decode(sb.toString(), "UTF-8");

		} catch (IOException e) {

			e.printStackTrace();
			return;

		} finally {
			if (null != is) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		System.out.println("selStr:" + selStr);

		String encryptedData = selStr.substring(selStr.lastIndexOf("encryptedData=") + 14, selStr.lastIndexOf("&iv="));
		System.out.println("encryptedData:" + encryptedData);

		String iv = selStr.substring(selStr.lastIndexOf("iv=") + 3, selStr.lastIndexOf("&code="));
		System.out.println("iv:" + iv);

		String code = selStr.substring(selStr.lastIndexOf("code=") + 5);
		System.out.println("code:" + code);

		OkHttpClient client = new OkHttpClient();
		Request okrequest = new Request.Builder()

				.url("https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code")

				.build();
		try {

			Response okresponse = client.newCall(okrequest).execute();

			String responsedata = okresponse.body().string();
			System.out.println("responsedata:" + responsedata);

			String openid = responsedata.substring(responsedata.lastIndexOf(":") + 2,
					responsedata.lastIndexOf("\""));
			String session_key = responsedata.substring(responsedata.indexOf(":") + 2,
					responsedata.indexOf("==") + 2);


			System.out.println("原始的openid:" + openid);
			System.out.println("原始的session_key:" + session_key);


		} catch (IOException e) {

			e.printStackTrace();
		}

	}



	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		doGet(request, response);

	}

}

3、调用WXCore类的decrypt方法,将【appId】、【iv】、【sessionKey】作为参数,对【encryptedData】进行解密,获取手机号码。


package servlet;

import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.MessageDigest;

import javax.security.sasl.SaslException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import tools.WXCore;


public class getPhoneNumberServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		String selStr;
		InputStream is = null;

		try {
			is = request.getInputStream();
			StringBuilder sb = new StringBuilder();
			byte[] b = new byte[4096];
			for (int n; (n = is.read(b)) != -1;) {
				sb.append(new String(b, 0, n));
			}

			selStr = java.net.URLDecoder.decode(sb.toString(), "UTF-8");

		} catch (IOException e) {

			e.printStackTrace();
			return;

		} finally {
			if (null != is) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		System.out.println("selStr:" + selStr);

		String encryptedData = selStr.substring(selStr.lastIndexOf("encryptedData=") + 14, selStr.lastIndexOf("&iv="));
		System.out.println("encryptedData:" + encryptedData);

		String iv = selStr.substring(selStr.lastIndexOf("iv=") + 3, selStr.lastIndexOf("&code="));
		System.out.println("iv:" + iv);

		String code = selStr.substring(selStr.lastIndexOf("code=") + 5);
		System.out.println("code:" + code);

		OkHttpClient client = new OkHttpClient();
		Request okrequest = new Request.Builder()

				.url("https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code")

				.build();
		try {

			Response okresponse = client.newCall(okrequest).execute();

			String responsedata = okresponse.body().string();
			System.out.println("responsedata:" + responsedata);

			String openid = responsedata.substring(responsedata.lastIndexOf(":") + 2,
					responsedata.lastIndexOf("\""));
			String session_key = responsedata.substring(responsedata.indexOf(":") + 2,
					responsedata.indexOf("==") + 2);


			System.out.println("原始的openid:" + openid);
			System.out.println("原始的session_key:" + session_key);


			String appId = "wx7xxxxxxxxxxxxxxxxxxxx";
			WXCore wxcore = new WXCore();
			String phonenumber = wxcore.decrypt(appId, encryptedData,                         responsedata_session_key, iv);

			System.out.println("手机号码:" + phonenumber);

			response.getWriter().write(openid + "&" + phonenumber);

		} catch (IOException e) {

			e.printStackTrace();
		}

	}



	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		doGet(request, response);

	}

}

4、大功告成。

五、运行效果截图:

六、结语

以上就是微信小程序获取用户手机号码,Java后台servlet解密的流程和注意事项;微信小程序调用微信支付也基本是这样的流程,第一次写博客,写得不好的地方见谅,面向新手,大佬请无视,不喜勿喷。

如有疑问或项目开发合作,欢迎私信交流

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大麦147

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值