sofort 支付 版本sofort/开发语言java/使用场景PC端网站

一、注册sofort 交易账号

注册中须填公司基本信息、绑定银行卡等,个人感觉让财务或行政做就行了,开发人员就不要搞了

https://www.sofort.com/integrationCenter-eng-DE/content/view/full/4520此链接是sofort关于注册、项目创建等的引导说明,按照步骤来就行了。

创建项目有Gateway project 和 Classic project两种,一般选择Gateway project 即可。测试模式当然要勾选,方便测试。 notificationURL 、successURL 、 abortURL 、 timeoutURL要根据项目实际情况填写,注意最好是https路径哦。

创建完项目后只能测试用,需要你**项目才能用于生产环境。

创建完后在My projects页面,点击你创建的项目,进入下图页面,Base setting窗口有你代码中需要的customerId、projectId和apiKey,Test the project窗口有你测试需要银行信息。

sofort 支付 版本sofort/开发语言java/使用场景PC端网站


二、API类型选择及源码下载

https://www.sofort.com/integrationCenter-eng-DE/integration/API-SDK/#2861-sue此链接API类型选择及源码下载

下图选择API版本

sofort 支付 版本sofort/开发语言java/使用场景PC端网站

下图源码下载及跳转到API文档页面,源码是gradle构建的,习惯maven的朋友百度搜下gradle的基本使用即可。(本人项目是电子商务网站,所以选择的是Sofort版,语言是java)

sofort 支付 版本sofort/开发语言java/使用场景PC端网站

开发前建议先看看API文档,另外sofort有点坑,没有可用的sdk jar包,需要你下载源码后自己打成jar包。

三、写代码喽

直接参照sofort给的示例写就可以了。如下如目录:

sofort 支付 版本sofort/开发语言java/使用场景PC端网站

四、本人代码

1、支付接口(跟sofort实例代码基本一样,只是方法变成静态方便调用,另外交易ID存入session方便回调获取session信息)

package com.aurorascm.pay;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.apache.shiro.session.Session;
import com.aurorascm.util.Jurisdiction;
import com.sofort.lib.core.internal.net.ConnectionException;
import com.sofort.lib.core.internal.net.http.HttpAuthorizationException;
import com.sofort.lib.core.internal.net.http.HttpConnectionException;
import com.sofort.lib.core.internal.transformer.RawResponse;
import com.sofort.lib.core.internal.transformer.RawResponse.Status;
import com.sofort.lib.core.internal.utils.StringUtilities;
import com.sofort.lib.core.products.request.parts.Notification;
import com.sofort.lib.core.products.response.SofortTransactionStatusNotification;
import com.sofort.lib.payment.DefaultSofortLibPayment;
import com.sofort.lib.payment.products.request.PaymentRequest;
import com.sofort.lib.payment.products.request.PaymentTransactionDetailsRequest;
import com.sofort.lib.payment.products.response.PaymentResponse;
import com.sofort.lib.payment.products.response.PaymentTransactionDetailsResponse;
import com.sofort.lib.payment.products.response.parts.PaymentTransactionDetails;
/**
 * An example of usage of the SofortLib Payment (SOFORT Überweisung).
 * 
 * 1st - use PaymentInitaliser to initialise a new payment
 * 
 * 2nd - start/resume/check listening on notificationUrls (see the SOFORT API
 * documentation)
 * 
 * 3rd - use the NotificationParser to parse and handle received status
 * notifications
 * 
 * 4th - use TransactionDetailsService to retrieve transaction details
 */
