New file |
| | |
| | | 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; |
| | | } |
| | | |
| | | |
| | | } |