对接JSAPI支付

官方统一下单参数说明

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1

下载证书

 

1.参数配置类

package wxpay.config;

public class Constant {
	/**
	 * 公众号AppId
	 */
	public static final String APP_ID = "wx2bef02******dfc";

	/**
	 * 公众号AppSecret
	 */
	public static final String APP_SECRET = "b1bf********285cb55bc212c7ece97";

	/**
	 * 微信支付商户号
	 */
	public static final String MCH_ID = "14******02";

	/**
	 * 微信支付API秘钥
	 */
	public static final String KEY = "QBmgXTJP7QDTud**********vfYh";

	/**
	 * 微信交易类型:公众号支付
	 */
	public static final String TRADE_TYPE_JSAPI = "JSAPI";

	/**
	 * WEB
	 */
	public static final String WEB = "WEB";

	/**
	 * 返回成功字符串
	 */
	public static final String RETURN_SUCCESS = "SUCCESS";

	/**
	 * 支付地址(包涵回调地址)
	 */
	public static final String PAY_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx2bef02f0ed84edfc&redirect_uri=http%3a%2f%2fwxpay.pes-soft.com%2fwxpay%2fm%2fweChat%2funifiedOrder&response_type=code&scope=snsapi_base#wechat_redirect";

	/**
	 * 微信统一下单url
	 */
	public static final String UNIFIED_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";

	/**
	 * 微信申请退款url
	 */
	public static final String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";

	/**
	 * 微信支付通知url
	 */
	public static final String NOTIFY_URL = "http://wxpay.pes-soft.com/wxpay/";
	
	/**
	 * 证书位置
	 */
	public static final String CERT_PATH = "H:/Ws/pes-wxpay/src/main/webapp/cert/apiclient_cert.p12";

	/**
	 * 通过code获取授权access_token的URL
	 */
	public static String Authtoken_URL(String code) {
		StringBuffer url = new StringBuffer();
		url.append("https://api.weixin.qq.com/sns/oauth2/access_token?appid=");
		url.append(Constant.APP_ID);
		url.append("&secret=");
		url.append(Constant.APP_SECRET);
		url.append("&code=");
		url.append(code);
		url.append("&grant_type=authorization_code");
		return url.toString();
	}
}

2.用户信息实体类

package wxpay.model;

import java.io.Serializable;

public class AuthToken implements Serializable {

	private static final long serialVersionUID = 8647249082921436361L;

	/**
	 * 授权access_token
	 */
	private String access_token;

	/**
	 * 有效期
	 */
	private String expires_in;

	/**
	 * 刷新access_token
	 */
	private String refresh_token;

	/**
	 * 用户OPENID
	 */
	private String openid;

	/**
	 * 授权方式Scope
	 */
	private String scope;

	/**
	 * 错误码
	 */
	private String errcode;

	/**
	 * 错误消息
	 */
	private String errmsg;

	public String getAccess_token() {
		return access_token;
	}

	public void setAccess_token(String access_token) {
		this.access_token = access_token;
	}

	public String getExpires_in() {
		return expires_in;
	}

	public void setExpires_in(String expires_in) {
		this.expires_in = expires_in;
	}

	public String getRefresh_token() {
		return refresh_token;
	}

	public void setRefresh_token(String refresh_token) {
		this.refresh_token = refresh_token;
	}

	public String getOpenid() {
		return openid;
	}

	public void setOpenid(String openid) {
		this.openid = openid;
	}

	public String getScope() {
		return scope;
	}

	public void setScope(String scope) {
		this.scope = scope;
	}

	public String getErrcode() {
		return errcode;
	}

	public void setErrcode(String errcode) {
		this.errcode = errcode;
	}

	public String getErrmsg() {
		return errmsg;
	}

	public void setErrmsg(String errmsg) {
		this.errmsg = errmsg;
	}

}

3.支付参数实体类

package wxpay.model;

import com.thoughtworks.xstream.annotations.XStreamAlias;

public class PaySendData {

	/**
	 * 公众账号ID[必须]
	 */
	@XStreamAlias("appid")
	private String appId;

	/**
	 * 商户号[必须]
	 */
	@XStreamAlias("mch_id")
	private String mch_id;

