|
|
@@ -0,0 +1,149 @@
|
|
|
+package cn.iocoder.yudao.module.system.controller.admin.pay;
|
|
|
+
|
|
|
+import cn.iocoder.yudao.module.system.util.pay.CertUtils;
|
|
|
+import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
|
|
|
+import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
|
|
|
+import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
|
|
|
+import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
|
|
|
+import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
|
|
|
+import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
|
|
|
+import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
|
|
|
+import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;
|
|
|
+import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
|
|
|
+import com.wechat.pay.contrib.apache.httpclient.util.RsaCryptoUtil;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.http.client.methods.CloseableHttpResponse;
|
|
|
+import org.apache.http.client.methods.HttpPost;
|
|
|
+import org.apache.http.entity.StringEntity;
|
|
|
+import org.apache.http.impl.client.CloseableHttpClient;
|
|
|
+import org.aspectj.lang.annotation.Before;
|
|
|
+import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
+import org.springframework.web.bind.annotation.RestController;
|
|
|
+
|
|
|
+import javax.crypto.BadPaddingException;
|
|
|
+import javax.crypto.IllegalBlockSizeException;
|
|
|
+import java.io.IOException;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.GeneralSecurityException;
|
|
|
+import java.security.PrivateKey;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 微信小程序统一下单控制器
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@RestController
|
|
|
+@RequestMapping("/pay/wx")
|
|
|
+public class WeChatPayController {
|
|
|
+
|
|
|
+ private CloseableHttpClient httpClient;
|
|
|
+ private CertificatesManager certificatesManager;
|
|
|
+ private Verifier verifier;
|
|
|
+
|
|
|
+ private static final String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzbDDaK6pFz8fEBIM/pFlIV4uApuhr/TDm8mlK0+Cw1+om1p2s2RFItgBw7Gk9qTN72L68utj5bEDJRQgdr1ixAjc4AH1AOYeV4YZnWTQkcjsRiEimqo+bkIm+osTpFEO9kdvfFMILOl1MDipIAcUrNq9CMs6s6nFDLxLlwy8Ap4VrP4N+FF04efG+8dj35z8dUdi/8WrAe4p7GYGojHHoZ/mIqEDnLdt+PM5pRizCfUCtmSF5UxnmNUlUAutIedvtOAT9rs9E71aO+ldhXNMfA+jLxuBmyp+oy3hWS4Vqp4RbC1a2xRSULvEgSUwrdNq/rytpK66/XY7Vk2f/onCdAgMBAAECggEAXtI/ox1OeGSN01b7MggeMzApBo2u6Vs+m97irGv7JBqHoYzseWuiScX9x6/5EmA4WCw86Srp/i8qsfOsjVucyLc+DXecufNtZ1VvnXC0MMq50tMuaf5btMAXO8tzuyY9gpLyGxwyTJLEuawGxlVBKUxWJOsK9LFVuEbJeunDDlmWsn+euRw3F7jxtNnjVjfqXsY9O+TtB8p0bOduWZc7OvDHoIZQL4NnDivnAR5q1dSLt77pzdinvGiXNYNuTTULstR+KVhJy5Kmsldtj3nrP/fcy/N+JsXm9+3xgaJ2edKwmfnwvQjJAWOtltOSoHx4RK3kzbC8UhKs/E3iaUEUgQKBgQDp0qoNKHbTCiwDhmrnnCyaoW16qEOj0MqHOy5mKYmJkcSDGgNQM/44gN7vOu5BBJHXdkizxaoX3w/ufW2ahhJ/LcjITjFIq8gpiFKbLNfhkCw47ZDtmhB9jAnaB+9+rLeAFXkfXKi+PYJGZIIzbgn0u5LADzRjvzaxe/Z+Ed5ooQKBgQDEcKkk0SmcsHdTkLs2kf6fu8z7MAg9l42fCO18TPt3PeoRcvf8AKw+WDjARSo0ojqL23T9U0IydKdsbcxrYsHETUBS+MAP09Ckpd8p7F5evJghXwhhQRx0gzVuNMkbeP1a3xnC3yL7V5fluGQqz7Xiv3sg9dxYDh8cVQBu6ckafQKBgQCcoF0Ay2YtH9cz1UqvMtI+Enw/eY81oJrJ0z7VeGWFHXvBRh+KDgnw14J+Rb9rFiCLb9Rrd7DkpKsLWkGdDMo/HvAsHRSuVUOTbpnHEFbb5bN5vskiH92D+9Ztkns/I3sX9UpZU7xFEva9KH5+7OsGYM+Aj67MUj3UzfDjqhyNgQKBgFcNojeZpbo1jbvvsLd/PXqmLDHI2G4LIoyu1Se3qdzvCDLRY0o/NhWu3P9/5zNKDW37RD4bToOzpJptkiCotDv9DBt49wxMjvLYOyyF/lA3faeUSM9onmaX2u7K37CYDpbdtbnhTsxZxgvcii9auz0QJE24BvzSzUCt/rIoUqG1AoGAX9sTEp77kdVrM8ECEKgLsOtRWEAgeNkWLgHZKYcEYyu3D4XEVScYNtTBLBHXs3n1GIYdLjWEAWWb55sqKSlVzVWfOhpnOqoFq51xi2TGr3pkp9cqZf0lxYKs7P4tlgeL0icXfb+lFTPmgfgE5vjHBvYQcj7o9lO5hRe46fVoxT8=";
|
|
|
+
|
|
|
+ private static final String merchantId = "1105835366";
|
|
|
+
|
|
|
+ private static final String certPem = "MIIELjCCAxagAwIBAgIUOjdSdMmYC2qOKZOM68wXFlQcfbEwDQYJKoZIhvcNAQEL\n" +
|
|
|
+ "BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\n" +
|
|
|
+ "FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg\n" +
|
|
|
+ "Q0EwHhcNMjYwMzAyMDM0MzM5WhcNMzEwMzAxMDM0MzM5WjCBhzETMBEGA1UEAwwK\n" +
|
|
|
+ "MTEwNTgzNTM2NjEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTMwMQYDVQQL\n" +
|
|
|
+ "DCrpopDlubTlgaXlurfkuqfkuJrvvIjpm4blm6LvvInmnInpmZDlhazlj7gxCzAJ\n" +
|
|
|
+ "BgNVBAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQAD\n" +
|
|
|
+ "ggEPADCCAQoCggEBALNsMNorqkXPx8QEgz+kWUhXi4Cm6Gv9MObyaUrT4LDX6ibW\n" +
|
|
|
+ "nazZEUi2AHDsaT2pM3vYvry62PlsQMlFCB2vWLECNzgAfUA5h5XhhmdZNCRyOxGI\n" +
|
|
|
+ "SKaqj5uQib6ixOkUQ72R298Uwgs6XUwOKkgBxSs2r0IyzqzqcUMvEuXDLwCnhWs/\n" +
|
|
|
+ "g34UXTh58b7x2PfnPx1R2L/xasB7insZgaiMcehn+YioQOct2348zmlGLMJ9QK2Z\n" +
|
|
|
+ "IXlTGeY1SVQC60h52+04BP2uz0TvVo76V2Fc0x8D6MvG4GbKn6jLeFZLhWqnhFsL\n" +
|
|
|
+ "VrbFFJQu8SBJTCt02r+vK2krrr9djtWTZ/+icJ0CAwEAAaOBuTCBtjAJBgNVHRME\n" +
|
|
|
+ "AjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDov\n" +
|
|
|
+ "L2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUw\n" +
|
|
|
+ "REJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJF\n" +
|
|
|
+ "MTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IB\n" +
|
|
|
+ "AQAVEO4RR9o+W0SySh9S6RwLV9e+GNl96K8BnfswLMeTcZTA5XJQRTfCSlE5v/mf\n" +
|
|
|
+ "NQw5HdDigF2BeIDJqWSDyApbILfngsZadH0I6fDk1u2zifeIQcN0C9yFRPn2uf3O\n" +
|
|
|
+ "YRc2sX7CJdPSbMGFaozaH40uZDl86/63qVFMuaOa3iAwiqQVVsSOcnhUhLBL1fh/\n" +
|
|
|
+ "0AauGFk5fyGgNqMIJ+7+z+nBtWfq1i2quRda66Ao0ytQP+L5CV0jePmQ0uOiv8AE\n" +
|
|
|
+ "EcqAqJ+/d0nqhFd7hVcmW+uzQ3eTTeuHnsAZt7bkUhTF5PJBvZipI+CYtUhZFlaT\n" +
|
|
|
+ "rXbHeFgiQcZb/sR8sTBV0KXR";
|
|
|
+
|
|
|
+ private static final String apiV3Key = "W2sE4rF6tY8uI0oP1aQ2wS3dF4gH5jK6";
|
|
|
+ public void setup() throws Exception {
|
|
|
+ String merchantSerialNumber = CertUtils.getMerchantSerialNumberFromPem(certPem);
|
|
|
+ PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(privateKey);
|
|
|
+ certificatesManager = CertificatesManager.getInstance();
|
|
|
+ certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId,
|
|
|
+ new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),
|
|
|
+ apiV3Key.getBytes(StandardCharsets.UTF_8));
|
|
|
+ verifier = certificatesManager.getVerifier(merchantId);
|
|
|
+ WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
|
|
|
+ .withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
|
|
|
+ .withValidator(new WechatPay2Validator(verifier));
|
|
|
+ httpClient = builder.build();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void encryptedTest() throws IllegalBlockSizeException {
|
|
|
+ String text = "helloWorld";
|
|
|
+ String transformation = "RSA/ECB/PKCS1Padding";
|
|
|
+ String encryptedText = RsaCryptoUtil.encrypt(text, verifier.getValidCertificate(), transformation);
|
|
|
+ System.out.println(encryptedText);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void decryptedTest() throws BadPaddingException {
|
|
|
+ String encryptedText = "";
|
|
|
+ String transformation = "RSA/ECB/PKCS1Padding";
|
|
|
+ String decryptedText = RsaCryptoUtil.decrypt(encryptedText, PemUtil.loadPrivateKey(privateKey), transformation);
|
|
|
+ assert("helloWorld".equals(decryptedText));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //Call Unified Order API
|
|
|
+ public void unifiedOrderTest() throws IOException {
|
|
|
+ String unifiedOrderBody = String.join("\n" ,
|
|
|
+ "{" ,
|
|
|
+ "'sp_appid': 'wx2421b1c4370ec43b'," ,
|
|
|
+ "'sp_mchid': '10000100'," ,
|
|
|
+ "'sub_mchid': '20000100'," ,
|
|
|
+ "'sub_appid': 'wx352671b037b437ec'," ,
|
|
|
+ "'out_trade_no': '20150806125346'," ,
|
|
|
+ "'merchant_category_code': '1011'," ,
|
|
|
+ "'payer': {" ,
|
|
|
+ "'sub_openid': 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o'" ,
|
|
|
+ "}," ,
|
|
|
+ "'notify_url': 'https://wxpay.wxutil.com/pub_v2/pay/notify.v2.php'," ,
|
|
|
+ "'trade_type': 'JSAPI'," ,
|
|
|
+ "'amount': {" ,
|
|
|
+ "'total': 10000," ,
|
|
|
+ "'currency': 'HKD'" ,
|
|
|
+ "}," ,
|
|
|
+ "'attach': 'Payment test'," ,
|
|
|
+ "'description': 'Miniprogramm Pay test'," ,
|
|
|
+ "'detail': {" ,
|
|
|
+ "'cost_price': 10000," ,
|
|
|
+ "'receipt_id': '1234'," ,
|
|
|
+ "'goods_detail': [{" ,
|
|
|
+ "'goods_id': 'iphone6s_16G'," ,
|
|
|
+ "'wxpay_goods_id': '1001'," ,
|
|
|
+ "'goods_name': 'iPhone6s 16G'," ,
|
|
|
+ "'quantity': 1," ,
|
|
|
+ "'price': 528800" ,
|
|
|
+ "}]" ,
|
|
|
+ "}," ,
|
|
|
+ "'scene_info': {" ,
|
|
|
+ "'payer_client_ip': '14.23.150.211'," ,
|
|
|
+ "'device_ip': '59.37.125.32'," ,
|
|
|
+ "'device_id': '013467007045764'," ,
|
|
|
+ "'operator_id': 'P001'," ,
|
|
|
+ "'store_info': {" ,
|
|
|
+ "'id': 'SZTX001'" ,
|
|
|
+ "}" ,
|
|
|
+ "}" ,
|
|
|
+ "}").replace("'","\"");
|
|
|
+ HttpPost httpPost = new HttpPost("https://apihk.mch.weixin.qq.com/v3/global/transactions/jsapi");
|
|
|
+ httpPost.addHeader("Accept", "application/json");
|
|
|
+ httpPost.addHeader("Content-type", "application/json; charset=utf-8");
|
|
|
+ httpPost.setEntity(new StringEntity(unifiedOrderBody));
|
|
|
+ CloseableHttpResponse response = httpClient.execute(httpPost);
|
|
|
+ //Process the response
|
|
|
+ }
|
|
|
+}
|