PayPal⽀付接⼝⽅式(checkout)集成
1.简述
PayPal是倍受全球亿万⽤户追捧的国际贸易⽀付⼯具,即时⽀付,即时到账,全中⽂操作界⾯,能通过中国的本地银⾏轻松提现,解决外贸收款难题,助您成功开展海外业务,决胜全球。注册PayPal后就可⽴即开始接受信⽤卡付款。作为在线付款服务商,PayPal是您向全世界近2.54亿的⽤户敞开⼤门的最快捷的⽅式。最⼤的好处是,注册完全免费!集国际流⾏的信⽤卡,借记卡,电⼦⽀票等⽀付⽅式于⼀⾝。帮助买卖双⽅解决各种交易过程中的⽀付难题。PayPal是名副其实的全球化⽀付平台,服务范围超过200个市场,⽀持的币种超过100个。在跨国交易中,将近70%的在线跨境买家更喜欢⽤PayPal⽀付海外购物款项。
PayPal提供了多种⽀付⽅式:
标准⽀付
快速⽀付
其中标准⽀付誉为最佳实践。
注意:paypal⽀付国内账号不能付款给国内账号
2.PayPal的相关URL
官⽅⽂档:
3.PayPal Checkout集成步骤
1、整合Smart Payment Buttons(PayPal智能付款按钮)到页⾯
2、⽤户点击⽀付按钮
3、按钮调⽤PayPal Orders API来创建交易
4、进⼊PayPal⽀付页⾯
5、⽤户登录后确认⽀付
6、按钮调⽤PayPal Orders API来完成交易
7、显⽰⽀付成功信息
4.PayPal Checkout集成步骤实现
(1)注册账号
(2)进⼊开发者界⾯创建相关信息
2、登录成功后,选择:SANBOX下的Accounts标签
3、创建个⼈账号和商家账号⽤于测试沙箱环境
4、创建APP获取client id和cret
点击Create app创建
(3)⽰例代码
控制器代码如下:
@Controller
@RequestMapping("/paypalC")
public class PaypalC {
@Autowired
private PaypalS paypalS;
@RequestMapping(method = RequestMethod.GET)
public String index(){
return "index";
}
/**创建订单
*/
@RequestMapping(method = RequestMethod.POST, value = "createOrder")
public void createOrder(HttpServletRequest req, HttpServletRespon resp){
蘸墨水}
/**执⾏付款
*/
@RequestMapping(method = RequestMethod.POST, value = "executePayment")
public void executePayment(HttpServletRequest req, HttpServletRespon resp){
}
/**交易取消
*/
@RequestMapping(method = RequestMethod.GET, value = "cancel")
public String cancel(){
return "cancel";
/**交易成功返回页⾯
*/
@RequestMapping(method = RequestMethod.GET, value = "success")
public String success(HttpServletRequest req, HttpServletRespon resp, String orderId){英转中
req.tAttribute("orderId", orderId);
return "success";
}
/**查询交易详情
*/
@RequestMapping(method = RequestMethod.POST, value = "paymentDetails")
public void paymentDetails(HttpServletRequest req, HttpServletRespon resp, String orderId){
paypalS.paymentDetails(req, resp, orderId);
}
}
View Code
业务层代码如下:
/**Paypal⽀付rvice类
*/
@Service
public class PaypalS {
/**创建订单
*/
public void createOrder(HttpServletRequest req, HttpServletRespon resp){
//1.获取paypal的token
String accessToken = AccessToken();
//2.提交交易到paypal
String BaUrl = Scheme() + "://"+ ServerName() + ((ServerPort() == 80) ? "" : ":" + ServerPort()) + ContextPath(); String result = ateOrder(req, accessToken, BaUrl);
resp.tContentType("application/json");
try {
PrintWriter out = Writer();
净植
out.print(result);
} catch (IOException e) {
e.printStackTrace();
}
}
/**执⾏付款
*/
public void executePayment(HttpServletRequest req, HttpServletRespon resp){
resp.tContentType("application/json");
try {
String jsonFromHtml = readInputStreamForData(req); // holding the json from request
JSONObject json = JSONObject.parObject(jsonFromHtml);
String orderId = String("orderId");//付款id
String accessToken = AccessToken();
String result = utePayment(req, accessToken, orderId);
PrintWriter out = Writer();
out.print(result);
}catch(Exception e) {
e.printStackTrace();
try {
PrintWriter out = Writer();
out.print(new AjaxDto(0, "⽀付失败,请联系管理员...", req).toJson());
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
/**查询交易详情
*/
public void paymentDetails(HttpServletRequest req, HttpServletRespon resp,String orderId){
try {
String accessToken = AccessToken();
JSONObject dataFromGetPaymentsAPI = PaymentDetails(req, accessToken, orderId);
resp.tContentType("application/json");
resp.tStatus(200);
PrintWriter out = Writer();
out.print(dataFromGetPaymentsAPI);
} catch (Exception e) {
resp.tStatus(500);
resp.tContentType("application/json");
try {
PrintWriter out = Writer();
Map<String, String> error = new HashMap<String, String>();
error.put("error", "获取交易详情失败,请联系管理员");
out.print(error);
} catch (IOException e1) {
e1.printStackTrace();
课代表还是科代表}
}
}
/**获取req传递参数
*/
private String readInputStreamForData(HttpServletRequest req) throws IOException {
BufferedReader br = new BufferedReader(new InputStream()));
String json = "";
if(br != null) {
json = br.readLine();
}
return json;
}
}
View Code
PayPal⼯具类如下:
public class PaypalUtils {
private static Log log = Log(PaypalUtils.class);
/**true表⽰测试环境(沙盒),fal:正式环境
*/
private static boolean IS_APPLICATION_IN_SANDBOX = true;
//TODO 测试环境使⽤
/**沙盒帐户详细信息-卖⽅
*/
private static String SELLAR_SANDBOX_EMAIL = "";//邮箱
private static String SELLAR_SANDBOX_PASSWORD = "";//密码
private static String SELLAR_SANDBOX_SIGNATURE = "";//标签
/**App Client ID 和 SECRET
*/
private static String CLIENT_ID = "";//Client ID
private static String SECRET = "";//SECRET
private static String ACCESS_TOKEN_URL = "api./v1/oauth2/token";//获取token接⼝private static String CREATE_PAYMENT_URL = "api./v2/checkout/orders";
private static String EXECUTE_PAYMENT_URL = "api./v2/checkout/orders/{id}/capture"; private static String GET_PAYMENT_DETAILS = "api./v2/checkout/orders/{id}";
//TODO 正式环境使⽤
/**真实帐户详细信息-卖⽅
*/
private static String SELLAR_LIVE_EMAIL = "";//邮箱
private static String SELLAR_LIVE_PASSWORD = "";//密码
private static String SELLAR_LIVE_SIGNATURE = "";//标签
/**App Client ID 和 SECRET
*/
private static String CLIENT_ID_LIVE = "";//Client ID
private static String SECRET_LIVE = "";//SECRET
private static String ACCESS_TOKEN_URL_LIVE = "/v1/oauth2/token";//获取token接⼝private static String CREATE_PAYMENT_URL_LIVE = "/v2/checkout/orders";
private static String EXECUTE_PAYMENT_URL_LIVE = "/v2/checkout/orders/{id}/capture"; private static String GET_PAYMENT_DETAILS_LIVE = "/v2/checkout/orders/{id}";
private static String CANCEL_URL= "paypalC/cancel";//交易失败页⾯
private static String RETURN_URL= "paypalC/success";//交易成功页⾯
/**初始化配置实体
*/
public static PaypalConfigBean paypalConfigBean = new PaypalConfigBean();
static{
if(IS_APPLICATION_IN_SANDBOX) {
// load all properties for sandbox
paypalConfigBean.tAccessTokenUrl(ACCESS_TOKEN_URL);
paypalConfigBean.tClientId(CLIENT_ID);
paypalConfigBean.tCreatePaymentsUrl(CREATE_PAYMENT_URL);
paypalConfigBean.tExecutePaymentsUrl(EXECUTE_PAYMENT_URL);
paypalConfigBean.tGetPaymentsDetailsUrl(GET_PAYMENT_DETAILS);
paypalConfigBean.tSecret(SECRET);
}el {
/
/ load all properties for live
paypalConfigBean.tAccessTokenUrl(ACCESS_TOKEN_URL_LIVE);
paypalConfigBean.tClientId(CLIENT_ID_LIVE);
paypalConfigBean.tCreatePaymentsUrl(CREATE_PAYMENT_URL_LIVE);
paypalConfigBean.tExecutePaymentsUrl(EXECUTE_PAYMENT_URL_LIVE);
paypalConfigBean.tGetPaymentsDetailsUrl(GET_PAYMENT_DETAILS_LIVE);
paypalConfigBean.tSecret(SECRET_LIVE);
}
paypalConfigBean.tCancelUrl(CANCEL_URL);
paypalConfigBean.tReturnUrl(RETURN_URL);
}
/
/TODO paypal请求处理
/**获取paypal的Token解读中医
*/
public static String getAccessToken() {
Map<String, String> headers = new HashMap<String, String>();
String token = ClientId(), Secret());
headers.put("Content-Type", "application/x-www-form-urlencoded");
headers.put("accept-language", "en_US");
headers.put("Authorization", token);
String param = "grant_type=client_credentials";
try {
Map<String, String> data = HttpsUtils.doPost(headers, param, AccessTokenUrl());
if(!OUtils.("statusCode")) && ("statusCode").startsWith("2")){
JSONObject jsonObj = JSONObject.("data"));
String("access_token");
}el{
<("paypal的token获取失败,参数:"+token+",返回结果:"+data);
}
} catch (Exception e) {
<(e.getMessage());
}
return "";
}
/**创建订单
*/
public static String createOrder(HttpServletRequest req, String accessToken, String BaUrl){
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
headers.put("accept-language", "en_US");
headers.put("authorization", "Bearer "+accessToken);
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();//订单信息
Map<String, Object> order = new HashMap<String, Object>();
Map<String, String> orderInfo = new HashMap<String, String>();
orderInfo.put("currency_code", "USD");//⽀付货币
orderInfo.put("value", "100.00");//⽀付⾦额
order.put("reference_id","PUHF");//订单编号,多个订单时使⽤
order.put("amount", orderInfo);
list.add(order);
Map<String, String> redirects = new HashMap<String, String>();
redirects.put("return_url", BaUrl+"/"+ReturnUrl());//付款成功返回地址
redirects.put("cancel_url", BaUrl+"/"+CancelUrl());//付款失败返回地址
Map<String, Object> params = new HashMap<String, Object>();
params.put("intent", "CAPTURE");//创建付款
params.put("purcha_units", list);//订单信息
params.put("application_context", redirects);//返回地址,⽆效的地址
Map<String, Object> result = new HashMap<String, Object>();
try {
String param = JSONString(params);
Map<String, String> data = HttpsUtils.doPost(headers, param, CreatePaymentsUrl());
if(!OUtils.("statusCode")) && ("statusCode").startsWith("2")){
JSONObject jsonObj = JSONObject.("data"));
result.put("id", String("id"));
}el{
<("paypal创建订单失败,token:"+accessToken+",参数:"+param+",返回结果:"+data);
return new AjaxDto(0, "创建订单失败,请联系管理员...", req).toJson();
}
} catch (Exception e) {
<(e.getMessage());
}
return new AjaxDto(1, null, result).toJson();
}
/**执⾏paypal付款
*/
public static String executePayment(HttpServletRequest req, String accessToken, String orderId) throws Exception { Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
headers.put("Authorization", "Bearer "+accessToken);
String url = ExecutePaymentsUrl().trim();
url = place("{id}", orderId);
Map<String, Object> result = new HashMap<String, Object>();
try {
Map<String, String> data = HttpsUtils.doPost(headers, null, url);
if(!OUtils.("statusCode")) && ("statusCode").startsWith("2")){
JSONObject jsonObj = JSONObject.("data"));
result.put("id", String("id"));
怎么取消退款
}el{
<("paypal⽀付失败,token:"+accessToken+",返回结果:"+data);
return new AjaxDto(0, "⽀付失败,请联系管理员...", req).toJson();
}
} catch (Exception e) {
e.printStackTrace();
}
return new AjaxDto(1, null, result).toJson();
}
/**获取付款详情
*/
public static JSONObject getPaymentDetails(HttpServletRequest req, String accessToken, String orderId) throws Exception {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
headers.put("Authorization", "Bearer "+accessToken);
String url = GetPaymentsDetailsUrl().trim();
url = place("{id}", orderId);
String data = HttpsUtils.doGet(headers, url);
if(!OUtils.isEmpty(data)){
JSONObject jsonObj = JSONObject.parObject(data);
return jsonObj;
}
return null;
}
/**把paypal的clientId、cret转为Ba64
*/
private static String getBasicBearerToken(String clientId, String cret) {
String token = String().trim() +":"+String().trim();
token = place("\"", "");
Ba64 b = new Ba64();
String accessToken = b.encodeAsString(new String(token).getBytes());
return "Basic "+ accessToken;
}
/**paypal返回的错误
*/
private static String getPaypalError(String statusCode,String errorCode){
return "";
}
}
View Code
HttpUtils⼯具类(httpclient-4.5.jar、httpcore-4.4.1.jar)如下:
public class HttpsUtils {
private static final String HTTP = "http";
private static final String HTTPS = "https";
private static SSLConnectionSocketFactory sslsf = null;
private static PoolingHttpClientConnectionManager cm = null;
情侣小笑话
private static SSLContextBuilder builder = null;
static {
try {
builder = new SSLContextBuilder();
// 全部信任不做⾝份鉴定
builder.loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
return true;
}
});
sslsf = new SSLConnectionSocketFactory(builder.build(), new String[] { "SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2" }, null, NoopHostnameVerifier.INSTANCE);
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory> create().register(HTTP, new PlainConnectionSocketFactory()).register(HTTPS, sslsf).build(); cm = new PoolingHttpClientConnectionManager(registry);
cm.tMaxTotal(200);// max connection
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* httpClient post请求
*
* @param url
* 请求url
* @param header
* 头部信息
* @param param
* 请求参数 form提交适⽤
* @param entity
* 请求实体 json/xml提交适⽤
* @return可能为空需要处理
* @throws Exception
*
*/
public static String doGet(String url) throws Exception {
String result = "";
CloableHttpClient httpClient = null;
try {
httpClient = getHttpClient();
HttpGet httpGet = new HttpGet(url);
RequestConfig requestConfig = RequestConfig.custom().tSocketTimeout(30000).tConnectTimeout(30000).build();// 设置请求和传输超时时间
httpGet.tConfig(requestConfig);
HttpRespon httpRespon = ute(httpGet);
int statusCode = StatusLine().getStatusCode();
低碳社区
if (statusCode == HttpStatus.SC_OK) {
HttpEntity resEntity = Entity();
result = String(resEntity);
} el {
readHttpRespon(httpRespon);
}
} catch (Exception e) {
throw e;
} finally {
if (httpClient != null) {
httpClient.clo();
}
}
return result;
}
/**
* httpClient post请求
*
* @param url
* 请求url
* @param header
* 头部信息
* @param param
* 请求参数 form提交适⽤
* @param entity
* 请求实体 json/xml提交适⽤
* @return可能为空需要处理
* @throws Exception
*
*/
public static String doPost(String url, Map<String, String> header, Map<String, String> param, HttpEntity entity) throws Exception {
String result = "";
CloableHttpClient httpClient = null;
try {
httpClient = getHttpClient();
HttpPost httpPost = new HttpPost(url);
// 设置头信息
if (MapUtils.isNotEmpty(header)) {
for (Map.Entry<String, String> entry : Set()) {
httpPost.Key(), Value());
}
}
// 设置请求参数
if (MapUtils.isNotEmpty(param)) {
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> entry : Set()) {
// 给参数赋值
formparams.add(new Key(), Value()));
}
UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(formparams, Consts.UTF_8);
httpPost.tEntity(urlEncodedFormEntity);
}
// 设置实体优先级⾼
if (entity != null) {
httpPost.tEntity(entity);
}
HttpGet httpGet = new HttpGet(url);
HttpRespon httpRespon = ute(httpGet);
int statusCode = StatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
HttpEntity resEntity = Entity();
result = String(resEntity);
} el {
readHttpRespon(httpRespon);
}
} catch (Exception e) {
throw e;
} finally {
if (httpClient != null) {
httpClient.clo();
}
}
return result;
}
public static String doGet(Map<String, String> header, String url) throws Exception {
String result = "";
CloableHttpClient httpClient = null;
try {
httpClient = getHttpClient();
HttpGet httpGet = new HttpGet(url);
if (MapUtils.isNotEmpty(header)) {
for (Map.Entry<String, String> entry : Set()) {
httpGet.Key(), Value());
}
}
RequestConfig requestConfig = RequestConfig.custom().tSocketTimeout(30000).tConnectTimeout(30000).build();// ��������ʹ��䳬ʱʱ�� httpGet.tConfig(requestConfig);
HttpRespon httpRespon = ute(httpGet);
int statusCode = StatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
HttpEntity resEntity = Entity();
result = String(resEntity);
} el {
readHttpRespon(httpRespon);
}
} catch (Exception e) {
throw e;
} finally {
if (httpClient != null) {
httpClient.clo();
}
}
return result;
}
public static Map<String, String> doPost(Map<String, String> header, String param, String url) throws Exception {
Map<String, String> data = new HashMap<String, String>();
CloableHttpClient httpClient = null;
try {
httpClient = getHttpClient();
HttpPost httpPost = new HttpPost(url);
if (MapUtils.isNotEmpty(header)) {
for (Map.Entry<String, String> entry : Set()) {
httpPost.Key(), Value());
}
}
if (!OUtils.isEmpty(param)) {
httpPost.tEntity(new StringEntity(param));
}
HttpRespon httpRespon = ute(httpPost);
HttpEntity resEntity = Entity();
data.put("statusCode", String.StatusLine().getStatusCode()));
data.put("data", String(resEntity));
} catch (Exception e) {
throw e;
} finally {
if (httpClient != null) {
httpClient.clo();
}
}
return data;
}
public static CloableHttpClient getHttpClient() throws Exception {
CloableHttpClient httpClient = HttpClients.custom().tSSLSocketFactory(sslsf).tConnectionManager(cm).tConnectionManagerShared(true).build();