	/**
	 * 设备号[WEB]
	 */
	@XStreamAlias("device_info")
	private String device_info;

	/**
	 * 随机字符串[必须]
	 */
	@XStreamAlias("nonce_str")
	private String nonce_str;

	/**
	 * 签名[必须]
	 */
	@XStreamAlias("sign")
	private String sign;

	/**
	 * 商品描述[必须]
	 */
	@XStreamAlias("body")
	private String body;

	/**
	 * 商品详情
	 */
	@XStreamAlias("detail")
	private String detail;

	/**
	 * 附加数据
	 */
	@XStreamAlias("attach")
	private String attach;

	/**
	 * 商户订单号[必须]
	 */
	@XStreamAlias("out_trade_no")
	private String out_trade_no;

	/**
	 * 货币类型
	 */
	@XStreamAlias("fee_type")
	private String fee_type;

	/**
	 * 交易金额 [必须]
	 */
	@XStreamAlias("total_fee")
	private int total_fee;

	/**
	 * 交易类型 [必须]
	 */
	@XStreamAlias("trade_type")
	private String trade_type;

	/**
	 * 通知地址 [必须]
	 */
	@XStreamAlias("notify_url")
	private String notify_url;

	/**
	 * 终端Ip [必须]
	 */
	@XStreamAlias("spbill_create_ip")
	private String spbill_create_ip;

	/**
	 * 订单生成时间yyyyMMddHHmmss
	 */
	@XStreamAlias("time_start")
	private String time_start;

	/**
	 * 订单失效时间yyyyMMddHHmmss 间隔>5min
	 */
	@XStreamAlias("time_expire")
	private String time_expire;

	/**
	 * 用户标识 tradeType=JSAPI时必须
	 */
	@XStreamAlias("openid")
	private String openId;

	/**
	 * 商品标记
	 */
	@XStreamAlias("goods_tag")
	private String goods_tag;

	/** 指定支付方式 */
	@XStreamAlias("limit_pay")
	private String limit_pay;

	// ===============以下属性为申请退款参数===================

	/**
	 * 微信订单号 [必须] 与商户退款单号二选一
	 */
	@XStreamAlias("transaction_id")
	private String transaction_id;

	/**
	 * 商户退款单号 [必须] 与微信单号二选一
	 */
	@XStreamAlias("out_refund_no")
	private String out_refund_no;

	/**
	 * 退款金额 [必须]
	 */
	@XStreamAlias("refund_fee")
	private Integer refund_fee;

	/**
	 * 退款货币种类
	 */
	@XStreamAlias("refund_fee_type")
	private String refund_fee_type;

	/**
	 * 操作员账号:默认为商户号 [必须]
	 */
	@XStreamAlias("op_user_id")
	private String op_user_id;

	public PaySendData() {
	}

	public String getAppId() {
		return appId;
	}

	public void setAppId(String appId) {
		this.appId = appId;
	}

	public String getMch_id() {
		return mch_id;
	}

	public void setMch_id(String mch_id) {
		this.mch_id = mch_id;
	}

	public String getDevice_info() {
		return device_info;
	}

	public void setDevice_info(String device_info) {
		this.device_info = device_info;
	}

	public String getNonce_str() {
		return nonce_str;
	}

	public void setNonce_str(String nonce_str) {
		this.nonce_str = nonce_str;
	}

	public String getSign() {
		return sign;
	}

	public void setSign(String sign) {
		this.sign = sign;
	}

	public String getBody() {
		return body;
	}

	public void setBody(String body) {
		this.body = body;
	}

	public String getDetail() {
		return detail;
	}

	public void setDetail(String detail) {
		this.detail = detail;
	}

	public String getAttach() {
		return attach;
	}

	public void setAttach(String attach) {
		this.attach = attach;
	}

	public String getOut_trade_no() {
		return out_trade_no;
	}

	public void setOut_trade_no(String out_trade_no) {
		this.out_trade_no = out_trade_no;
	}

	public String getFee_type() {
		return fee_type;
	}

	public void setFee_type(String fee_type) {
		this.fee_type = fee_type;
	}