public class SofortPayment {

// https://域名/sofort/success(success-link)
// https://域名/sofort/abort(abort-link)
// https://域名/sofort/http_notification(HTTP_notification)
// https://域名/sofort/payment(Timeout-link)


// private static final ResourceBundle CORE_BUNDLE = ResourceBundle.getBundle("core");
private static final int customerId = 你的账号ID;//Integer.parseInt(CORE_BUNDLE.getString("customerId"));
private static final int projectId = 你的项目ID;//Integer.parseInt(CORE_BUNDLE.getString("projectId"));
private static final String apiKey = "你的apiKey";//CORE_BUNDLE.getString("apiKey");
private static final String currency = "EUR";//货币单位


// private static final ResourceBundle PAYMENT_BUNDLE = ResourceBundle.getBundle("payment");
private static final String notificationURL = "https://域名/sofort/http_notification";//PAYMENT_BUNDLE.getString("notificationURL");
private static final String successURL = "https://域名/sofort/success";//PAYMENT_BUNDLE.getString("successURL");
private static final String abortURL = "https://域名/sofort/abort";//PAYMENT_BUNDLE.getString("abortURL");
private static final String timeoutURL = "https://域名/sofort/timeout";//PAYMENT_BUNDLE.getString("timeoutURL");


public static class PaymentInitialiser {


/**
* Start a sofort payment, check for errors and warnings and use the
* received payment url for redirection of the customer.

* @return the payment URL the customer have to be redirected to
*/
public static String sofortPayment(double amount) {
boolean consumerProtection = Boolean.TRUE;
String[] purposes = {"aurora-germany-trade"};
PaymentRequest paymentRequest = new PaymentRequest(projectId, amount, currency, Arrays.asList(purposes), consumerProtection)
.setNotificationUrls(Arrays.asList(new Notification(notificationURL)))
.setSuccessUrl(successURL)
.setAbortUrl(abortURL)
.setTimeoutUrl(timeoutURL);


// initialise a payment.
PaymentResponse paymentResponse = doRequest(paymentRequest);


// handle the transaction ID.
handlePayment(paymentResponse);

/**此处为本人添加将交易ID放入session,在成功路径中获取交易信息。像支付宝、paypal能直接取得交易信息,但sofort试了很久没有找出办法,只得放session中,另外支付宝、paypal回调后session是失效的,但是sofort 回调后session没有失效。可能就是这样取交易信息吧。*/
String transId = paymentResponse.getTransId();

Session session = Jurisdiction.getSession(); 

String key = Jurisdiction.getCustomerID() + "sofortTransId";
session.setAttribute(key, transId);


// redirection URL.
return paymentResponse.getPaymentUrl();
}
private static PaymentResponse doRequest(PaymentRequest paymentRequest) {
PaymentResponse paymentResponse;
try {
paymentResponse = new DefaultSofortLibPayment(customerId, apiKey).sendPaymentRequest(paymentRequest);
} catch (HttpAuthorizationException e) {
System.err.println("The authorization with the given apiKey has been failed.");
throw e;
} catch (HttpConnectionException e) {
System.err.println("The HTTP communication has been failed. Response/status code: " + e.getResponseCode());
throw e;
} catch (ConnectionException e) {
System.err.println("The communication has been failed.");
throw e;
}
// check and handle the response errors and warnings
if (paymentResponse.hasResponseErrors()) {
throw new IllegalStateException("Initialization errors: " + new StringUtilities().glue(paymentResponse.getResponseErrors(), " /// "));
}
if (paymentResponse.hasResponseWarnings()) {
System.err.println("Initialisation warnings: " + new StringUtilities().glue(paymentResponse.getResponseWarnings(), " /// "));
}
// check and handle the payment errors and warnings
if (paymentResponse.hasResponsePaymentErrors()) {
throw new IllegalStateException("Could not initialize a sofort payment. Errors: " + new StringUtilities().glue(paymentResponse.getResponsePaymentErrors(), " /// "));
}
if (paymentResponse.hasNewPaymentWarnings()) {
System.err.println("Initialisation of a new payment warnings: " + new StringUtilities().glue(paymentResponse.getNewPaymentWarnings(), " /// "));
}
return paymentResponse;
}
private static void handlePayment(PaymentResponse paymentResponse) {
// handle initialised payment, i.e. store transId into DB
}
}
public static class NotificationParser {
/**
* Parse the received transaction changes notification.

* @param statusNotification
*            received status notification
* @param status
* @return
*/
public SofortTransactionStatusNotification parseManualReceivedStatusNotification(Status status, String statusNotificationRaw) {
SofortTransactionStatusNotification statusNotification = new DefaultSofortLibPayment(customerId, apiKey).parseStatusNotificationResponse(new RawResponse(status, statusNotificationRaw));
// check and handle the response errors and warnings
if (statusNotification.hasResponseErrors()) {
throw new IllegalStateException("Parsed status notification contains errors. Errors: " + new StringUtilities().glue(statusNotification.getResponseErrors(), " /// "));
}
if (statusNotification.hasResponseWarnings()) {
System.err.println("Parsed status notification contains warnings. Warnings: " + new StringUtilities().glue(statusNotification.getResponseWarnings(), " /// "));
}
return statusNotification;
}
}
public static class TransactionDetailsService {
/**
* Get transaction details for a transaction.

* @param transIds
*            - transaction ids
* @return list of transaction details
*/
public static List<PaymentTransactionDetails> getDetails(String... transIds) {
PaymentTransactionDetailsRequest transactionRequest = new PaymentTransactionDetailsRequest()
.setTransIds(Arrays.asList(transIds));
return doRequest(transactionRequest).getTransactions();
}
/**
* Get transaction details for a time span.

* @param from
*            start date
* @param to
*            end date

* @return list of transaction details
*/
public List<PaymentTransactionDetails> getDetails(Date from, Date to) {
PaymentTransactionDetailsRequest transactionRequest = new PaymentTransactionDetailsRequest()
.setFromTime(from)
.setToTime(to);
return doRequest(transactionRequest).getTransactions();
}
private static PaymentTransactionDetailsResponse doRequest(PaymentTransactionDetailsRequest transactionRequest) {
PaymentTransactionDetailsResponse transactionDetailsResponse;
try {
transactionDetailsResponse = new DefaultSofortLibPayment(customerId, apiKey).sendTransactionDetailsRequest(transactionRequest);
} catch (HttpAuthorizationException e) {
System.err.println("The authorization with the given apiKey has been failed.");
throw e;
} catch (HttpConnectionException e) {
System.err.println("The HTTP communication has been failed. Response/status code: " + e.getResponseCode());
throw e;
} catch (ConnectionException e) {
System.err.println("The communication has been failed.");
throw e;
}
// check and handle the response errors
if (transactionDetailsResponse.hasResponseErrors()) {
throw new IllegalStateException("Initialization errors: " + new StringUtilities().glue(transactionDetailsResponse.getResponseErrors(), " /// "));
}
if (transactionDetailsResponse.hasResponseWarnings()) {
System.err.println("Initialisation warnings: " + new StringUtilities().glue(transactionDetailsResponse.getResponseWarnings(), " /// "));
}=
return transactionDetailsResponse;
}
}
}

