package com.dsh.course.util.midtrans;
|
|
import com.alibaba.fastjson.JSON;
|
import com.midtrans.Config;
|
import com.midtrans.Midtrans;
|
import com.midtrans.httpclient.SnapApi;
|
import com.midtrans.httpclient.TransactionApi;
|
import com.midtrans.httpclient.error.MidtransError;
|
import org.json.JSONObject;
|
|
import javax.servlet.http.HttpServletRequest;
|
import java.io.BufferedReader;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.InputStreamReader;
|
import java.nio.charset.StandardCharsets;
|
import java.security.MessageDigest;
|
import java.security.NoSuchAlgorithmException;
|
import java.util.HashMap;
|
import java.util.Map;
|
|
/**
|
* Midtrans支付工具类
|
* @author pzb
|
* @Date 2022/11/28 14:19
|
*/
|
public class MidtransUtil {
|
|
private static String sandbox_merchant_id = "G118246934";
|
|
private static String sandbox_serverKey = "SB-Mid-server-qR4Xy4kbpyxND_7f6c1_knb9";
|
|
private static String sandbox_clientKey = "SB-Mid-client-xhRbIV8lsbu7bKCE";
|
|
private static String merchant_id = "G118246934";
|
|
private static String serverKey = "Mid-server-w1ATM2ldDpd0c4Q0s9sNfeNN";
|
|
private static String clientKey = "Mid-client-X22yMA1Wvs0v1vfO";
|
|
|
/**
|
* 获取支付令牌
|
* @param order_id 商户订单id
|
* @param gross_amount 支付金额
|
* @param xOverrideNotification 支付状态通知回调地址
|
* @return
|
*/
|
public static TokenResult getPayToken(String order_id, String gross_amount, String xOverrideNotification){
|
//沙箱环境
|
Midtrans.serverKey = sandbox_serverKey;
|
Midtrans.clientKey = sandbox_clientKey;
|
Midtrans.isProduction = false;
|
|
//生产环境
|
// Midtrans.serverKey = serverKey;
|
// Midtrans.clientKey = clientKey;
|
// Midtrans.isProduction = true;
|
|
Midtrans.paymentOverrideNotification(xOverrideNotification);
|
// Create Token and then you can send token variable to FrontEnd,
|
// to initialize Snap JS when customer click pay button
|
//201 成功创建 Snap 令牌。 “令牌”:“66e4fa55-fdac-4ef9-91b5-733b97d1b862”
|
//401 未能创建令牌,因为发送了错误的授权。 “访问被拒绝,请检查客户端或服务器密钥”
|
//4xx 未能创建令牌,因为发送了错误的参数。按照 error_message 并检查您的参数。 “transaction_details.gross_amount 不等于 item_details 的总和”
|
//5xx 由于 Midtrans 内部错误,无法创建令牌。大多数情况下这是暂时的,您可以稍后重试。 “抱歉,我们遇到内部服务器错误。我们会尽快解决这个问题。”
|
|
try {
|
JSONObject transaction = SnapApi.createTransaction(requestBody(order_id, gross_amount), Config.getGlobalConfig());
|
TokenResult tokenResult = new TokenResult();
|
tokenResult.setToken(transaction.getString("token"));
|
tokenResult.setRedirect_url(transaction.getString("redirect_url"));
|
return tokenResult;
|
} catch (MidtransError midtransError) {
|
midtransError.printStackTrace();
|
}
|
return null;
|
}
|
|
|
// Create params JSON Raw Object request
|
public static Map<String, Object> requestBody(String order_id, String gross_amount) {
|
Map<String, Object> params = new HashMap<>();
|
Map<String, String> transactionDetails = new HashMap<>();
|
transactionDetails.put("order_id", order_id);
|
transactionDetails.put("gross_amount", gross_amount);
|
Map<String, String> creditCard = new HashMap<>();
|
creditCard.put("secure", "true");
|
params.put("transaction_details", transactionDetails);
|
params.put("credit_card", creditCard);
|
return params;
|
}
|
|
|
/**
|
* 获取订单支付状态
|
* @param order_id
|
* @return
|
*/
|
public static PaymentNotice getPayStatus(String order_id){
|
//沙箱环境
|
Midtrans.serverKey = sandbox_serverKey;
|
Midtrans.clientKey = sandbox_clientKey;
|
Midtrans.isProduction = false;
|
|
//生产环境
|
// Midtrans.serverKey = serverKey;
|
// Midtrans.clientKey = clientKey;
|
// Midtrans.isProduction = true;
|
JSONObject jsonObject = null;
|
try {
|
jsonObject = TransactionApi.checkTransaction(order_id);
|
} catch (MidtransError midtransError) {
|
midtransError.printStackTrace();
|
}
|
PaymentNotice paymentNotice = JSON.parseObject(jsonObject.toString(), PaymentNotice.class);
|
if(null == paymentNotice){
|
System.err.println("回调结果解析失败");
|
return null;
|
}
|
String signature_key = paymentNotice.getSignature_key();
|
order_id = paymentNotice.getOrder_id();
|
String status_code = paymentNotice.getStatus_code();
|
if("400".equals(status_code)){
|
System.err.println("数据丢失或无效");
|
return null;
|
}
|
if("401".equals(status_code)){
|
System.err.println("授权错误");
|
return null;
|
}
|
if("404".equals(status_code)){
|
System.err.println("找不到请求的资源");
|
return null;
|
}
|
String gross_amount = paymentNotice.getGross_amount();
|
String sha_512_securePassword = get_SHA_512_SecurePassword(order_id + status_code + gross_amount + sandbox_serverKey);
|
if(!signature_key.equals(sha_512_securePassword)){
|
System.err.println("签名校验失败");
|
return null;
|
}
|
return paymentNotice;
|
}
|
|
|
/**
|
* 支付回调解析
|
* @param request
|
* @return
|
*/
|
public static PaymentNotice payResultNotification(HttpServletRequest request){
|
String param = null;
|
try {
|
param = getParam(request);
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
|
System.err.println("支付回调结果:========》" + param);
|
|
PaymentNotice paymentNotice = JSON.parseObject(param, PaymentNotice.class);
|
if(null == paymentNotice){
|
System.err.println("回调结果解析失败");
|
return null;
|
}
|
String signature_key = paymentNotice.getSignature_key();
|
String order_id = paymentNotice.getOrder_id();
|
String status_code = paymentNotice.getStatus_code();
|
if("400".equals(status_code)){
|
System.err.println("数据丢失或无效");
|
return null;
|
}
|
if("401".equals(status_code)){
|
System.err.println("授权错误");
|
return null;
|
}
|
if("404".equals(status_code)){
|
System.err.println("找不到请求的资源");
|
return null;
|
}
|
String gross_amount = paymentNotice.getGross_amount();
|
String sha_512_securePassword = get_SHA_512_SecurePassword(order_id + status_code + gross_amount + sandbox_serverKey);
|
if(!signature_key.equals(sha_512_securePassword)){
|
System.err.println("签名校验失败");
|
return null;
|
}
|
return paymentNotice;
|
}
|
|
|
/**
|
* 退款交易
|
* @param transaction_id 支付订单id
|
* @param refund_key 商户退款id
|
* @param amount 退款金额
|
* @param reason 退款说明
|
* @return
|
*/
|
public static DirectRefundTransaction directRefundTransaction(String transaction_id, String refund_key, String amount, String reason){
|
//沙箱环境
|
Midtrans.serverKey = sandbox_serverKey;
|
Midtrans.clientKey = sandbox_clientKey;
|
Midtrans.isProduction = false;
|
|
//生产环境
|
// Midtrans.serverKey = serverKey;
|
// Midtrans.clientKey = clientKey;
|
// Midtrans.isProduction = true;
|
|
Map<String, String> requestBody = new HashMap<>();
|
requestBody.put("refund_key", refund_key);
|
requestBody.put("amount", amount);
|
requestBody.put("reason", reason);
|
|
JSONObject jsonObject = null;
|
try {
|
jsonObject = TransactionApi.directRefundTransaction(transaction_id, requestBody);
|
} catch (MidtransError midtransError) {
|
midtransError.printStackTrace();
|
}
|
/**
|
* {
|
* "status_code": "200",
|
* "status_message": "Success, refund request is approved by the bank",
|
* "transaction_id": "fddb5889-fd39-46fe-809d-30679fe42434",
|
* "order_id": "MID-1620622357",
|
* "gross_amount": "10000.00",
|
* "payment_type": "credit_card",
|
* "transaction_time": "2016-06-28 09:42:20",
|
* "transaction_status": "refund",
|
* "refund_chargeback_id": 47594,
|
* "refund_amount": "10000.00",
|
* "refund_key": "01f1f771-b75c-48ef-b21d-193a79f8aa5b"
|
* }
|
*/
|
|
DirectRefundTransaction directRefundTransaction = JSON.parseObject(jsonObject.toString(), DirectRefundTransaction.class);
|
if(null == directRefundTransaction){
|
System.err.println("退款结果解析失败");
|
return null;
|
}
|
String status_code = directRefundTransaction.getStatus_code();
|
if("400".equals(status_code)){
|
System.err.println("数据丢失或无效");
|
return null;
|
}
|
if("401".equals(status_code)){
|
System.err.println("授权错误");
|
return null;
|
}
|
if("404".equals(status_code)){
|
System.err.println("找不到请求的资源");
|
return null;
|
}
|
return directRefundTransaction;
|
}
|
|
|
|
|
/**
|
* 获取请求内容
|
* @param request
|
* @return
|
* @throws IOException
|
*/
|
private static String getParam(HttpServletRequest request) throws IOException {
|
// 读取参数
|
InputStream inputStream;
|
StringBuilder sb = new StringBuilder();
|
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();
|
return sb.toString();
|
}
|
|
|
private static String get_SHA_512_SecurePassword(String passwordToHash){
|
String generatedPassword = null;
|
try {
|
MessageDigest md = MessageDigest.getInstance("SHA-512");
|
byte[] bytes = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));
|
StringBuilder sb = new StringBuilder();
|
for(int i=0; i< bytes.length ;i++){
|
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
|
}
|
generatedPassword = sb.toString();
|
} catch (NoSuchAlgorithmException e) {
|
e.printStackTrace();
|
}
|
return generatedPassword;
|
}
|
|
|
}
|