一、支付宝支付
1、官方文档是最好的教程:
①电脑网站支付文档:https://docs.open.alipay.com/270/105899/
②支付宝沙箱使用教程:https://docs.open.alipay.com/200/105311/
③调用支付宝相关接口的应用创建:https://open.alipay.com/developmentAccess/developmentAccess.htm
2、支付宝支付示例:
在使用支付宝支付时,先要在蚂蚁金服开放平台中下载alipay-sdk-java-3.4.49.ALL.jar。
在调用支付接口乃至很多第三方接口时,很多都有一个发起调用的方法和一个调用成功后的回调方法。在支付宝支付中也是一样,先看看发起支付的方法:
/**
* 发起支付
* @param httpRequest
* @param httpResponse
* @param out_trade_no 订单号
* @param total_amount 订单金额
* @param subject 订单名称
* @param body 商品描述
* @throws ServletException
* @throws IOException
*/
@RequestMapping("aliPay")
public void aliPay(HttpServletRequest httpRequest,
HttpServletResponse httpResponse,String out_trade_no,String total_amount, String subject,String body) throws ServletException, IOException{
doPost(httpRequest, httpResponse, out_trade_no, total_amount, subject, body);
}
/**
* @param httpRequest
* @param httpResponse
* @param out_trade_no 订单号
* @param total_amount 订单金额
* @param subject 订单名称
* @param body 商品描述
* @throws ServletException
* @throws IOException
*/
public void doPost(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
String out_trade_no,String total_amount, String subject,String body)
throws ServletException, IOException {
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.GATEWAYURL, AlipayConfig.APP_ID,
AlipayConfig.APP_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET,
AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGN_TYPE); // 获得初始化的AlipayClient
// 创建API对应的request
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(AlipayConfig.RETURN_URL);
alipayRequest.setNotifyUrl(AlipayConfig.NOTIFY_URL);
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
+ "\"total_amount\":\""+ total_amount +"\","
+ "\"subject\":\""+ subject +"\","
+ "\"body\":\""+ body +"\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
String form = "";
try {
// 调用SDK生成表单
form = alipayClient.pageExecute(alipayRequest).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
httpResponse.setContentType("text/html;charset=" + AlipayConfig.CHARSET);
// 直接将完整的表单html输出到页面
httpResponse.getWriter().write(form);
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
支付宝支付成功后的回调方法:
/**
* 支付宝支付回调
* @param request
* @return
* @throws UnsupportedEncodingException
* @throws AlipayApiException
*/
@RequestMapping("aliPaySuccess")
public String aliPaySuccess(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException {
System.out.println("------------------------------------>回调成功!");
Map<String,String> params = new HashMap<String,String>();
Map<String,String[]> requestParams = request.getParameterMap();
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGN_TYPE); //调用SDK验证签名
//——请在这里编写您的程序(以下代码仅作参考)——
/* 实际验证过程建议商户务必添加以下校验:
1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
4、验证app_id是否为该商户本身。
*/
if(signVerified) {
//验证成功
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
System.out.println("trade_no"+out_trade_no);
System.out.println("trade_no"+trade_no);
System.out.println("支付成功");
}else {
//验证失败
System.out.println("支付失败");
}
return "testPay/aliPayPage";
}
AlipayConfig.java常量类:
package com.mfc.util;
/**
* @author 74790
* 支付宝支付相关参数
*/
public class AlipayConfig {
// 支付宝网关
public static String GATEWAYURL = "https://openapi.alipaydev.com/gateway.do";
// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
public static final String APP_ID = "";
// 商户私钥,您的PKCS8格式RSA2私钥
public static final String APP_PRIVATE_KEY = "";
public static final String FORMAT = "json";
// 字符编码格式
public static final String CHARSET = "utf-8";
// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
public static final String ALIPAY_PUBLIC_KEY = "";
// 签名方式
public static final String SIGN_TYPE = "RSA2";
//页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static final String RETURN_URL="";
// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static final String NOTIFY_URL="";
}
3、支付宝支付订单实现思路:
①.点击支付调用TestPayCtrl中的aliPay方法发起支付,此时会跳往支付宝支付界面
②.在发起支付的aliPay方法中(本示例中其实是在doPost方法中),调用service方法将支付相关信息(如订单号、订单金额、商品信息等)存进自己系统的业务表中(这里只演示支付过程,所以没有将支付相关信息存进自己系统的业务表中)。
③.支付宝支付成功后会回调本系统的一个方法,我这里回调的是TestPayCtrl中的aliPaySuccess方法,支付宝会反馈给回调方法一些参数: 如out_trade_no(商户的订单号)、trade_no(支付宝交易号)等。<br/>
④.在回调方法中就可以通过out_trade_no(商户的订单号)取支付相关信息(支付相关信息在步骤2中已经存进了自己的业务表)。取出这些支付相关信息就可以写自己网站的逻辑了。<br/>
二、微信支付
1、同样官方文档是最好的教程:
官方支付相关文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_2
微信支付(扫码支付)教程:https://www.cnblogs.com/gdufs/p/7230950.html
2、微信支付示例:
这里使用Maven依赖:
<!-- 微信支付 -->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<!-- google二维码工具 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.1.0</version>
</dependency>
微信支付发起支付:
private WxPayConfig config = new WxPayConfig();
private WXPay wxPay = new WXPay(config);
@RequestMapping("wxpay/pay")
public void pay(HttpServletResponse response){
//这里执行商户系统创建新的订单操作,写商户自己的逻辑
//设置微信支付请求参数
Map<String, String> data = new HashMap<String, String>();
//商品简单描述,该字段请按照规范传递,具体请见参数规定,必填
data.put("body", "微信支付测试");
//商户订单号 ,必填
data.put("out_trade_no", "20190106");
//设备号,非必填
//data.put("device_info", "");
//标价币种,默认人民币(CNY),非必填
data.put("fee_type", "CNY");
//标价金额,必填
data.put("total_fee", "1");
//支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP,必填
data.put("spbill_create_ip", "192.168.0.11");
//异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
data.put("notify_url", "");
//交易类型,必填
data.put("trade_type", "NATIVE"); // 此处指定为扫码支付
//商品ID,非必填
data.put("product_id", "12");
try {
//发起支付
Map<String, String> resp = wxPay.unifiedOrder(data);
//获取二维码URL
String code_url = resp.get("code_url");
//根据URL生成二维码
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
//设置二维码参数
Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix bitMatrix = multiFormatWriter.encode(code_url, BarcodeFormat.QR_CODE, 300, 300, hints);
//返回二维码
MatrixToImageWriter.writeToStream(bitMatrix, "jpg", response.getOutputStream());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
支付成功回调:
/**
* 支付结果回调
* @return
* @throws Exception
*/
@RequestMapping("/wxpay/notify_url")
public void notifyUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 读取回调内容
InputStream inputStream;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null) {
sb.append(s);
}
in.close();
inputStream.close();
// 支付结果通知的xml格式数据
String notifyData = sb.toString();
// 转换成map
Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);
//支付确认内容
String resXml = "";
//验证签名
if (wxPay.isPayResultNotifySignatureValid(notifyMap)) { // 签名正确
System.out.println("返回的商户订单号:"+notifyMap.get("out_trade_no"));
System.out.println("这里需要根据商户的订单号在自己系统中查询,判断这个订单号是不是本系统的订单号");
if(notifyMap.get("out_trade_no") != null) {
if("SUCCESS".equals(notifyMap.get("result_code"))) { //交易成功
// TODO:更新订单
System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付成功");
} else { //交易失败
System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付失败");
}
}
// 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
//设置成功确认内容
resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
}
else { // 签名错误,如果数据里没有sign字段,也认为是签名错误
//设置失败确认内容
resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg></return_msg>" + "</xml> ";
System.out.println("订单" + notifyMap.get("out_trade_no") + "微信支付失败");
}
//发送通知
response.getWriter().println(resXml);
}
实现的微信支付相关配置的参数类:
package com.mfc.util;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import com.github.wxpay.sdk.WXPayConfig;
public class WxPayConfig implements WXPayConfig{
private byte[] certData;
//初始化退款、撤销时的商户证书
public WxPayConfig() {
try {
String certPath = "D://第三方开放平台/wx_apiclient_cert.p12";
File file = new File(certPath);
InputStream certStream = new FileInputStream(file);
this.certData = new byte[(int) file.length()];
certStream.read(this.certData);
certStream.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 微信支付分配的公众账号ID(企业号corpid即为此appId)
* */
public String getAppID() {
return "";
}
/**
* 微信支付分配的商户号
* */
public String getMchID() {
return "";
}
public String getKey() {
return "";
}
public int getHttpConnectTimeoutMs() {
return 8000;
}
public int getHttpReadTimeoutMs() {
return 10000;
}
public InputStream getCertStream() {
ByteArrayInputStream certBis;
certBis = new ByteArrayInputStream(this.certData);
return certBis;
}
}
3、微信支付实现思路:
①.点击支付调用TestPayCtrl中的pay方法发起支付,此时弹出微信支付二维码
②.在发起支付的pay方法中,调用service方法将支付相关信息(如订单号、订单金额、商品信息等)存进自己系统的业务表中。
③.微信支付成功后会回调本系统的一个方法,我这里回调的是TestPayCtrl中的notifyUrl方法,微信会反馈给回调方法一些参数:如out_trade_no(商户的订单号)等。
④.在回调方法中就可以通过out_trade_no(商户的订单号)取支付相关信息(支付相关信息在步骤2中已经存进了自己的业务表)。取出这些支付相关信息就可以写自己网站的逻辑了。