2、控制器

package com.aurorascm.controller.pay;

import java.io.IOException;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.shiro.session.Session;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.xml.sax.SAXException;
import com.aurorascm.controller.base.BaseController;
import com.aurorascm.pay.SofortPayment;
import com.aurorascm.util.Jurisdiction;
import com.sofort.lib.core.internal.transformer.RawResponse.Status;
import com.sofort.lib.payment.products.response.parts.PaymentStatus;
import com.sofort.lib.payment.products.response.parts.PaymentTransactionDetails;


/** Sofort支付控制器
 * @author 
 * @version 1.0
 */
@Controller
//
@RequestMapping(value="/sofort")
public class SofortCommonController extends BaseController {


/**Sofort 支付接口
* @author BYG/2018.1.10
* @param String orderID;
* @return String sofortPayUrl;
* @throws Exception
*/
@RequestMapping(value="/payment", produces="application/json;charset=UTF-8")
@ResponseBody
public String sofortPayment(String orderID)throws Exception{
//    BigDecimal shouldPayment = orderServiceImpl.getShouldPayByOID(orderID);//订单实际应付金额
//    double amount = shouldPayment.doubleValue();
double amount = 1;
String sofortPayUrl = SofortPayment.PaymentInitialiser.sofortPayment(amount);//sofort 支付路径
logger.info("sofort-sofortPayment-" + sofortPayUrl);
return sofortPayUrl;
}

/**Sofort 支付成功
* @author BYG/2018.1.10
* @param 
* @throws ParserConfigurationException 
* @throws IOException 
* @throws SAXException 
*/
@RequestMapping(value="/success", produces="application/xml;charset=UTF-8")
@ResponseBody
    public String success() throws ParserConfigurationException{
Session session = Jurisdiction.getSession(); 
String key = Jurisdiction.getCustomerID() + "sofortTransId";
String transId = session.getAttribute(key).toString();
String[] transIds = {transId};
List<PaymentTransactionDetails> transactions = SofortPayment.TransactionDetailsService.getDetails(transIds);
double amount = transactions.get(0).getAmount();
PaymentStatus status = transactions.get(0).getStatus();
return null;
    }

/**sofort 通知
* @author 
* @param 
* @throws ParserConfigurationException 
* @throws Exception
*/
@RequestMapping(value="/http_notification", produces="application/xml;charset=UTF-8")
@ResponseBody
    public void http_notification(Status status, String statusNotificationRaw) throws ParserConfigurationException{
/** 很遗憾没有想到获取异步通知信息的方法*/
}

/**Sofort 支付中止
* @author
* @param 
*/
@RequestMapping(value="/abort", produces="application/json;charset=UTF-8")
    public String abort(ModelMap modelMap){
/** 支付成功   */
modelMap.put("payResult", "abort");
return "system/pay/sofort/abort";
    }

/**Sofort 支付超时
* @author 
* @param 
*/
@RequestMapping(value="/timeout", produces="application/json;charset=UTF-8")
    public String timeout(ModelMap modelMap){
/** 支付成功   */
modelMap.put("payResult", "timeout");
return "system/pay/sofort/timeout";
    }

}

最后很遗憾我们公司没有接sofort,因为sofort**需要网站有德语版,我们小公司没有时间搞啊。。。另外吐槽下sofort客服,跟客服的沟通是我欲哭无泪。。。。