	public int getTotal_fee() {
		return total_fee;
	}

	public void setTotal_fee(int total_fee) {
		this.total_fee = total_fee;
	}

	public String getTrade_type() {
		return trade_type;
	}

	public void setTrade_type(String trade_type) {
		this.trade_type = trade_type;
	}

	public String getNotify_url() {
		return notify_url;
	}

	public void setNotify_url(String notify_url) {
		this.notify_url = notify_url;
	}

	public String getSpbill_create_ip() {
		return spbill_create_ip;
	}

	public void setSpbill_create_ip(String spbill_create_ip) {
		this.spbill_create_ip = spbill_create_ip;
	}

	public String getTime_start() {
		return time_start;
	}

	public void setTime_start(String time_start) {
		this.time_start = time_start;
	}

	public String getTime_expire() {
		return time_expire;
	}

	public void setTime_expire(String time_expire) {
		this.time_expire = time_expire;
	}

	public String getOpenId() {
		return openId;
	}

	public void setOpenId(String openId) {
		this.openId = openId;
	}

	public String getGoods_tag() {
		return goods_tag;
	}

	public void setGoods_tag(String goods_tag) {
		this.goods_tag = goods_tag;
	}

	public String getLimit_pay() {
		return limit_pay;
	}

	public void setLimit_pay(String limit_pay) {
		this.limit_pay = limit_pay;
	}

	public String getTransaction_id() {
		return transaction_id;
	}

	public void setTransaction_id(String transaction_id) {
		this.transaction_id = transaction_id;
	}

	public String getOut_refund_no() {
		return out_refund_no;
	}

	public void setOut_refund_no(String out_refund_no) {
		this.out_refund_no = out_refund_no;
	}

	public Integer getRefund_fee() {
		return refund_fee;
	}

	public void setRefund_fee(Integer refund_fee) {
		this.refund_fee = refund_fee;
	}

	public String getRefund_fee_type() {
		return refund_fee_type;
	}

	public void setRefund_fee_type(String refund_fee_type) {
		this.refund_fee_type = refund_fee_type;
	}

	public String getOp_user_id() {
		return op_user_id;
	}

	public void setOp_user_id(String op_user_id) {
		this.op_user_id = op_user_id;
	}

}

4.service

package wxpay.service;

import wxpay.model.AuthToken;

public interface PayService {
	
	/**
	 * 统一下单接口
	 * @param authToken 授权token
	 * @param remoteAddr 请求主机ip
	 * @return prepayId 预支付id
	 */
	String unifiedOrder(AuthToken authToken, String remoteAddr);
	
	/**
	 * 申请退款接口
	 */
	String refund();
}

serviceImpl

package wxpay.service;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;

import wxpay.config.Constant;
import wxpay.model.AuthToken;
import wxpay.model.PaySendData;
import wxpay.utils.HttpUtil;
import wxpay.utils.PayUtils;

@Service("payService")
public class PayServiceImpl implements PayService {

	/**
	 * 微信支付统一下单
	 **/
	public String unifiedOrder(AuthToken authToken, String remoteAddr) {
		Map<String, String> resultMap = null;
		// 统一下单返回的预支付id
		String prepayId = null;
		PaySendData paySendData = new PaySendData();
		// 构建微信支付请求参数集合
		paySendData.setAppId(Constant.APP_ID);
		paySendData.setMch_id(Constant.MCH_ID);
		paySendData.setNotify_url(Constant.NOTIFY_URL);
		paySendData.setTrade_type(Constant.TRADE_TYPE_JSAPI);
		paySendData.setDevice_info(Constant.WEB);
		paySendData.setBody("商品名称");
		paySendData.setNonce_str(PayUtils.getRandomStr(32));
		paySendData.setOut_trade_no(PayUtils.getRandomStr(8));
		paySendData.setTotal_fee(1);
		paySendData.setSpbill_create_ip(remoteAddr);
		paySendData.setOpenId(authToken.getOpenid());
		// 将参数拼成map,生产签名
		paySendData.setSign(PayUtils.getSign(buildParamMap(paySendData)));
		// 将请求参数对象转换成xml
		String reqXml = PayUtils.sendDataToXml(paySendData);
		try {
			// 发送请求
			CloseableHttpResponse response = HttpUtil.Post(Constant.UNIFIED_ORDER_URL, reqXml, false);
			try {
				resultMap = PayUtils.parseXml(response.getEntity().getContent());
				// 关闭流
				EntityUtils.consume(response.getEntity());
			} finally {
				response.close();
			}
		} catch (Exception e) {
			System.out.println("微信支付统一下单异常");
		}
		String return_code = resultMap.get("return_code");
		String result_code = resultMap.get("result_code");
		if (Constant.RETURN_SUCCESS.equals(return_code) && Constant.RETURN_SUCCESS.equals(result_code)) {
			// return_code=通信标识
			// result_code=交易标识
			// 只有当returnCode与resultCode均返回“success”,才代表微信支付统一下单成功
			prepayId = "prepay_id=" + resultMap.get("prepay_id");
		}
		return prepayId;
	}

