New file |
| | |
| | | package com.oying.modules.hwc.service.impl; |
| | | |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.oying.exception.BadRequestException; |
| | | import com.oying.modules.hwc.domain.HwcResponse; |
| | | import com.oying.modules.hwc.service.SwiftPassService; |
| | | import com.oying.modules.hwc.utils.SignUtil; |
| | | import com.oying.modules.hwc.utils.SignUtils; |
| | | import com.oying.modules.hwc.utils.XmlUtils; |
| | | import com.oying.modules.security.config.SwiftPassProperties; |
| | | import com.oying.modules.security.config.WeiXinProperties; |
| | | import com.oying.utils.CloseUtil; |
| | | import com.oying.utils.enums.PayTypeEnum; |
| | | import lombok.RequiredArgsConstructor; |
| | | 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.apache.http.impl.client.HttpClients; |
| | | import org.apache.http.util.EntityUtils; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * @author xin |
| | | * @description |
| | | * @date 2025/1/23 下午4:01 |
| | | */ |
| | | @SuppressWarnings({"unchecked", "all"}) |
| | | @Slf4j |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class SwiftPassServiceImpl implements SwiftPassService { |
| | | |
| | | private final static String version = "2.0"; |
| | | private final static String charset = "UTF-8"; |
| | | private final static String service_pay = "pay.weixin.jspay"; |
| | | private final static String service_query = "unified.trade.query"; |
| | | private final static String service_refund = "unified.trade.refund"; |
| | | private final static String service_close = "unified.trade.close"; |
| | | |
| | | private final SwiftPassProperties properties; |
| | | private final WeiXinProperties weiXinProperties; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public HwcResponse pay(String ip, String total, String timeExpire, String description, String openId, |
| | | String orderNum, PayTypeEnum status) { |
| | | SortedMap<String, String> map = new TreeMap<>(); |
| | | map.put("service", service_pay); |
| | | map.put("version", version); |
| | | map.put("charset", charset); |
| | | map.put("sign_type", properties.getSignType()); |
| | | map.put("is_raw", properties.getIsRaw()); |
| | | map.put("is_minipg", properties.getIsMinipg()); |
| | | map.put("out_trade_no", orderNum); |
| | | map.put("body", description); |
| | | map.put("sub_openid", openId); |
| | | map.put("sub_appid", weiXinProperties.getAppId()); |
| | | map.put("total_fee", total); |
| | | map.put("mch_create_ip", ip); |
| | | map.put("notify_url", properties.getNotifyUrl()); |
| | | map.put("time_expire", timeExpire); |
| | | map.put("nonce_str", String.valueOf(new Date().getTime())); |
| | | switch (status) { |
| | | case HWC: |
| | | map.put("mch_id", properties.getMchId()); |
| | | break; |
| | | case HWC2: |
| | | map.put("mch_id", properties.getMchId2()); |
| | | break; |
| | | default: |
| | | throw new BadRequestException("汇旺财类型错误"); |
| | | } |
| | | Map<String, String> params = SignUtils.paraFilter(map); |
| | | StringBuilder buf = new StringBuilder((params.size() + 1) * 10); |
| | | SignUtils.buildPayParams(buf, params, false); |
| | | String preStr = buf.toString(); |
| | | String sign_type = map.get("sign_type"); |
| | | |
| | | map.put("sign", SignUtil.getSign(sign_type, preStr, properties, status)); |
| | | |
| | | String reqUrl = properties.getReqUrl(); |
| | | CloseableHttpResponse response = null; |
| | | CloseableHttpClient client = null; |
| | | Map<String, String> resultMap = new HashMap<>(); |
| | | try { |
| | | HttpPost httpPost = new HttpPost(reqUrl); |
| | | StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map), "utf-8"); |
| | | httpPost.setEntity(entityParams); |
| | | httpPost.setHeader("Content-Type", "text/xml;utf-8"); |
| | | client = HttpClients.createDefault(); |
| | | response = client.execute(httpPost); |
| | | if (response != null && response.getEntity() != null) { |
| | | resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8"); |
| | | String reSign = resultMap.get("sign"); |
| | | sign_type = resultMap.get("sign_type"); |
| | | if (resultMap.containsKey("sign") && SignUtil.verifySign(reSign, sign_type, resultMap, properties, status)) { |
| | | throw new BadRequestException("验证签名错误"); |
| | | } else { |
| | | if ("0".equals(resultMap.get("status")) && "0".equals(resultMap.get("result_code"))) { |
| | | return JSONObject.parseObject(resultMap.get("pay_info"), HwcResponse.class); |
| | | } else { |
| | | throw new BadRequestException(resultMap.get("err_code") + " : " + resultMap.get("err_msg") + "\n" + |
| | | resultMap.get("status") + " : " + resultMap.get("message")); |
| | | } |
| | | } |
| | | } else { |
| | | throw new BadRequestException("操作失败"); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("汇旺财下单错误请求参数:{}", params); |
| | | log.error("汇旺财下单错误返回参数:{}", resultMap); |
| | | throw new BadRequestException("汇旺财下单错误:" + e.getMessage()); |
| | | } finally { |
| | | if (response != null) { |
| | | CloseUtil.close(response); |
| | | } |
| | | if (client != null) { |
| | | CloseUtil.close(client); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public JSONObject query(String orderNum, PayTypeEnum status) { |
| | | // 参数 |
| | | SortedMap<String, String> map = new TreeMap<>(); |
| | | map.put("service", service_query); |
| | | map.put("version", version); |
| | | map.put("charset", charset); |
| | | map.put("out_trade_no", orderNum); |
| | | map.put("sign_type", properties.getSignType()); |
| | | switch (status) { |
| | | case HWC: |
| | | map.put("mch_id", properties.getMchId()); |
| | | break; |
| | | case HWC2: |
| | | map.put("mch_id", properties.getMchId2()); |
| | | break; |
| | | default: |
| | | throw new BadRequestException("汇旺财类型错误"); |
| | | } |
| | | map.put("nonce_str", String.valueOf(new Date().getTime())); |
| | | // 签名 |
| | | Map<String, String> params = SignUtils.paraFilter(map); |
| | | StringBuilder buf = new StringBuilder((params.size() + 1) * 10); |
| | | SignUtils.buildPayParams(buf, params, false); |
| | | String preStr = buf.toString(); |
| | | String sign_type = map.get("sign_type"); |
| | | map.put("sign", SignUtil.getSign(sign_type, preStr, properties, status)); |
| | | // 请求 |
| | | CloseableHttpResponse response = null; |
| | | CloseableHttpClient client = null; |
| | | Map<String, String> resultMap = new HashMap<>(); |
| | | try { |
| | | HttpPost httpPost = new HttpPost(properties.getReqUrl()); |
| | | StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map), "utf-8"); |
| | | httpPost.setEntity(entityParams); |
| | | httpPost.setHeader("Content-Type", "text/xml;utf-8"); |
| | | client = HttpClients.createDefault(); |
| | | response = client.execute(httpPost); |
| | | if (response != null && response.getEntity() != null) { |
| | | resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8"); |
| | | String reSign = resultMap.get("sign"); |
| | | sign_type = resultMap.get("sign_type"); |
| | | if (resultMap.containsKey("sign") && SignUtil.verifySign(reSign, sign_type, resultMap, properties, status)) { |
| | | throw new BadRequestException("验证签名错误"); |
| | | } else { |
| | | if ("0".equals(resultMap.get("status"))) { |
| | | return JSONObject.parseObject(JSONObject.toJSONString(resultMap)); |
| | | } else { |
| | | |
| | | throw new BadRequestException(resultMap.get("err_code") + " : " + resultMap.get("err_msg") + "\n" + |
| | | resultMap.get("status") + " : " + resultMap.get("message")); |
| | | } |
| | | } |
| | | } else { |
| | | throw new BadRequestException("操作失败!"); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("请求参数:{}", params); |
| | | log.error("返回参数:{}", resultMap); |
| | | throw new BadRequestException("操作失败,原因:" + e.getMessage()); |
| | | } finally { |
| | | if (response != null) { |
| | | CloseUtil.close(response); |
| | | } |
| | | if (client != null) { |
| | | CloseUtil.close(client); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void closeOrder(String outTradeNo, PayTypeEnum status) { |
| | | // 参数 |
| | | SortedMap<String, String> map = new TreeMap<>(); |
| | | map.put("service", service_close); |
| | | map.put("version", version); |
| | | map.put("charset", charset); |
| | | map.put("out_trade_no", outTradeNo); |
| | | map.put("sign_type", properties.getSignType()); |
| | | switch (status) { |
| | | case HWC: |
| | | map.put("mch_id", properties.getMchId()); |
| | | break; |
| | | case HWC2: |
| | | map.put("mch_id", properties.getMchId2()); |
| | | break; |
| | | default: |
| | | throw new BadRequestException("汇旺财类型错误"); |
| | | } |
| | | map.put("nonce_str", String.valueOf(new Date().getTime())); |
| | | // 签名 |
| | | Map<String, String> params = SignUtils.paraFilter(map); |
| | | StringBuilder buf = new StringBuilder((params.size() + 1) * 10); |
| | | SignUtils.buildPayParams(buf, params, false); |
| | | String preStr = buf.toString(); |
| | | String sign_type = map.get("sign_type"); |
| | | map.put("sign", SignUtil.getSign(sign_type, preStr, properties, status)); |
| | | // 请求 |
| | | CloseableHttpResponse response = null; |
| | | CloseableHttpClient client = null; |
| | | Map<String, String> resultMap = new HashMap<>(); |
| | | try { |
| | | HttpPost httpPost = new HttpPost(properties.getReqUrl()); |
| | | StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map), "utf-8"); |
| | | httpPost.setEntity(entityParams); |
| | | httpPost.setHeader("Content-Type", "text/xml;utf-8"); |
| | | client = HttpClients.createDefault(); |
| | | response = client.execute(httpPost); |
| | | if (response != null && response.getEntity() != null) { |
| | | resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8"); |
| | | String reSign = resultMap.get("sign"); |
| | | sign_type = resultMap.get("sign_type"); |
| | | if (resultMap.containsKey("sign") && SignUtil.verifySign(reSign, sign_type, resultMap, properties, status)) { |
| | | throw new BadRequestException("验证签名错误"); |
| | | } else { |
| | | if (!("0".equals(resultMap.get("status")))) { |
| | | throw new BadRequestException(resultMap.get("err_code") + " : " + resultMap.get("err_msg") + "\n" + |
| | | resultMap.get("status") + " : " + resultMap.get("message")); |
| | | } |
| | | } |
| | | } else { |
| | | throw new BadRequestException("操作失败!"); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("请求参数:{}", params); |
| | | log.error("返回参数:{}", resultMap); |
| | | throw new BadRequestException("操作失败,原因:" + e.getMessage()); |
| | | } finally { |
| | | if (response != null) { |
| | | CloseUtil.close(response); |
| | | } |
| | | if (client != null) { |
| | | CloseUtil.close(client); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Map<String, String> refund(String returnNum, String orderNum, String reason, long refund, |
| | | long total, PayTypeEnum payType) { |
| | | // 参数 |
| | | SortedMap<String, String> map = new TreeMap<>(); |
| | | map.put("service", service_refund); |
| | | map.put("version", version); |
| | | map.put("charset", charset); |
| | | map.put("sign_type", properties.getSignType()); |
| | | map.put("out_trade_no", orderNum); |
| | | map.put("out_refund_no", returnNum); |
| | | map.put("total_fee", String.valueOf(total)); |
| | | map.put("refund_fee", String.valueOf(refund)); |
| | | map.put("nonce_str", String.valueOf(new Date().getTime())); |
| | | switch (payType) { |
| | | case HWC: |
| | | map.put("mch_id", properties.getMchId()); |
| | | map.put("op_user_id", properties.getMchId()); |
| | | break; |
| | | case HWC2: |
| | | map.put("mch_id", properties.getMchId2()); |
| | | map.put("op_user_id", properties.getMchId2()); |
| | | break; |
| | | default: |
| | | throw new BadRequestException("汇旺财类型错误"); |
| | | } |
| | | // 签名 |
| | | Map<String, String> params = SignUtils.paraFilter(map); |
| | | StringBuilder buf = new StringBuilder((params.size() + 1) * 10); |
| | | SignUtils.buildPayParams(buf, params, false); |
| | | String preStr = buf.toString(); |
| | | String sign_type = map.get("sign_type"); |
| | | map.put("sign", SignUtil.getSign(sign_type, preStr, properties, payType)); |
| | | // 参数 |
| | | CloseableHttpResponse response = null; |
| | | CloseableHttpClient client = null; |
| | | Map<String, String> resultMap = new HashMap<>(); |
| | | try { |
| | | HttpPost httpPost = new HttpPost(properties.getReqUrl()); |
| | | StringEntity entityParams = new StringEntity(XmlUtils.parseXML(map), "utf-8"); |
| | | httpPost.setEntity(entityParams); |
| | | httpPost.setHeader("Content-Type", "text/xml;utf-8"); |
| | | client = HttpClients.createDefault(); |
| | | response = client.execute(httpPost); |
| | | if (response != null && response.getEntity() != null) { |
| | | resultMap = XmlUtils.toMap(EntityUtils.toByteArray(response.getEntity()), "utf-8"); |
| | | if (resultMap.containsKey("sign") && SignUtil.verifySign(resultMap.get("sign"), resultMap.get("sign_type"), resultMap, properties, payType)) { |
| | | throw new BadRequestException("验证签名错误"); |
| | | } else { |
| | | if ("0".equals(resultMap.get("status"))) { |
| | | return resultMap; |
| | | } else { |
| | | throw new BadRequestException(resultMap.get("err_code") + " : " + resultMap.get("err_msg") + "\n" + |
| | | resultMap.get("status") + " : " + resultMap.get("message")); |
| | | } |
| | | } |
| | | } else { |
| | | throw new BadRequestException("操作失败!"); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("请求参数:{}", params); |
| | | log.error("返回参数:{}", resultMap); |
| | | throw new BadRequestException("操作失败,原因:" + e); |
| | | } finally { |
| | | if (response != null) { |
| | | CloseUtil.close(response); |
| | | } |
| | | if (client != null) { |
| | | CloseUtil.close(client); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | } |