|
@@ -0,0 +1,270 @@
|
|
|
+package com.llisoft.pay.service;
|
|
|
+
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Objects;
|
|
|
+
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import com.alipay.api.AlipayClient;
|
|
|
+import com.alipay.api.DefaultAlipayClient;
|
|
|
+import com.alipay.api.domain.AlipayTradeAppPayModel;
|
|
|
+import com.alipay.api.domain.AlipayTradePagePayModel;
|
|
|
+import com.alipay.api.domain.AlipayTradeQueryModel;
|
|
|
+import com.alipay.api.domain.AlipayTradeWapPayModel;
|
|
|
+import com.alipay.api.internal.util.AlipaySignature;
|
|
|
+import com.alipay.api.request.AlipayTradeAppPayRequest;
|
|
|
+import com.alipay.api.request.AlipayTradePagePayRequest;
|
|
|
+import com.alipay.api.request.AlipayTradeQueryRequest;
|
|
|
+import com.alipay.api.request.AlipayTradeWapPayRequest;
|
|
|
+import com.alipay.api.response.AlipayTradeAppPayResponse;
|
|
|
+import com.alipay.api.response.AlipayTradePagePayResponse;
|
|
|
+import com.alipay.api.response.AlipayTradeQueryResponse;
|
|
|
+import com.alipay.api.response.AlipayTradeWapPayResponse;
|
|
|
+import com.llisoft.pay.util.DecimalUtil;
|
|
|
+import com.llisoft.pay.util.JsonUtil;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 支付宝支付
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class PayAliNewService {
|
|
|
+
|
|
|
+ private Logger logger = LoggerFactory.getLogger(PayAliNewService.class);
|
|
|
+
|
|
|
+ @Value("${mta.domain}")
|
|
|
+ private String domain;
|
|
|
+
|
|
|
+ private String serverUrl = "https://openapi.alipay.com/gateway.do";
|
|
|
+ private String appidDongke = "2017020505526927";
|
|
|
+ private String appidQinggu = "2021004131649155";
|
|
|
+ private String privateKeyDongke = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCJDDaWPOLc5n7D2wNrPSou+Yi+C/cw7x2105ANs8vXlGSCJyHfmKR3b2+1/fiKYDvjboeKbL5wbpbUrWt10VWPQ/YjwqbuQEFqOINInvp+uWWrIhLvB/xPNpCcW/jN6JfUkC0Rh495se/vVKpsR+/+/h2fZgPy8K0JP9u1yxuP9XGNgTyvH7lMBFxuABEnpIVsoEoBo+Hj7w8thOqBvETgb/pf+lXd1OXq6ag0FOmaf13hQekttlSIWrjlTmXHjTG/o7qLOu6H34zOvIAZuf+Ij4vSTIsbBnQSzvILul/sRmUzT/QxLFlTuD3MuOJMYSNLNzbmsgOfGsFpV/O3cUK9AgMBAAECggEATyMyUkcOaajgApDxxHcpaL7Ha5bVQviRG3HzeTYdu3sBHvch5E/siNtckqb5Yk53xrkIo7JvtdTmXCFYMEyVL4l7FONOKb4JCCFiDglfdNXyE4Q1krn1xHgpwWCKp7xsEF7A56J0Az3w4y7symIv//sVd/ocxaidAv5RDQUgAVxNlz53AMafuXGMEwVkQETp43EewfuoS43pMxaPvl/IkRv66RHMKWNhcY9drxAsCYmVojUCnX0WuCqTS2hdG81RiyyWnItGTC2+bHGR3FrkwgNVAxUJefJ5QO1ojcOIj9uBN6yzkBW3+eYCWfWME92utsSna+fFJPHEP9o5kf11MQKBgQDDRbLmI0R1AnYnrTf8Z7kKNxvDNQdm22s/b+FCEnyV2XGpIzeqe5ea6G3zqjSQvyfg6gY7uLHtZRQkm0rdhTj7bb2wcy0ejC2vFNRISZoU05cP23T5cs4ajQBPmj6biTlfw/tbBavEx9NJ6otJx0xs+VrfuM/yElgTwtzviGGTBwKBgQCzqw5X2aplU0LIrYGLarR09MYFKxVBDWXFgYRb9ge0+WEbi9j1EcVL80xG4Z1GePkrAdJ3/+/x/kctna5Lbjp4cosxL44Ty5yUoGQaYy6n+YJTmo8TWuoaIPgoxFznnwMOc24seIds9mj4GtbVJfVjWwK/rNjHyJ8B2GL6k533GwKBgDkv21GsuGqwGtxJzWCdG8LTGs1TZWSJE+KTKFwKP/Q+pxvKlY3W/jI+qZy3lwdhBBPJVaP91hXZCUojNIylbGet3uSjBm6wzNw+dGDrNTWuNcpOEfbP2W5LJvEpEfbI/EWAhsdEZOaPQuCd0Mb9l/M+H4/vdu7E0oiPA9cekLzXAoGBAIE5miJjoyQnw5QU/2ToRY0NdNPIzguw+C8bXbjK93YaG9c1OcHimzZqcsVUhstmPUjKkbfPtKQoUMelbvQ//vwc3rJs0tK4ExHvXrB//9G/Kxa4xwmTzWcnqXWg7nWFsCwXp/mCY11iydMRcs1x9NIWZp64Ul83k+4+1coGnIpbAoGBALXxiTjCxZUBrS6UdOY0w3mZtXvZ0AeYLMMCuokfP8Z+9j6MXRx4DR5rlqej0GB5wBrwOslbs7jlMNg9yVpS7egZ3AKnNHFvf0Ew7R3QTi58yBawESrsWzyWigXIDuOPOEslpVaLlTFOy5zaXgkJ/85oEDJqPhTAfhuPbmpTU0h2";
|
|
|
+ private String privateKeyQinggu = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCGiwhzLQftPQzpfpS0VahZQuIcD9To0hUH+ZLOOA7W7Wvd7B4nk6TwEVLcGRzdZhxzsXxhU54Yyf8h7z056BbW/JnafR+VV+J5dVgKzJNO+7VNBpZH74ccbnF6/YWdPqOaDRE9cTshkWGlgPiJSlQhuUjW+ero/hO0QObFRp74veQoxm4zYOXawFb/seTPWg2pW0P6502ptbz7s24OqG1s6O8NXVK47rBHk0Nkrr8yIA/Q2/Wy82zVl97peB9O31biMbGYjbnlkR1hfgpgoBMbm8gb9d3ikDw+9BhDUngJSpU/DB2dK2y1/Qw1yVpCu37SQvRf0MHh+/zyjyKq5AHJAgMBAAECggEAEhFfvB/i/aACOOUP0TvjlMEfnkcd/3oe6uhAJ8Ntcr2Fi9Lmpcf1EWwyJW6V6sGItpyyKFvTUl7mDUeUgE9DqfFYM/gzopmfx1HT1fdtHOE+kq58xgJLsay/PpYHOHut+sUgeJDZMQPWCiTMu5souzKnrn73Zfyg5scEdp+qP5sGxdBJ4b8Un4O9yzF6G4nuOYKPr2xwfnFYbH+AnJ1uESLyLoZJeiYIZ7oxWu2tnaCOv1KW+BaD8pCaZ91bn6A4Rpr7AqklDuSTsArvC9LrSNQa2Nz3+huYoMGDh0c+DeNkRSmheB2UGkY+F3dpPxyWZrlgzIreMLb7mCoioITz0QKBgQDAAeu3TkCzofhFN10t5p6q4kMErbVYGdZ8khgEXFkgZr/l/vXlVZqc+yMaC0RQB8n4l5kKxOfKrnTFy8GPQ2Oe2EmQ3Rr672xD1UPpgc0J3dxQqkAfFnFpaHryrxVZ0ntYuJ8mvMZ37cIpSvMjwLPI7RLT1lLsu7/ZahHWSSi5lQKBgQCzYj/cY08THB6gDUotD//HFooIRKs6VBoKolR+faGC/oKHV0iugKJGnbh4jSHunk2z3SkFcCPkNV+/Im6k18yV1jXrVnsLSUl0RpozwVwQjK4rPE96WhwCgItY7Lrao8mtE/gDiXqto12xkGr5q6jIYstwjzPP++DaWC7MBzkiZQKBgQCXa+xc71WPVJja3UKaxFk1IqL/uY5eIGJKc1yFc97F8sI7u8poRg5c5qFUFLaW9s2NQuDq4UZ7TQHCS2ImfVq/FotNt1FjvBWBmVqpeDgfI9xvsRRIcAaYvlDXusP3xkqIOXEpt449Xj/VGMqO05X1SyGh9lAHajluWHwgpil70QKBgEjuWBJtWdfmJdlirda2W4KA+mu0J32WdeP+7aVjxIeynDUUWpt/9voI49g3YSVXvTW0ZBou5pjAzoWyJRPmHOqKZe+hgHMtP60Di2whYCHmYGV5psKS4jJuOrlTvgBoePViWgJuIa947P3lPmj1zrBx4k6IGkOkH14GXjhbc3I1AoGAV5BLnPrAaxedyDJdystReDEnOV4urfhcg0EGsgDe1wMe8brPXD+pvKaIzhHNLHL1zz0LSvrgHqpuX4P2I7MWAoWVLjNuKYw8tBuUPATxdPDES5IekHFfC09hrTsX7iyd1FWUtP6ENrnJn/B8yQuHmFin2BaPNLtIHDkev4hKWMA=";
|
|
|
+ private String signType = "RSA2";
|
|
|
+
|
|
|
+ private AlipayClient alipayClientDongke = DefaultAlipayClient.builder(serverUrl, appidDongke, privateKeyDongke).signType(signType).build();
|
|
|
+ private AlipayClient alipayClientQinggu = DefaultAlipayClient.builder(serverUrl, appidQinggu, privateKeyQinggu).signType(signType).build();
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * PC 栋科
|
|
|
+ * @param pid
|
|
|
+ * @param money
|
|
|
+ * @param subject
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String pcDongke(String pid, int money, String subject) {
|
|
|
+ return this.pc(alipayClientDongke, pid, money, subject);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * PC 青谷
|
|
|
+ * @param pid
|
|
|
+ * @param money
|
|
|
+ * @param subject
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String pcQinggu(String pid, int money, String subject) {
|
|
|
+ return this.pc(alipayClientQinggu, pid, money, subject);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * PC
|
|
|
+ * @param alipayClient
|
|
|
+ * @param pid
|
|
|
+ * @param money
|
|
|
+ * @param subject
|
|
|
+ * @return 该结果用于跳转到支付宝页面,返回到用户浏览器渲染或重定向跳转到支付宝页面
|
|
|
+ * https://opendocs.alipay.com/open/59da99d0_alipay.trade.page.pay
|
|
|
+ */
|
|
|
+ public String pc(AlipayClient alipayClient, String pid, int money, String subject) {
|
|
|
+ AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
|
|
|
+ request.setReturnUrl(domain+"/alipay/return");
|
|
|
+ request.setNotifyUrl(domain+"/alipay/notify");
|
|
|
+ AlipayTradePagePayModel model = new AlipayTradePagePayModel();
|
|
|
+ model.setOutTradeNo(pid); // Y 商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复
|
|
|
+ model.setTotalAmount(DecimalUtil.toString(money)); // Y 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
|
|
|
+ model.setSubject(subject); // Y 订单标题
|
|
|
+ model.setProductCode("FAST_INSTANT_TRADE_PAY"); // Y 销售产品码,与支付宝签约的产品码名称。 注:目前仅支持FAST_INSTANT_TRADE_PAY
|
|
|
+ request.setBizModel(model);
|
|
|
+ try {
|
|
|
+ logger.debug("支付宝支付接口(PC)请求:{}", JsonUtil.toJson(request));
|
|
|
+ AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
|
|
|
+ logger.debug("支付宝支付接口(pc)返回:{}", JsonUtil.toJson(response));
|
|
|
+ return response.getBody();
|
|
|
+ } catch (Exception exception) {
|
|
|
+ logger.error("支付宝支付接口(pc)异常", exception);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * WAP 栋科
|
|
|
+ * @param pid
|
|
|
+ * @param money
|
|
|
+ * @param subject
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String wapDongke(String pid, int money, String subject) {
|
|
|
+ return this.wap(alipayClientDongke, pid, money, subject);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * WAP 青谷
|
|
|
+ * @param pid
|
|
|
+ * @param money
|
|
|
+ * @param subject
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String wapQinggu(String pid, int money, String subject) {
|
|
|
+ return this.wap(alipayClientQinggu, pid, money, subject);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 支付 移动端
|
|
|
+ * @param alipayClient
|
|
|
+ * @param pid
|
|
|
+ * @param money
|
|
|
+ * @param subject
|
|
|
+ * @return
|
|
|
+ * https://docs.open.alipay.com/270/alipay.trade.page.pay
|
|
|
+ */
|
|
|
+ public String wap(AlipayClient alipayClient, String pid, int money, String subject) {
|
|
|
+ AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
|
|
|
+ request.setReturnUrl(domain+"/alipay/return");
|
|
|
+ request.setNotifyUrl(domain+"/alipay/notify");
|
|
|
+ AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
|
|
|
+ model.setOutTradeNo(pid); // Y 商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复
|
|
|
+ model.setTotalAmount(DecimalUtil.toString(money)); // Y 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
|
|
|
+ model.setSubject(subject); // Y 订单标题
|
|
|
+ request.setBizModel(model);
|
|
|
+ try {
|
|
|
+ logger.debug("支付宝支付接口(WAP)请求:{}", JsonUtil.toJson(request));
|
|
|
+ AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
|
|
|
+ logger.debug("支付宝支付接口(WAP)返回:{}", JsonUtil.toJson(response));
|
|
|
+ return response.getBody();
|
|
|
+ } catch (Exception exception) {
|
|
|
+ logger.error("支付宝支付接口(WAP)异常", exception);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * WAP 栋科
|
|
|
+ * @param pid
|
|
|
+ * @param money
|
|
|
+ * @param subject
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String appDongke(String pid, int money, String subject) {
|
|
|
+ return this.app(alipayClientDongke, pid, money, subject);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * WAP 青谷
|
|
|
+ * @param pid
|
|
|
+ * @param money
|
|
|
+ * @param subject
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String appQinggu(String pid, int money, String subject) {
|
|
|
+ return this.app(alipayClientQinggu, pid, money, subject);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 支付 移动端
|
|
|
+ * @param alipayClient
|
|
|
+ * @param pid
|
|
|
+ * @param money
|
|
|
+ * @param subject
|
|
|
+ * @return
|
|
|
+ * https://opendocs.alipay.com/open/29ae8cb6_alipay.trade.wap.pay
|
|
|
+ */
|
|
|
+ public String app(AlipayClient alipayClient, String pid, int money, String subject) {
|
|
|
+ AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
|
|
|
+ request.setReturnUrl(domain+"/alipay/return");
|
|
|
+ request.setNotifyUrl(domain+"/alipay/notify");
|
|
|
+ AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
|
|
|
+ model.setOutTradeNo(pid); // Y 商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复
|
|
|
+ model.setTotalAmount(DecimalUtil.toString(money)); // Y 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
|
|
|
+ model.setSubject(subject); // Y 订单标题
|
|
|
+ request.setBizModel(model);
|
|
|
+ try {
|
|
|
+ logger.debug("支付宝支付接口(APP)请求:{}", JsonUtil.toJson(request));
|
|
|
+ AlipayTradeAppPayResponse response = alipayClient.pageExecute(request);
|
|
|
+ logger.debug("支付宝支付接口(APP)返回:{}", JsonUtil.toJson(response));
|
|
|
+ return response.getBody();
|
|
|
+ } catch (Exception exception) {
|
|
|
+ logger.error("支付宝支付接口(APP)异常", exception);
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询 栋科
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public boolean queryDongke(String pid) throws Exception {
|
|
|
+ return this.query(alipayClientDongke, pid);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询 青谷
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public boolean queryQinggu(String pid) throws Exception {
|
|
|
+ return this.query(alipayClientQinggu, pid);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询
|
|
|
+ * @param pid
|
|
|
+ * @return
|
|
|
+ * https://docs.open.alipay.com/api_1/alipay.trade.query
|
|
|
+ */
|
|
|
+ public boolean query(AlipayClient alipayClient, String pid) {
|
|
|
+ AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
|
|
|
+ AlipayTradeQueryModel model = new AlipayTradeQueryModel();
|
|
|
+ model.setOutTradeNo(pid); // 商户订单号
|
|
|
+ request.setBizModel(model);
|
|
|
+ try {
|
|
|
+ logger.debug("支付宝查询接口请求:{}", JsonUtil.toJson(request));
|
|
|
+ AlipayTradeQueryResponse response = alipayClient.execute(request);
|
|
|
+ logger.debug("支付宝查询接口返回:{}", JsonUtil.toJson(response));
|
|
|
+ // {"alipay_trade_query_response":{"code":"10000","msg":"Success","buyer_logon_id":"ipb***@sandbox.com","buyer_pay_amount":"0.00","buyer_user_id":"2088102170394382","buyer_user_type":"PRIVATE","invoice_amount":"0.00","out_trade_no":"1529637131201603","point_amount":"0.00","receipt_amount":"0.00","send_pay_date":"2018-06-22 11:12:23","total_amount":"12.00","trade_no":"2018062221001004380200826678","trade_status":"TRADE_SUCCESS"},"sign":"gnWtxKDDhkRmoWnfwLVs2RGtt4GbiY+xaVs5+G47D5e9SnQHqGnElKme4jlDdnqhAroX3aqyJLVexohBjzA+DlpRzDhIu5EZLXnDr/B2FZEVjyiU66ImVH6vSyWyOVEjbGIgmVhUslhXqXYK5KxAx3QAdLrJLQeMO/gUdjs0qWcGO9yTU/suDy0YcdLSLlFyUutwD2MBz4Ri0tBk+uHjpxXoTZeb9/lQ7e4BixwCy+wB3hcESWN1b/m77YLKztmbLy67auhxzP9TRwQQ+6WRrTdMe/9rouIt6AW9T+6XSFd/LwL73Qo+1MfQa+iEUx2Iq+AYekhSgVyLJMRgz/qoZA=="}
|
|
|
+ String body = response.getBody();
|
|
|
+ if(Objects.nonNull(body) && !body.trim().isEmpty()) {
|
|
|
+ Map<String, Object> bodyMap = JsonUtil.toObject(body, Map.class, String.class, Object.class);
|
|
|
+ Map<String, Object> tradeMap = JsonUtil.toObject(JsonUtil.toJson(bodyMap.get("alipay_trade_query_response")), Map.class, String.class, Object.class);
|
|
|
+ return "10000".equals(tradeMap.get("code")) && ("TRADE_SUCCESS".equals(tradeMap.get("trade_status")) || "TRADE_FINISHED".equals(tradeMap.get("trade_status")));
|
|
|
+ }
|
|
|
+ } catch (Exception exception) {
|
|
|
+ logger.error("支付宝查询接口异常", exception);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 支付宝公钥
|
|
|
+ String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ZsJ44iDOtJ2vJnoIL970l3a9xJXiRtLWJWlUyhFz8zIlkNb0A/oMSWWpkUs7B2ryUTKmItmRqg8em4diQTcE5b0fpYIFntg+ThLN4Jbt3+CK05tCKIKfuCkDSaIkr8PP+vCZyHlpw5MBdBpX4sG9lDsPh3E48qXeh9vvLUeqF2n+Pok9FHHzEUcrCtVWp5eHL34a/HnJbTzb4t25b9FqQmhYK/vI2CUN3aI+rmthzqJFrmxsTFkR5rTvcMyVzOze6EoDgzBFShJnrfVD4efbqhc1+afmrKj+VAp8Uxpj8HCzTvuBDuB2yg/rgTt2y3u9HZT67NM18Butk/XgmIUlQIDAQAB";
|
|
|
+ public boolean notify(Map<String, String> map) throws Exception {
|
|
|
+ // 验证签名
|
|
|
+ if(!AlipaySignature.rsaCheckV1(map, publicKey, "UTF-8", signType)) {
|
|
|
+ logger.error("支付宝异步通知: 签名验证失败: {}", map);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // 验证支付宝交易状态
|
|
|
+ String tradeStatus = map.get("trade_status"); // 支付宝交易状态 https://docs.open.alipay.com/#s1
|
|
|
+ if(Objects.nonNull(tradeStatus) && ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus))) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|