	public String refund() {
		PaySendData paySendData = new PaySendData();
		// 构建微信支付请求参数集合
		paySendData.setAppId(Constant.APP_ID);
		paySendData.setMch_id(Constant.MCH_ID);
		paySendData.setNonce_str(PayUtils.getRandomStr(32));
		// paySendData.setTransaction_id(WeChatUtils.getRandomStr(32));
		// Out_trade_no与Transaction_id二选一
		paySendData.setOut_trade_no("jtVFcgbM");
		paySendData.setOut_refund_no("jtVFcgbM");
		paySendData.setTotal_fee(1);
		paySendData.setRefund_fee(1);
		paySendData.setOp_user_id(Constant.MCH_ID);
		// 将参数拼成map,生产签名
		paySendData.setSign(PayUtils.getSign(buildParamMap(paySendData)));
		// 将请求参数对象转换成xml
		String reqXml = PayUtils.sendDataToXml(paySendData);
		try {
			// 发送请求
			CloseableHttpResponse response = HttpUtil.Post(Constant.UNIFIED_ORDER_URL, reqXml, true);
			try {
				// 关闭流
				EntityUtils.consume(response.getEntity());
			} finally {
				response.close();
			}
		} catch (Exception e) {
			System.out.println("微信退款异常");
		}
		return null;
	}

	/**
	 * 构建统一下单参数map 用于生成签名
	 * 
	 * @param data
	 * @return SortedMap<String,Object>
	 */
	private SortedMap<String, Object> buildParamMap(PaySendData data) {
		SortedMap<String, Object> paramters = new TreeMap<String, Object>();
		Field[] fields = data.getClass().getDeclaredFields();
		try {
			for (Field field : fields) {
				field.setAccessible(true);
				if (null != field.get(data)) {
					paramters.put(field.getName().toLowerCase(), field.get(data).toString());
				}
			}
		} catch (Exception e) {
			System.out.print("构建签名map错误: ");
			e.printStackTrace();
		}

		return paramters;
	}

}

5.主页controller

package wxpay.ctrl;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import wxpay.config.Constant;

@Controller
@RequestMapping(value = "/")
public class IndexController {
	@RequestMapping(value = "/")
	public String index(Model model) {
		model.addAttribute("payURL", Constant.PAY_URL);
		return "index";
	}
}

支付controller

package wxpay.ctrl;

import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import wxpay.config.Constant;
import wxpay.model.AuthToken;
import wxpay.service.PayService;
import wxpay.utils.PayUtils;

@Controller
@RequestMapping(value = "/m/weChat")
public class WeChatOrderController {

	@Autowired
	private PayService payService;

