引入官方sdk
<!--微信v3支付sdk {https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient}--> <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apache-httpclient</artifactId> <version>0.4.8</version> </dependency>
新建配置类
/** * @Description : 微信支付配置 * @Author : wzkris * @Version : V1.0.0 * @Date : 2022/11/27 15:41 */ @ConfigurationProperties("wx.pay") @Component @Data public class WxPayConfig { /** appid*/ public String appId; /** appSecret*/ private String appSecret; /** 商户号 */ public String merchantId; /** 商户API私钥路径 */ public String privateKeyPath; /**商户API私钥*/ public PrivateKey privateKey; /** 商户证书序列号 */ public String merchantSerialNumber; /**v3密钥*/ public String apiV3key; }
新建service
/** * @Description : 微信v3支付服务 * @Author : wzkris * @Version : V1.0.0 * @Date : 2022/11/27 15:48 * @Description : 微信支付服务,金额一律为分;对账单中的交易金额单位为元 */ @Component public class WxPayService { @Resource private WxPayConfig wxconfig; @Resource private GtConfig gtConfig; /** * 请求客户端 */ private static CloseableHttpClient httpClient; /** * 微信平台证书验证器 */ private static Verifier verifier; @PostConstruct public void init() { try { String privateKey = FileUtils.readFileToString(wxconfig.privateKeyPath); wxconfig.setPrivateKey(PemUtil.loadPrivateKey(privateKey)); //初始化微信平台证书容器,certificatesManager可以放多个商户 CertificatesManager certificatesManager = CertificatesManager.getInstance(); certificatesManager.putMerchant( wxconfig.merchantId, new WechatPay2Credentials(wxconfig.merchantId, new PrivateKeySigner(wxconfig.merchantSerialNumber, wxconfig.privateKey)), wxconfig.getApiV3key().getBytes(StandardCharsets.UTF_8) ); verifier = certificatesManager.getVerifier(wxconfig.merchantId); //初始化httpClient httpClient = WechatPayHttpClientBuilder .create() .withMerchant(wxconfig.merchantId, wxconfig.merchantSerialNumber, PemUtil.loadPrivateKey(privateKey)) .withValidator(new WechatPay2Validator(verifier)) .build(); } catch (Exception e) { e.printStackTrace(); } } /** * 添加子商户进件申请 */ public JSONObject addSubMerchant(SubMerchantApplyment applyment) { HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/"); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-type", "application/json; charset=utf-8"); httpPost.addHeader("Wechatpay-Serial", String.valueOf(verifier.getValidCertificate().getSerialNumber())); //敏感信息加密 encryptSubMerchantInfo(applyment); httpPost.setEntity(new StringEntity(JSONObject.toJSONString(applyment), StandardCharsets.UTF_8)); try { CloseableHttpResponse response = httpClient.execute(httpPost); JSONObject jsonObject = JSONObject.parseObject(EntityUtils.toString(response.getEntity())); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new ServiceException(jsonObject); } return jsonObject; } catch (IOException e) { throw new RuntimeException(e); } } /** * 进件敏感信息加密 * * @param applyment 特约商户进件 */ public void encryptSubMerchantInfo(SubMerchantApplyment applyment) { //1.超级管理员信息加密 ContactInfo contactInfo = applyment.getContactInfo(); contactInfo.setContactName(encrypt(contactInfo.getContactName())) .setOpenId(encrypt(contactInfo.getOpenId())) .setMobilePhone(encrypt(contactInfo.getMobilePhone())) .setContactEmail(encrypt(contactInfo.getContactEmail())); //1.1经办人类型 if (contactInfo.getContactType().equals(ContactInfo.contactType.SUPER.toString())) { contactInfo.setContactIdNumber(encrypt(contactInfo.getContactIdNumber())); } //2.主体资料 SubjectInfo subjectInfo = applyment.getSubjectInfo(); //2.1受益人信息加密 if (!subjectInfo.getUboInfoList().isEmpty()) { //每个受益人信息都加密 for (UboInfo uboInfo : subjectInfo.getUboInfoList()) { uboInfo.setUboIdDocName(encrypt(uboInfo.getUboIdDocName())) .setUboIdDocNumber(encrypt(uboInfo.getUboIdDocNumber())) .setUboIdDocAddress(encrypt(uboInfo.getUboIdDocAddress())); } } //3.结算银行账户 BankAccountInfo bankAccountInfo = applyment.getBankAccountInfo(); bankAccountInfo.setAccountName(encrypt(bankAccountInfo.getAccountName())) .setAccountNumber(encrypt(bankAccountInfo.getAccountNumber())); } /** * 查看申请单状态 * * @param businessCode 业务申请编号 */ public ApplymentResult searchApplymentStatus(String businessCode) { HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/applyment4sub/applyment/business_code/" + businessCode); try { CloseableHttpResponse response = httpClient.execute(httpGet); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new ServiceException(JSONObject.parseObject(EntityUtils.toString(response.getEntity()))); } return JSONObject.parseObject(EntityUtils.toString(response.getEntity()), ApplymentResult.class); } catch (IOException e) { throw new RuntimeException(e); } } /** * @param bo 支付参数 * @param enums 支付渠道 * @return 返回参数 * @Description 服务商付款 */ public JSONObject pay(WxPayParamsBO bo, PayEnums enums) { //1.组装参数 JSONObject requestParams = new JSONObject(); requestParams.put("sp_appid", wxconfig.getAppId()); requestParams.put("sp_mchid", wxconfig.getMerchantId()); //子商户appid requestParams.put("sub_appid", bo.getSubAppId()); //子商户号 requestParams.put("sub_mchid", bo.getSubMchId()); requestParams.put("description", bo.getDescription()); requestParams.put("out_trade_no", bo.getOrderNo()); requestParams.put("notify_url", gtConfig.getUrl() + bo.getNotifyUrl()); JSONObject amount = new JSONObject(); amount.put("total", bo.getAmount()); requestParams.put("amount", amount); JSONObject payer = new JSONObject(); if (enums.equals(PayEnums.JSAPI)) { payer.put("sp_openid", bo.getOpenId()); requestParams.put("payer", payer); } else if (enums.equals(PayEnums.H5)) { JSONObject sceneInfo = new JSONObject(); //拿到HttpServletRequest解析ip HttpServletRequest request = ServletUtils.getRequest(); sceneInfo.put("payer_client_ip", IpUtils.getIpAddr(request)); JSONObject h5Info = new JSONObject(); h5Info.put("type", IpUtils.getOperatorSys(request)); sceneInfo.put("h5_info", h5Info); requestParams.put("scene_info", sceneInfo); } //2.初始化post请求 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/" + enums.getPath()); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-type", "application/json; charset=utf-8"); httpPost.setEntity(new StringEntity(requestParams.toJSONString(), StandardCharsets.UTF_8)); try { CloseableHttpResponse response = httpClient.execute(httpPost); //拿到返回参数 JSONObject resParams = JSONObject.parseObject(EntityUtils.toString(response.getEntity())); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new ServiceException(resParams); } return resParams; } catch (IOException e) { throw new ServiceException(e.getMessage()); } } /** * @param bo 查询订单详情 * @Description 查询订单信息 */ public OrderResultInfo queryOrder(QueryOrderBO bo) { String url = " https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/" + bo.getOrderNo() + "?" + "sp_mchid=" + bo.getSpMchid() + "&" + "sub_mchid=" + bo.getSubMchid(); HttpGet httpGet = new HttpGet(url); httpGet.addHeader("Accept", "application/json"); try { CloseableHttpResponse response = httpClient.execute(httpGet); String bodyAsString = EntityUtils.toString(response.getEntity()); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new ServiceException(JSONObject.parseObject(bodyAsString)); } return JSONObject.parseObject(bodyAsString, OrderResultInfo.class); } catch (IOException e) { throw new ServiceException(e); } } /** * @param orderNo 订单号 * @param subMchid 子商户号 * @description: 关闭订单 */ public void closeOrder(String orderNo, String subMchid) { String url = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/" + orderNo + "/close"; //构造参数 JSONObject requestParams = new JSONObject(); requestParams.put("sp_mchid", wxconfig.getMerchantId()); requestParams.put("sub_mchid", subMchid); //构造请求 HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-type", "application/json; charset=utf-8"); httpPost.setEntity(new StringEntity(requestParams.toJSONString(), StandardCharsets.UTF_8)); try { CloseableHttpResponse response = httpClient.execute(httpPost); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) { throw new ServiceException(response.getEntity()); } } catch (IOException e) { throw new ServiceException(e.getMessage()); } } /** * 退款 */ public RefundResultInfo refund(RefundBO bo) { //1. 构造参数 JSONObject requestParams = new JSONObject(); //子商户号 requestParams.put("sub_mchid", bo.getSubMchId()); //服务商订单号 requestParams.put("out_trade_no", bo.getOrderNo()); //退款单号 requestParams.put("out_refund_no", bo.getRefundNo()); requestParams.put("reason", bo.getReason()); JSONObject amount = new JSONObject(); //退款金额,单位分 amount.put("refund", bo.getRefund()); //原订单金额,单位分 amount.put("total", bo.getTotal()); amount.put("currency", "CNY"); requestParams.put("amount", amount); //2. 初始化post请求 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-type", "application/json; charset=utf-8"); httpPost.setEntity(new StringEntity(requestParams.toJSONString(), StandardCharsets.UTF_8)); try { CloseableHttpResponse httpResponse = httpClient.execute(httpPost); String resString = EntityUtils.toString(httpResponse.getEntity()); if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new ServiceException(JSONObject.parseObject(resString)); } return JSONObject.parseObject(resString, RefundResultInfo.class); } catch (IOException e) { throw new ServiceException(e); } } /** * @param request * @Description 回调请求的验签、解密 */ public OrderResultInfo asyncCallback(HttpServletRequest request) { //1.获取请求头 String body = getRequestBody(request); String serialNumber = request.getHeader("Wechatpay-Serial"); String timeStamp = request.getHeader("Wechatpay-Timestamp"); String nonce = request.getHeader("Wechatpay-Nonce"); String signature = request.getHeader("Wechatpay-Signature"); //2.构造请求 NotificationRequest notificationRequest = new NotificationRequest.Builder().withSerialNumber(serialNumber) .withNonce(nonce) .withTimestamp(timeStamp) .withSignature(signature) .withBody(body) .build(); NotificationHandler handler = new NotificationHandler(verifier, wxconfig.getApiV3key().getBytes(StandardCharsets.UTF_8)); // 验签和解析请求体 try { Notification notification = handler.parse(notificationRequest); return JSONObject.parseObject(notification.getDecryptData(), OrderResultInfo.class); } catch (ValidationException | ParseException e) { throw new ServiceException(e); } } /** * 微信上传图片/视频 */ public String upload(MultipartFile multipartFile, UploadEnums enums) throws IOException { String sha256 = DigestUtils.sha256Hex(multipartFile.getBytes()); HttpPost httpPost = new WechatPayUploadHttpPost .Builder(URI.create("https://api.mch.weixin.qq.com/v3/merchant/media/" + enums.getValue())) .withImage(multipartFile.getOriginalFilename(), sha256, new ByteArrayInputStream(multipartFile.getBytes())) .build(); CloseableHttpResponse response = httpClient.execute(httpPost); String resString = EntityUtils.toString(response.getEntity()); JSONObject resParams = JSONObject.parseObject(resString); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { throw new ServiceException("请求失败", resParams); } return resParams.getString("media_id"); } /** * @param text 明文 * @return 加密后的数据 */ public String encrypt(String text) { // 建议从Verifier中获得微信支付平台证书,或使用预先下载到本地的平台证书文件中 X509Certificate certificate = verifier.getValidCertificate(); try { return RsaCryptoUtil.encryptOAEP(text, certificate); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } return null; } /** * @param ciphertext 密文 * @return 解密后端数据 */ public String decrypt(String ciphertext) { // 使用商户私钥解密 try { return RsaCryptoUtil.decryptOAEP(ciphertext, wxconfig.privateKey); } catch (BadPaddingException e) { e.printStackTrace(); } return null; } /** * 获取POST请求的json参数 */ private String getRequestBody(HttpServletRequest request) { try (BufferedReader streamReader = new BufferedReader(new InputStreamReader(request.getInputStream(), StandardCharsets.UTF_8))) { StringBuilder responseStrBuilder = new StringBuilder(); String inputStr; while ((inputStr = streamReader.readLine()) != null) { responseStrBuilder.append(inputStr); } return responseStrBuilder.toString(); } catch (IOException e) { throw new RuntimeException(e); } } }
service里面有个方法是服务商进件的方法,里面的请求参数非常多,建议参考微信支付-开发者文档 (qq.com)
标签:requestParams,String,微信,服务商,api,httpPost,JSONObject,put,new From: https://www.cnblogs.com/wzkris/p/16998665.html