	/**
	 * 统一下单
	 */
	@RequestMapping(value = "/unifiedOrder")
	public String unifiedOrder(HttpServletRequest request, Model model) {
		// 用户同意授权,获得的code
		String code = request.getParameter("code");
		// 通过code获取网页授权access_token
		AuthToken authToken = PayUtils.getTokenByAuthCode(code);
		// 调用统一下单service
		String prepayId = payService.unifiedOrder(authToken, request.getRemoteAddr());
		if (!PayUtils.isEmpty(prepayId)) {
			String timeStamp = PayUtils.getTimeStamp();// 当前时间戳
			String nonceStr = PayUtils.getRandomStr(20);// 不长于32位的随机字符串

			SortedMap<String, Object> signMap = new TreeMap<String, Object>();// 自然升序map
			signMap.put("appId", Constant.APP_ID);
			signMap.put("package", prepayId);
			signMap.put("timeStamp", timeStamp);
			signMap.put("nonceStr", nonceStr);
			signMap.put("signType", "MD5");

			model.addAttribute("appId", Constant.APP_ID);
			model.addAttribute("timeStamp", timeStamp);
			model.addAttribute("nonceStr", nonceStr);
			model.addAttribute("prepayId", prepayId);
			model.addAttribute("paySign", PayUtils.getSign(signMap));// 获取签名
		} else {
			System.out.println("微信统一下单失败,订单编号:失败原因");
			return "redirect:/";// 支付下单失败,重定向至订单列表
		}
		// 将支付需要参数返回至页面,采用h5方式调用支付接口
		return "h5Pay";
	}

	/**
	 * 申请退款
	 */
	@RequestMapping(value = "/refund")
	public String refund(HttpServletRequest request, Model model) {
		// 调用统一下单service
		payService.refund();
		return "h5Pay";
	}
}

6.工具类

https://pan.baidu.com/s/1qWunw5piOxCeZynHIGMQWg 密码:wy31

7.页面

https://pan.baidu.com/s/15v0cWoXmjJJLF9L_4h17Ng  密码:1p6g

JS JSP ASP .NET J2AM API接口和返回的版本 目前所有版本的JS JSP ASP .NET J2AM 都是提供源代码的,对于一些脚本语言来说,直接解压缩之后就可以使用了,不需要什么安装步骤。另外一些需要编译的语言,则提供了编译用的 shell 文件(Linux/Unix 下使用)和 bat 文件(Windows 下使用),或者直接提供编译好的二进制库文件。 不过为了让读者能够更清楚如何安装,我们还是对每种语言的安装都做详细的讲解,你可以在安装列表里找到你感兴趣的语言的安装方法。 示例 如果你已经把 JS JSP ASP .NET J2AM 安装好了,那么接下来就让我们开始第一个小程序吧。按照惯例,第一个演示程序几乎总是 HelloWorld,我们也不想打破这个惯例,不过对于 PHPRPC 来说,有服务器端就要有客户端,否则我们就没有什么好演示的啦,所以我们的第一个演示程序实际上是两个,一个是服务器端,另一个是客户端。我们都先用 PHP 语言来写好了。 服务器端 view plaincopy to clipboardprint? <?php include ("php/phprpc_server.php"); function HelloWorld() { return 'Hello World!'; } $server = new PHPRPC_Server(); $server->add('HelloWorld'); $server->start(); ?> 客户端 view plaincopy to clipboardprint? <?php include ("php/phprpc_client.php"); $client = new PHPRPC_Client('http://127.0.0.1/server.php'); echo $client->HelloWorld(); ?> 对于服务器端程序,我们应该将它命名为 server.php(这是因为客户端调用时用的是这个名字,而不是 PHPRPC 的什么规定),然后把它放在本地 Web 服务器的根目录下,并保证服务器可以正常运行 PHP 程序,之后在浏览器或命令行下运行客户端程序,你就可以看到结果了。 这两个程序几乎简单到无需解释的地步,所以如果你已经明白它们的意思,那么就可以直接跳过下面的解释,继续看后面的例子。 服务器端第 1 句是将 它的服务器端程序包含到你的程序里,之后的 2 - 4 句是定义一个远程调用的函数,你会发现它与本地函数没有任何区别。第 5 句是创建服务器端对象,第 6 句是添加要发布的方法,这里添加的就是刚刚定义的 HelloWorld 函数,在 PHP 中,添加的发布方法是函数名的字符串表示,在其它语言中可能略有不同。第 7 句是启动服务。 客户端就更简单了,第 1 句是将 它的客户端程序包含到你的程序里。第 2 句是创建客户端对象,其中的参数就是服务器端的地址。第 3 句是对远程方法(函数)的调用,之后通过 echo 将它显示出来。如果顺利的话,执行后你就会看到输出的 Hello World!。 上面的例子是发布的是函数,下面我们来看一下类中的静态方法如何发布: view plaincopy to clipboardprint? <?php include ("php/phprpc_server.php"); class Hello { static function HelloWorld() { return 'Hello World!'; } } $server = new PHPRPC_Server(); $server->add('HelloWorld', 'Hello'); $server->start(); ?> 这个服务器端只要它的名字与发布的地址与上面那个发布函数的例子一样的话,上面的那个客户端就可以得到同样的结果,也就是说,在客户端看来是没有任何区别的。 它并不是只可以在 PHP 中使用,它同样支持其它语言的服务器和客户端,而且还可以无差别的相互调用。 现在我们来看一下如何在 Java 中调用这个 PHP 的服务器方法: view plaincopy to clipboardprint? import org.phprpc.*; interface IHello { public String helloWorld(); } public class HelloWorld { public static void main ( String [] args ) { PHPRPC_Client client = new PHPRPC_Client("http://127.0.0.1/server.php"); IHello clientProxy = (IHello)client.useService(IHello.class); System.out.println(clientProxy.helloWorld()); } } 当我们把这个例子编译之后,在命令行中输入以下命令就可以看到执行结果了: java -classpath .;phprpc_client.jar HelloWorld 这个 Java 的客户端看上去比 PHP 的要稍微复杂一些,不过仍然很好理解。在 Java 客户端中,我们使用了接口来描述远程方法,之后我们通过 useService 方法返回一个远程代理对象,该对象实现了我们定义的接口,之后我们就可以直接调用远程方法 helloWorld 了。如果你比较细心的话,你还会发现我们在 PHP 中定义的方法和在 Java 中定义的接口的名字的大小写有点不同,但是仍然可以正常调用。是的,PHPRPC 发布的方法是不区分大小写的。所以不论你所使用的语言是否区分大小写,都可以按照自己(或语言)的习惯来定义方法名。 在本章的最后,我们再来看一下在 JavaScript 如何调用它的服务。顺便再强调一下,服务器端不止是可以用 PHP 来编写,你同样可以使用其它语言(比如 Java,.NET,Ruby,Python 等),这里我们只是以 PHP 为例而已。在这个例子中你还会看到如何使用加密传输。 view plaincopy to clipboardprint? <html> <head> <title>HelloWorld</title> [removed][removed] [removed] var client = new PHPRPC_Client('http://127.0.0.1/server.php', ['HelloWorld']); client.setEncryptMode(2); client.HelloWorld(function (result) { alert(result); }); [removed] </head> <body> </body> </html> 这个 JavaScript 是在网页中运行的,这里建议大家要把 head 和 body 标签都写全,即使它们对你来说看上去没有什么用处,但是在有些浏览器中,如果这些标签没有写全,或者写的不正确,程序就不能正确运行。 在这个例子中,我们会发现在创建 PHPRPC_Client 对象时,除了要写服务器地址以外,还要将远程方法的名字作为参数,因为远程方法可能不止一个,所以这个参数是数组类型的。 client.setEncryptMode(2); 这句是设置加密传输,参数 2 表示双向加密,就是参数和结果都加密(只不过这个 HelloWorld 比较特殊,它没有参数)。 接下来就是调用远程方法 HelloWorld 了,我们会发现它跟 PHP 和 Java 客户端的调用不太一样。是的,在 JavaScript 中远程调用都是采用异步方式的,也就是说要获得结果,需要用回调函数,回调函数作为远程方法的最后一个参数,回调函数也有四个参数,这里我们只使用第一个参数,也就是返回结果 result,通过 alert(result); 我们就可以在浏览器中看到最后弹出的 Hello World! 提示框了。 通过上面的例子,我们已经看到在 PHP、JavaJavaScript 这三种语言中使用 PHPRPC 都很简单,但因为语言的不同,在写法和用法上又有一些差别。不过你不用担心其它的语言跟它们也会有很大的差别,因为在接下来的章节中你很快就会发现其它语言跟这上面三种语言实现的写法和用法上的相似或相同之处了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值