Commit 097828a9 authored by lijun's avatar lijun

del pay model

parent 2a4c5c1f
......@@ -27,6 +27,5 @@
<module>smart-common-im</module>
<module>smart-common-lock</module>
<module>smart-common-mq</module>
<module>smart-common-pay</module>
</modules>
</project>
......@@ -106,11 +106,6 @@
<artifactId>smart-common-mq</artifactId>
<version>${smart.version}</version>
</dependency>
<dependency>
<groupId>com.smart.hospital</groupId>
<artifactId>smart-common-pay</artifactId>
<version>${smart.version}</version>
</dependency>
<!--mybatis plus extension,包含了mybatis plus core-->
<dependency>
<groupId>com.baomidou</groupId>
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.smart.hospital</groupId>
<artifactId>smart-hospital-common</artifactId>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<description>支付模块</description>
<artifactId>smart-common-pay</artifactId>
<packaging>jar</packaging>
<properties>
<alipay.version>4.16.57.ALL</alipay.version>
<fastjson.version>1.2.78</fastjson.version>
</properties>
<dependencies>
<dependency>
<groupId>com.smart.hospital</groupId>
<artifactId>smart-common-core</artifactId>
</dependency>
<!--ali sdk-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>${alipay.version}</version>
<exclusions>
<exclusion>
<artifactId>fastjson</artifactId>
<groupId>com.alibaba</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
</dependencies>
</project>
package com.smart.hospital.common.pay;
import com.smart.hospital.common.pay.annotation.ClientScan;
import com.smart.hospital.common.pay.parser.DefaultPayAnnotationParser;
import com.smart.hospital.common.pay.parser.PayAnnotationParser;
import com.smart.hospital.common.pay.prop.WxPayV3Properties;
import com.smart.hospital.common.pay.source.AnnotationPayAttributeSource;
import com.smart.hospital.common.pay.source.PayAttributeSource;
import com.smart.hospital.common.pay.strategy.PayStrategy;
import com.smart.hospital.common.pay.strategy.PayStrategyManager;
import com.smart.hospital.common.pay.strategy.StrategyPropertiesCustomizer;
import com.smart.hospital.common.pay.strategy.builder.HandlerFactoryBuilder;
import com.smart.hospital.common.pay.strategy.builder.PayHandlerFactoryBuilder;
import com.smart.hospital.common.pay.strategy.handler.WxCertV3StrategyHandler;
import com.smart.hospital.common.pay.strategy.handler.WxJsapiV3StrategyHandler;
import com.smart.hospital.common.pay.strategy.handler.StrategyHandler;
import com.smart.hospital.common.pay.strategy.handler.WxRefundStrategyHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.lang.Nullable;
import java.util.List;
/**
* 支付自动配置类
*/
@Order
@Configuration
@EnableConfigurationProperties({WxPayV3Properties.class})
@ClientScan(basePackages = {"com.smart.hospital.common.pay.client"})
public class PayAutoConfiguration {
// @Bean
// 使用该种方法会导致过早得实例化,从而导致配置文件WxPayV3Properties注入得属性都为空
// public static PayClientBeanConfigurer payClientBeanConfigurer(PayAttributeSource payAttributeSource, PayStrategy payStrategyManager) {
// PayClientBeanConfigurer configurer = new PayClientBeanConfigurer();
// configurer.setPayAttributeSource(payAttributeSource);
// configurer.setPayStrategyManager(payStrategyManager);
// configurer.setBasePackage("com.smart.hospital.common.pay.client");
// return configurer;
// }
@Bean
public PayAttributeSource annotationPayAttributeSource(ObjectProvider<List<PayAnnotationParser>> objectProvider) {
return new AnnotationPayAttributeSource(objectProvider.getIfAvailable());
}
@Bean
public PayAnnotationParser defaultPayAnnotationParser() {
return new DefaultPayAnnotationParser();
}
@Bean
@ConditionalOnMissingBean
public HandlerFactoryBuilder payHandlerFactoryBuilder(ObjectProvider<List<StrategyHandler>> objectProvider) {
return new PayHandlerFactoryBuilder(objectProvider.getIfAvailable());
}
@Bean
@ConditionalOnMissingBean
public PayStrategy payStrategyManager(HandlerFactoryBuilder payHandlerFactoryBuilder) {
PayStrategyManager strategyManager = new PayStrategyManager();
strategyManager.setFactoryBuilder(payHandlerFactoryBuilder);
return strategyManager;
}
@Bean
@ConditionalOnMissingClass
public StrategyPropertiesCustomizer strategyPropertiesCustomizer(@Nullable WxPayV3Properties wxPayV3Properties, @Nullable List<StrategyHandler> handlers) {
return new StrategyPropertiesCustomizer(wxPayV3Properties, handlers);
}
@Bean
public StrategyHandler wxJsapiV3StrategyHandler() {
return new WxJsapiV3StrategyHandler();
}
@Bean
public StrategyHandler wxCertV3StrategyHandler() {
return new WxCertV3StrategyHandler();
}
@Bean
public StrategyHandler wxRefundStrategyHandler() {
return new WxRefundStrategyHandler();
}
}
package com.smart.hospital.common.pay.annotation;
import com.smart.hospital.common.pay.constant.Version;
import com.smart.hospital.common.pay.enums.PaymentMethod;
import org.springframework.http.HttpMethod;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 支付支付
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ALI {
/**
* 支付方式
*
* @return
*/
PaymentMethod payment() default PaymentMethod.ALI_WEB;
/**
* 版本
*
* @return
*/
String version() default Version.ALI_1_0;
/**
* 请求地址
*
* @return
*/
// String url() default "";
/**
* 请求方式
*
* @return
*/
HttpMethod method() default HttpMethod.POST;
}
package com.smart.hospital.common.pay.annotation;
import com.smart.hospital.common.pay.config.PayClientBeanDefinitionRegister;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(PayClientBeanDefinitionRegister.class)
public @interface ClientScan {
String[] basePackages() default {};
}
package com.smart.hospital.common.pay.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 银联支付
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UNION {
}
package com.smart.hospital.common.pay.annotation;
import com.smart.hospital.common.pay.constant.Version;
import com.smart.hospital.common.pay.enums.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 微信支付
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WX {
/**
* 支付方式
*
* @return
*/
PaymentMethod payment() default PaymentMethod.WX_JSAPI;
/**
* 商户平台模式
*
* @return
*/
PayModel model() default PayModel.BUSINESS_MODEL;
/**
* 版本
*
* @return
*/
String version() default Version.WX_V2;
/**
* 请求路径前缀
*
* @return
*/
Domain prefix() default Domain.CHINA;
/**
* 请求路径后缀
*
* @return
*/
Uri suffix();
/**
* 请求方式
*
* @return
*/
RequestMethod method() default RequestMethod.POST;
}
package com.smart.hospital.common.pay.client;
import com.alipay.api.AlipayResponse;
import com.smart.hospital.common.pay.annotation.ALI;
import com.smart.hospital.common.pay.annotation.WX;
import com.smart.hospital.common.pay.constant.Version;
import com.smart.hospital.common.pay.enums.PaymentMethod;
import com.smart.hospital.common.pay.enums.Domain;
import com.smart.hospital.common.pay.enums.RequestMethod;
import com.smart.hospital.common.pay.enums.Uri;
import com.smart.hospital.common.pay.model.*;
import org.springframework.http.HttpMethod;
/**
* 支付客户端
*/
public interface PayClient {
@WX(prefix = Domain.CHINA, suffix = Uri.JS_API_PAY, version = Version.WX_V3, method = RequestMethod.POST, payment = PaymentMethod.WX_JSAPI)
String wxJsapiPay(WxUnifiedOrderModel model);
@WX(prefix = Domain.CHINA, suffix = Uri.REFUND, version = Version.WX_V3, method = RequestMethod.POST, payment = PaymentMethod.WX_REFUND)
String wxRefund(WxRefundModel model);
@WX(prefix = Domain.CHINA, suffix = Uri.GET_CERTIFICATES, version = Version.WX_V3, payment = PaymentMethod.WX_CERT, method = RequestMethod.GET)
WxHttpResponse wxPlatformCert();
@ALI(method = HttpMethod.POST, payment = PaymentMethod.ALI_WEB)
<T extends AlipayResponse> T aliWebPay(AliUnifiedOrderModel<?> model);
}
package com.smart.hospital.common.pay.config;
import com.smart.hospital.common.pay.source.PayAttributeSource;
import com.smart.hospital.common.pay.strategy.PayStrategy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.StringUtils;
public abstract class AbstractBeanConfigurer implements BeanDefinitionRegistryPostProcessor {
private String basePackage;
private PayAttributeSource payAttributeSource;
private PayStrategy payStrategyManager;
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
PayClientRegistryScanner scanner = new PayClientRegistryScanner(registry);
scanner.setPayAttributeSource(payAttributeSource);
scanner.setPayStrategy(payStrategyManager);
scanner.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// do nothing
}
public String getBasePackage() {
return basePackage;
}
public void setBasePackage(String basePackage) {
this.basePackage = basePackage;
}
public PayAttributeSource getPayAttributeSource() {
return payAttributeSource;
}
public void setPayAttributeSource(PayAttributeSource payAttributeSource) {
this.payAttributeSource = payAttributeSource;
}
public PayStrategy getPayStrategyManager() {
return payStrategyManager;
}
public void setPayStrategyManager(PayStrategy payStrategyManager) {
this.payStrategyManager = payStrategyManager;
}
}
package com.smart.hospital.common.pay.config;
import com.smart.hospital.common.pay.factory.PayFactoryBean;
import com.smart.hospital.common.pay.source.PayAttributeSource;
import com.smart.hospital.common.pay.strategy.PayStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import java.util.Arrays;
import java.util.Set;
@Slf4j
public abstract class AbstractClientRegistryScanner extends ClassPathBeanDefinitionScanner {
private PayAttributeSource payAttributeSource;
private PayStrategy payStrategy;
protected PayFactoryBean<?> factoryBean = new PayFactoryBean<>();
public AbstractClientRegistryScanner(BeanDefinitionRegistry registry) {
super(registry, false);
}
public PayFactoryBean<?> getFactoryBean() {
return factoryBean;
}
public PayAttributeSource getPayAttributeSource() {
return payAttributeSource;
}
public void setPayAttributeSource(PayAttributeSource payAttributeSource) {
this.payAttributeSource = payAttributeSource;
}
public void setPayStrategy(PayStrategy payStrategy) {
this.payStrategy = payStrategy;
}
public PayStrategy getPayStrategy() {
return payStrategy;
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Set<BeanDefinitionHolder> definitions = super.doScan(basePackages);
if (definitions.isEmpty()) {
log.warn("No interface was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
processBeanDefinitions(definitions);
}
return definitions;
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
public void registerFilters() {
boolean acceptAllInterfaces = true;
if (acceptAllInterfaces) {
// default include filter that accepts all classes
addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
}
// exclude package-info.java
addExcludeFilter((metadataReader, metadataReaderFactory) -> {
String className = metadataReader.getClassMetadata().getClassName();
return className.endsWith("package-info");
});
}
/**
* 处理Bean
*
* @param beanDefinitions
*/
protected abstract void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions);
}
package com.smart.hospital.common.pay.config;
public class PayClientBeanConfigurer extends AbstractBeanConfigurer {
}
package com.smart.hospital.common.pay.config;
import com.smart.hospital.common.pay.annotation.ClientScan;
import com.smart.hospital.common.pay.source.PayAttributeSource;
import com.smart.hospital.common.pay.strategy.PayStrategy;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class PayClientBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
private PayAttributeSource payAttributeSource;
private PayStrategy payStrategyManager;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(ClientScan.class.getName()));
if (mapperScanAttrs != null) {
registerBeanDefinitions(mapperScanAttrs, registry);
}
}
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry) {
List<String> basePackages = Arrays.stream(annoAttrs.getStringArray("basePackages"))
.filter(StringUtils::hasText).collect(Collectors.toList());
PayClientRegistryScanner scanner = new PayClientRegistryScanner(registry);
scanner.setPayAttributeSource(payAttributeSource);
scanner.setPayStrategy(payStrategyManager);
scanner.registerFilters();
scanner.scan(StringUtils.toStringArray(basePackages));
}
public PayAttributeSource getPayAttributeSource() {
return payAttributeSource;
}
public void setPayAttributeSource(PayAttributeSource payAttributeSource) {
this.payAttributeSource = payAttributeSource;
}
public PayStrategy getPayStrategyManager() {
return payStrategyManager;
}
public void setPayStrategyManager(PayStrategy payStrategyManager) {
this.payStrategyManager = payStrategyManager;
}
}
package com.smart.hospital.common.pay.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import java.util.Objects;
import java.util.Set;
@Slf4j
public class PayClientRegistryScanner extends AbstractClientRegistryScanner {
public PayClientRegistryScanner(BeanDefinitionRegistry registry) {
super(registry);
}
@Override
protected void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
log.info("Creating FactoryBean with name '" + holder.getBeanName() + "' and '" + definition.getBeanClassName() + "' clientInterface");
// 构造器注入
definition.getConstructorArgumentValues().addGenericArgumentValue(Objects.requireNonNull(definition.getBeanClassName()));
// 属性注入
definition.getPropertyValues().add("payAttributeSource", getPayAttributeSource());
definition.getPropertyValues().add("payStrategy", getPayStrategy());
// 设置FactoryBean类型
definition.setBeanClass(getFactoryBean().getClass());
definition.setPrimary(true);
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
}
package com.smart.hospital.common.pay.constant;
/**
* 请求地址URL
*/
public interface URL {
/**
* 微信jsapi调用接口
*/
String WX_JSAPI = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
}
package com.smart.hospital.common.pay.constant;
/**
* 支付版本号
*/
public interface Version {
/**
* 微信v3支付
*/
String WX_V3 = "v3";
/**
* 微信v2支付
*/
String WX_V2 = "v2";
/**
* 支付宝1.0支付
*/
String ALI_1_0 = "1.0";
}
package com.smart.hospital.common.pay.core.wx;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import com.smart.hospital.common.pay.enums.*;
import com.smart.hospital.common.pay.model.WxHttpResponse;
import com.smart.hospital.common.pay.util.HttpKit;
import com.smart.hospital.common.pay.util.PayKit;
import com.smart.hospital.common.pay.util.WxPayKit;
import java.io.File;
import java.io.InputStream;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.Map;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875</p>
*
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
*
* <p>微信支付相关接口</p>
*
* @author Javen
*/
public class WxPayApi {
/**
* 获取接口请求的 URL
*
* @param Uri {@link Uri} 支付 API 接口枚举
* @return {@link String} 返回完整的接口请求URL
*/
public static String getReqUrl(Uri Uri) {
return getReqUrl(Uri, null, false);
}
/**
* 获取接口请求的 URL
*
* @param Uri {@link Uri} 支付 API 接口枚举
* @param isSandBox 是否是沙箱环境
* @return {@link String} 返回完整的接口请求URL
*/
public static String getReqUrl(Uri Uri, boolean isSandBox) {
return getReqUrl(Uri, null, isSandBox);
}
/**
* 获取接口请求的 URL
*
* @param Uri {@link Uri} 支付 API 接口枚举
* @param Domain {@link Domain} 支付 API 接口域名枚举
* @param isSandBox 是否是沙箱环境
* @return {@link String} 返回完整的接口请求URL
*/
public static String getReqUrl(Uri Uri, Domain Domain, boolean isSandBox) {
if (Domain == null) {
Domain = Domain.CHINA;
}
return Domain.getType()
.concat(isSandBox ? Uri.SAND_BOX_NEW.getType() : "")
.concat(Uri.getType());
}
/**
* 发起请求
*
* @param apiUrl 接口 URL
* 通过 {@link WxPayApi#getReqUrl(Uri)}
* 或者 {@link WxPayApi#getReqUrl(Uri, Domain, boolean)} 来获取
* @param params 接口请求参数
* @return {@link String} 请求返回的结果
*/
public static String execution(String apiUrl, Map<String, String> params) {
return doPost(apiUrl, params);
}
/**
* 发起请求
*
* @param apiUrl 接口 URL
* 通过 {@link WxPayApi#getReqUrl(Uri)}
* 或者 {@link WxPayApi#getReqUrl(Uri, Domain, boolean)} 来获取
* @param params 接口请求参数
* @return {@link String} 请求返回的结果
*/
public static String executionByGet(String apiUrl, Map<String, Object> params) {
return doGet(apiUrl, params);
}
/**
* 发起请求
*
* @param apiUrl 接口 URL
* 通过 {@link WxPayApi#getReqUrl(Uri)}
* 或者 {@link WxPayApi#getReqUrl(Uri, Domain, boolean)} 来获取
* @param params 接口请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String execution(String apiUrl, Map<String, String> params, String certPath, String certPass) {
return doPostSsl(apiUrl, params, certPath, certPass);
}
/**
* 发起请求
*
* @param apiUrl 接口 URL
* 通过 {@link WxPayApi#getReqUrl(Uri)}
* 或者 {@link WxPayApi#getReqUrl(Uri, Domain, boolean)} 来获取
* @param params 接口请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String executionByProtocol(String apiUrl, Map<String, String> params, String certPath, String certPass, String protocol) {
return doPostSslByProtocol(apiUrl, params, certPath, certPass, protocol);
}
/**
* 发起请求
*
* @param apiUrl 接口 URL
* 通过 {@link WxPayApi#getReqUrl(Uri)}
* 或者 {@link WxPayApi#getReqUrl(Uri, Domain, boolean)} 来获取
* @param params 接口请求参数
* @param certPath 证书文件路径
* @return {@link String} 请求返回的结果
*/
public static String execution(String apiUrl, Map<String, String> params, String certPath) {
return doPostSsl(apiUrl, params, certPath);
}
/**
* 发起请求
*
* @param apiUrl 接口 URL
* 通过 {@link WxPayApi#getReqUrl(Uri)}
* 或者 {@link WxPayApi#getReqUrl(Uri, Domain, boolean)} 来获取
* @param params 接口请求参数
* @param certPath 证书文件路径
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String executionByProtocol(String apiUrl, Map<String, String> params, String certPath, String protocol) {
return doPostSslByProtocol(apiUrl, params, certPath, protocol);
}
/**
* 发起请求
*
* @param apiUrl 接口 URL
* 通过 {@link WxPayApi#getReqUrl(Uri)}
* 或者 {@link WxPayApi#getReqUrl(Uri, Domain, boolean)} 来获取
* @param params 接口请求参数
* @param certFile 证书文件输入流
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String execution(String apiUrl, Map<String, String> params, InputStream certFile, String certPass) {
return doPostSsl(apiUrl, params, certFile, certPass);
}
/**
* 发起请求
*
* @param apiUrl 接口 URL
* 通过 {@link WxPayApi#getReqUrl(Uri)}
* 或者 {@link WxPayApi#getReqUrl(Uri, Domain, boolean)} 来获取
* @param params 接口请求参数
* @param certFile 证书文件输入流
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String executionByProtocol(String apiUrl, Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return doPostSslByProtocol(apiUrl, params, certFile, certPass, protocol);
}
/**
* 发起请求
*
* @param apiUrl 接口 URL
* 通过 {@link WxPayApi#getReqUrl(Uri)}
* 或者 {@link WxPayApi#getReqUrl(Uri, Domain, boolean)} 来获取
* @param params 接口请求参数
* @param certFile 证书文件输入流
* @return {@link String} 请求返回的结果
*/
public static String execution(String apiUrl, Map<String, String> params, InputStream certFile) {
return doPostSsl(apiUrl, params, certFile);
}
/**
* 发起请求
*
* @param apiUrl 接口 URL
* 通过 {@link WxPayApi#getReqUrl(Uri)}
* 或者 {@link WxPayApi#getReqUrl(Uri, Domain, boolean)} 来获取
* @param params 接口请求参数
* @param certFile 证书文件输入流
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String executionByProtocol(String apiUrl, Map<String, String> params, InputStream certFile, String protocol) {
return doPostSslByProtocol(apiUrl, params, certFile, protocol);
}
public static String execution(String apiUrl, Map<String, String> params,
String certPath, String certPass, String filePath) {
return doUploadSsl(apiUrl, params, certPath, certPass, filePath);
}
public static String executionByProtocol(String apiUrl, Map<String, String> params, String certPath, String certPass, String filePath, String protocol) {
return doUploadSslByProtocol(apiUrl, params, certPath, certPass, filePath, protocol);
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号,接口中包含敏感信息时必传
* @param keyPath apiclient_key.pem 证书路径
* @param body 接口请求参数
* @param nonceStr 随机字符库
* @param timestamp 时间戳
* @param authType 认证类型
* @param file 文件
* @return {@link WxHttpResponse} 请求返回的结果
* @throws Exception 接口执行异常
*/
public static WxHttpResponse v3(RequestMethod method, String urlPrefix, String urlSuffix,
String mchId, String serialNo, String platSerialNo, String keyPath,
String body, String nonceStr, long timestamp, String authType,
File file) throws Exception {
// 构建 Authorization
String authorization = WxPayKit.buildAuthorization(method, urlSuffix, mchId, serialNo,
keyPath, body, nonceStr, timestamp, authType);
if (StrUtil.isEmpty(platSerialNo)) {
platSerialNo = serialNo;
}
if (method == RequestMethod.GET) {
return get(urlPrefix.concat(urlSuffix), authorization, platSerialNo, null);
} else if (method == RequestMethod.POST) {
return post(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
} else if (method == RequestMethod.DELETE) {
return delete(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
} else if (method == RequestMethod.UPLOAD) {
return upload(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body, file);
} else if (method == RequestMethod.PUT) {
return put(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
}
return null;
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号,接口中包含敏感信息时必传
* @param privateKey 商户私钥
* @param body 接口请求参数
* @param nonceStr 随机字符库
* @param timestamp 时间戳
* @param authType 认证类型
* @param file 文件
* @return {@link WxHttpResponse} 请求返回的结果
* @throws Exception 接口执行异常
*/
public static WxHttpResponse v3(RequestMethod method, String urlPrefix, String urlSuffix,
String mchId, String serialNo, String platSerialNo, PrivateKey privateKey,
String body, String nonceStr, long timestamp, String authType,
File file) throws Exception {
// 构建 Authorization
String authorization = WxPayKit.buildAuthorization(method, urlSuffix, mchId, serialNo,
privateKey, body, nonceStr, timestamp, authType);
if (StrUtil.isEmpty(platSerialNo)) {
platSerialNo = serialNo;
}
if (method == RequestMethod.GET) {
return get(urlPrefix.concat(urlSuffix), authorization, platSerialNo, null);
} else if (method == RequestMethod.POST) {
return post(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
} else if (method == RequestMethod.DELETE) {
return delete(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
} else if (method == RequestMethod.UPLOAD) {
return upload(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body, file);
} else if (method == RequestMethod.PUT) {
return put(urlPrefix.concat(urlSuffix), authorization, platSerialNo, body);
}
return null;
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号
* @param keyPath apiclient_key.pem 证书路径
* @param body 接口请求参数
* @return {@link WxHttpResponse} 请求返回的结果
* @throws Exception 接口执行异常
*/
public static WxHttpResponse v3(RequestMethod method, String urlPrefix, String urlSuffix, String mchId,
String serialNo, String platSerialNo, String keyPath, String body) throws Exception {
long timestamp = System.currentTimeMillis() / 1000;
String authType = "WECHATPAY2-SHA256-RSA2048";
String nonceStr = WxPayKit.generateStr();
return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, nonceStr, timestamp, authType, null);
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号
* @param privateKey 商户私钥
* @param body 接口请求参数
* @return {@link WxHttpResponse} 请求返回的结果
* @throws Exception 接口执行异常
*/
public static WxHttpResponse v3(RequestMethod method, String urlPrefix, String urlSuffix, String mchId,
String serialNo, String platSerialNo, PrivateKey privateKey, String body) throws Exception {
long timestamp = System.currentTimeMillis() / 1000;
String authType = "WECHATPAY2-SHA256-RSA2048";
String nonceStr = WxPayKit.generateStr();
return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, privateKey, body, nonceStr, timestamp, authType, null);
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号
* @param keyPath apiclient_key.pem 证书路径
* @param params Get 接口请求参数
* @return {@link WxHttpResponse} 请求返回的结果
* @throws Exception 接口执行异常
*/
public static WxHttpResponse v3(RequestMethod method, String urlPrefix, String urlSuffix,
String mchId, String serialNo, String platSerialNo, String keyPath,
Map<String, String> params) throws Exception {
long timestamp = System.currentTimeMillis() / 1000;
String authType = "WECHATPAY2-SHA256-RSA2048";
String nonceStr = WxPayKit.generateStr();
if (null != params && !params.keySet().isEmpty()) {
urlSuffix = urlSuffix.concat("?").concat(PayKit.createLinkString(params, true));
}
return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, "", nonceStr, timestamp, authType, null);
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号
* @param privateKey 商户私钥
* @param params Get 接口请求参数
* @return {@link WxHttpResponse} 请求返回的结果
* @throws Exception 接口执行异常
*/
public static WxHttpResponse v3(RequestMethod method, String urlPrefix, String urlSuffix,
String mchId, String serialNo, String platSerialNo, PrivateKey privateKey,
Map<String, String> params) throws Exception {
long timestamp = System.currentTimeMillis() / 1000;
String authType = "WECHATPAY2-SHA256-RSA2048";
String nonceStr = WxPayKit.generateStr();
if (null != params && !params.keySet().isEmpty()) {
urlSuffix = urlSuffix.concat("?").concat(PayKit.createLinkString(params, true));
}
return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, privateKey, "", nonceStr, timestamp, authType, null);
}
/**
* V3 接口统一执行入口
*
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号
* @param keyPath apiclient_key.pem 证书路径
* @param body 接口请求参数
* @param file 文件
* @return {@link WxHttpResponse} 请求返回的结果
* @throws Exception 接口执行异常
*/
public static WxHttpResponse v3(String urlPrefix, String urlSuffix, String mchId, String serialNo, String platSerialNo, String keyPath, String body, File file) throws Exception {
long timestamp = System.currentTimeMillis() / 1000;
String authType = "WECHATPAY2-SHA256-RSA2048";
String nonceStr = WxPayKit.generateStr();
return v3(RequestMethod.UPLOAD, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, nonceStr, timestamp, authType, file);
}
/**
* V3 接口统一执行入口
*
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号
* @param privateKey 商户私钥
* @param body 接口请求参数
* @param file 文件
* @return {@link WxHttpResponse} 请求返回的结果
* @throws Exception 接口执行异常
*/
public static WxHttpResponse v3(String urlPrefix, String urlSuffix, String mchId, String serialNo,
String platSerialNo, PrivateKey privateKey, String body, File file) throws Exception {
long timestamp = System.currentTimeMillis() / 1000;
String authType = "WECHATPAY2-SHA256-RSA2048";
String nonceStr = WxPayKit.generateStr();
return v3(RequestMethod.UPLOAD, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, privateKey, body, nonceStr, timestamp, authType, file);
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号,接口中包含敏感信息时必传
* @param keyPath apiclient_key.pem 证书路径
* @param body 接口请求参数
* @param nonceStr 随机字符库
* @param timestamp 时间戳
* @param authType 认证类型
* @param file 文件
* @return {@link Map} 请求返回的结果
* @throws Exception 接口执行异常
*/
@Deprecated
public static Map<String, Object> v3Execution(RequestMethod method, String urlPrefix, String urlSuffix,
String mchId, String serialNo, String platSerialNo, String keyPath,
String body, String nonceStr, long timestamp, String authType,
File file) throws Exception {
WxHttpResponse response = v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, nonceStr, timestamp, authType, file);
return buildResMap(response);
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param keyPath apiclient_key.pem 证书路径
* @param body 接口请求参数
* @return {@link Map} 请求返回的结果
*/
@Deprecated
public static Map<String, Object> v3Execution(RequestMethod method, String urlPrefix, String urlSuffix, String mchId,
String serialNo, String keyPath, String body) throws Exception {
WxHttpResponse response = v3(method, urlPrefix, urlSuffix, mchId, serialNo, null, keyPath, body);
return buildResMap(response);
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号
* @param keyPath apiclient_key.pem 证书路径
* @param body 接口请求参数
* @return {@link Map} 请求返回的结果
* @throws Exception 接口执行异常
*/
@Deprecated
public static Map<String, Object> v3Execution(RequestMethod method, String urlPrefix, String urlSuffix, String mchId,
String serialNo, String platSerialNo, String keyPath, String body) throws Exception {
WxHttpResponse response = v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body);
return buildResMap(response);
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号
* @param keyPath apiclient_key.pem 证书路径
* @param params Get 接口请求参数
* @return {@link Map} 请求返回的结果
* @throws Exception 接口执行异常
*/
@Deprecated
public static Map<String, Object> v3Execution(RequestMethod method, String urlPrefix, String urlSuffix,
String mchId, String serialNo, String platSerialNo, String keyPath,
Map<String, String> params) throws Exception {
WxHttpResponse response = v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, params);
return buildResMap(response);
}
/**
* V3 接口统一执行入口
*
* @param method {@link RequestMethod} 请求方法
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param keyPath apiclient_key.pem 证书路径
* @param params Get 接口请求参数
* @return {@link Map} 请求返回的结果
* @throws Exception 接口执行异常
*/
@Deprecated
public static Map<String, Object> v3Execution(RequestMethod method, String urlPrefix, String urlSuffix,
String mchId, String serialNo, String keyPath,
Map<String, String> params) throws Exception {
WxHttpResponse response = v3(method, urlPrefix, urlSuffix, mchId, serialNo, null, keyPath, params);
return buildResMap(response);
}
/**
* V3 接口统一执行入口
*
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param platSerialNo 平台序列号
* @param keyPath apiclient_key.pem 证书路径
* @param body 接口请求参数
* @param file 文件
* @return {@link Map} 请求返回的结果
* @throws Exception 接口执行异常
*/
@Deprecated
public static Map<String, Object> v3Upload(String urlPrefix, String urlSuffix, String mchId, String serialNo, String platSerialNo, String keyPath, String body, File file) throws Exception {
WxHttpResponse response = v3(urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, file);
return buildResMap(response);
}
/**
* V3 接口统一执行入口
*
* @param urlPrefix 可通过 {@link Domain}来获取
* @param urlSuffix 可通过 {@link Uri} 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param keyPath apiclient_key.pem 证书路径
* @param body 接口请求参数
* @param file 文件
* @return {@link Map} 请求返回的结果
* @throws Exception 接口执行异常
*/
@Deprecated
public static Map<String, Object> v3Upload(String urlPrefix, String urlSuffix, String mchId, String serialNo, String keyPath, String body, File file) throws Exception {
return v3Upload(urlPrefix, urlSuffix, mchId, serialNo, null, keyPath, body, file);
}
/**
* 获取验签秘钥API
*
* @param mchId 商户号
* @param partnerKey API 密钥
* @param signType 签名方式
* @return {@link String} 请求返回的结果
*/
public static String getSignKey(String mchId, String partnerKey, SignType signType) {
Map<String, String> map = new HashMap<>(3);
String nonceStr = WxPayKit.generateStr();
map.put("mch_id", mchId);
map.put("nonce_str", nonceStr);
map.put("sign", WxPayKit.createSign(map, partnerKey, signType));
return execution(getReqUrl(Uri.GET_SIGN_KEY), map);
}
/**
* 统一下单
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String pushOrder(Map<String, String> params) {
return pushOrder(false, null, params);
}
/**
* 统一下单
*
* @param isSandbox 是否是沙盒环境
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String pushOrder(boolean isSandbox, Map<String, String> params) {
return pushOrder(isSandbox, null, params);
}
/**
* 统一下单
*
* @param isSandbox 是否是沙盒环境
* @param Domain {@link Domain} 支付 API 接口域名枚举
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String pushOrder(boolean isSandbox, Domain Domain, Map<String, String> params) {
return execution(getReqUrl(Uri.UNIFIED_ORDER, Domain, isSandbox), params);
}
/**
* 订单查询
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String orderQuery(Map<String, String> params) {
return orderQuery(false, null, params);
}
/**
* 订单查询
*
* @param isSandbox 是否是沙盒环境
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String orderQuery(boolean isSandbox, Map<String, String> params) {
return execution(getReqUrl(Uri.ORDER_QUERY, null, isSandbox), params);
}
/**
* 订单查询
*
* @param isSandbox 是否是沙盒环境
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String orderQuery(boolean isSandbox, Domain Domain, Map<String, String> params) {
return execution(getReqUrl(Uri.ORDER_QUERY, Domain, isSandbox), params);
}
/**
* 关闭订单
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String closeOrder(Map<String, String> params) {
return execution(getReqUrl(Uri.CLOSE_ORDER), params);
}
/**
* 撤销订单
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String orderReverse(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.REVERSE), params, certPath, certPass);
}
/**
* 撤销订单
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String orderReverse(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.REVERSE), params, certFile, certPass);
}
/**
* 申请退款
*
* @param isSandbox 是否是沙盒环境
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String orderRefund(boolean isSandbox, Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.REFUND, null, isSandbox), params, certPath, certPass);
}
/**
* 申请退款
*
* @param isSandbox 是否是沙盒环境
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String orderRefundByProtocol(boolean isSandbox, Map<String, String> params, String certPath, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.REFUND, null, isSandbox), params, certPath, certPass, protocol);
}
/**
* 申请退款
*
* @param isSandbox 是否是沙盒环境
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String orderRefund(boolean isSandbox, Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.REFUND, null, isSandbox), params, certFile, certPass);
}
/**
* 申请退款
*
* @param isSandbox 是否是沙盒环境
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String orderRefundByProtocol(boolean isSandbox, Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.REFUND, null, isSandbox), params, certFile, certPass, protocol);
}
/**
* 查询退款
*
* @param isSandbox 是否是沙盒环境
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String orderRefundQuery(boolean isSandbox, Map<String, String> params) {
return execution(getReqUrl(Uri.REFUND_QUERY, null, isSandbox), params);
}
/**
* 下载对账单
*
* @param isSandbox 是否是沙盒环境
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String downloadBill(boolean isSandbox, Map<String, String> params) {
return execution(getReqUrl(Uri.DOWNLOAD_BILL, null, isSandbox), params);
}
/**
* 交易保障
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String orderReport(Map<String, String> params) {
return execution(getReqUrl(Uri.REPORT, null, false), params);
}
/**
* 转换短链接
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String toShortUrl(Map<String, String> params) {
return execution(getReqUrl(Uri.SHORT_URL, null, false), params);
}
/**
* 授权码查询 openId
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String authCodeToOpenid(Map<String, String> params) {
return execution(getReqUrl(Uri.AUTH_CODE_TO_OPENID, null, false), params);
}
/**
* 刷卡支付
*
* @param isSandbox 是否是沙盒环境
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String microPay(boolean isSandbox, Map<String, String> params) {
return execution(getReqUrl(Uri.MICRO_PAY, null, isSandbox), params);
}
/**
* 企业付款到零钱
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String transfers(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.TRANSFER, null, false), params, certPath, certPass);
}
/**
* 企业付款到零钱
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String transfersByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.TRANSFER, null, false), params, certPath, certPass, protocol);
}
/**
* 企业付款到零钱
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String transfers(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.TRANSFER, null, false), params, certFile, certPass);
}
/**
* 企业付款到零钱
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String transfersByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.TRANSFER, null, false), params, certFile, certPass, protocol);
}
/**
* 查询企业付款到零钱
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String getTransferInfo(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.GET_TRANSFER_INFO, null, false), params, certPath, certPass);
}
/**
* 查询企业付款到零钱
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String getTransferInfo(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.GET_TRANSFER_INFO, null, false), params, certFile, certPass);
}
/**
* 企业付款到银行
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String payBank(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.TRANSFER_BANK, null, false), params, certPath, certPass);
}
/**
* 企业付款到银行
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String payBankByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.TRANSFER_BANK, null, false), params, certPath, certPass, protocol);
}
/**
* 企业付款到银行
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String payBank(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.TRANSFER_BANK, null, false), params, certFile, certPass);
}
/**
* 企业付款到银行
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String payBankByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.TRANSFER_BANK, null, false), params, certFile, certPass, protocol);
}
/**
* 查询企业付款到银行
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String queryBank(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.GET_TRANSFER_BANK_INFO, null, false), params, certPath, certPass);
}
/**
* 查询企业付款到银行
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String queryBank(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.GET_TRANSFER_BANK_INFO, null, false), params, certFile, certPass);
}
/**
* 获取 RSA 加密公钥
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String getPublicKey(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.GET_PUBLIC_KEY, Domain.FRAUD, false), params, certPath, certPass);
}
/**
* 获取 RSA 加密公钥
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String getPublicKey(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.GET_PUBLIC_KEY, Domain.FRAUD, false), params, certFile, certPass);
}
/**
* 公众号纯签约
*
* @param params 请求参数
* @param payModel 商户平台模式
* @return {@link String} 请求返回的结果
*/
public static String entrustWeb(Map<String, Object> params, PayModel payModel) {
if (payModel == PayModel.BUSINESS_MODEL) {
return executionByGet(getReqUrl(Uri.ENTRUST_WEB), params);
} else {
return executionByGet(getReqUrl(Uri.PARTNER_ENTRUST_WEB), params);
}
}
/**
* APP 纯签约
*
* @param params 请求参数
* @param payModel 商户平台模式
* @return {@link String} 请求返回的结果
*/
public static String preEntrustWeb(Map<String, Object> params, PayModel payModel) {
if (payModel == PayModel.BUSINESS_MODEL) {
return executionByGet(getReqUrl(Uri.PRE_ENTRUST_WEB), params);
} else {
return executionByGet(getReqUrl(Uri.PARTNER_PRE_ENTRUST_WEB), params);
}
}
/**
* H5 纯签约
*
* @param params 请求参数
* @param payModel 商户平台模式
* @return {@link String} 请求返回的结果
*/
public static String h5EntrustWeb(Map<String, Object> params, PayModel payModel) {
if (payModel == PayModel.BUSINESS_MODEL) {
return executionByGet(getReqUrl(Uri.H5_ENTRUST_WEB), params);
} else {
return executionByGet(getReqUrl(Uri.PARTNER_H5_ENTRUST_WEB), params);
}
}
/**
* 支付中签约
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String contractOrder(Map<String, String> params) {
return execution(getReqUrl(Uri.PAY_CONTRACT_ORDER), params);
}
/**
* 查询签约关系
*
* @param params 请求参数
* @param payModel 商户平台模式
* @return {@link String} 请求返回的结果
*/
public static String queryContract(Map<String, String> params, PayModel payModel) {
if (payModel == PayModel.BUSINESS_MODEL) {
return execution(getReqUrl(Uri.QUERY_ENTRUST_CONTRACT), params);
} else {
return execution(getReqUrl(Uri.PARTNER_QUERY_ENTRUST_CONTRACT), params);
}
}
/**
* 申请扣款
*
* @param params 请求参数
* @param payModel 商户平台模式
* @return {@link String} 请求返回的结果
*/
public static String papPayApply(Map<String, String> params, PayModel payModel) {
if (payModel == PayModel.BUSINESS_MODEL) {
return execution(getReqUrl(Uri.PAP_PAY_APPLY), params);
} else {
return execution(getReqUrl(Uri.PARTNER_PAP_PAY_APPLY), params);
}
}
/**
* 申请解约
*
* @param params 请求参数
* @param payModel 商户平台模式
* @return {@link String} 请求返回的结果
*/
public static String deleteContract(Map<String, String> params, PayModel payModel) {
if (payModel == PayModel.BUSINESS_MODEL) {
return execution(getReqUrl(Uri.DELETE_ENTRUST_CONTRACT), params);
} else {
return execution(getReqUrl(Uri.PARTNER_DELETE_ENTRUST_CONTRACT), params);
}
}
/**
* 查询签约关系对账单
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String contractBill(Map<String, String> params, PayModel payModel) {
if (payModel == PayModel.BUSINESS_MODEL) {
return execution(getReqUrl(Uri.QUERY_ENTRUST_CONTRACT), params);
} else {
return execution(getReqUrl(Uri.PARTNER_QUERY_ENTRUST_CONTRACT), params);
}
}
/**
* 查询代扣订单
*
* @param params 请求参数
* @param payModel 商户平台模式
* @return {@link String} 请求返回的结果
*/
public static String papOrderQuery(Map<String, String> params, PayModel payModel) {
if (payModel == PayModel.BUSINESS_MODEL) {
return execution(getReqUrl(Uri.PAP_ORDER_QUERY), params);
} else {
return execution(getReqUrl(Uri.PARTNER_PAP_ORDER_QUERY), params);
}
}
/**
* 请求单次分账
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String profitSharing(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.PROFIT_SHARING), params, certPath, certPass);
}
/**
* 请求单次分账
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String profitSharing(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.PROFIT_SHARING), params, certFile, certPass);
}
/**
* 请求多次分账
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String multiProfitSharing(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.MULTI_PROFIT_SHARING), params, certPath, certPass);
}
/**
* 请求多次分账
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String multiProfitSharing(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.MULTI_PROFIT_SHARING), params, certFile, certPass);
}
/**
* 查询分账结果
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String profitSharingQuery(Map<String, String> params) {
return execution(getReqUrl(Uri.PROFIT_SHARING_QUERY), params);
}
/**
* 添加分账接收方
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String profitSharingAddReceiver(Map<String, String> params) {
return execution(getReqUrl(Uri.PROFITS_HARING_ADD_RECEIVER), params);
}
/**
* 删除分账接收方
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String profitSharingRemoveReceiver(Map<String, String> params) {
return execution(getReqUrl(Uri.PROFIT_SHARING_REMOVE_RECEIVER), params);
}
/**
* 完结分账
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String profitSharingFinish(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.PROFIT_SHARING_FINISH), params, certPath, certPass);
}
/**
* 完结分账
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String profitSharingFinish(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.PROFIT_SHARING_FINISH), params, certFile, certPass);
}
/**
* 分账回退
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String profitSharingReturn(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.PROFIT_SHARING_RETURN), params, certPath, certPass);
}
/**
* 分账回退
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String profitSharingReturn(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.PROFIT_SHARING_RETURN), params, certFile, certPass);
}
/**
* 分账回退结果查询
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String profitSharingReturnQuery(Map<String, String> params) {
return execution(getReqUrl(Uri.PROFIT_SHARING_RETURN_QUERY), params);
}
/**
* 发放代金券
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String sendCoupon(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.SEND_COUPON), params, certPath, certPass);
}
/**
* 发放代金券
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String sendCoupon(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.SEND_COUPON), params, certFile, certPass);
}
/**
* 查询代金券批次
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String queryCouponStock(Map<String, String> params) {
return execution(getReqUrl(Uri.QUERY_COUPON_STOCK), params);
}
/**
* 查询代金券信息
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String queryCouponsInfo(Map<String, String> params) {
return execution(getReqUrl(Uri.QUERY_COUPONS_INFO), params);
}
/**
* 拉取订单评价数据
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String batchQueryComment(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.BATCH_QUERY_COMMENT), params, certPath, certPass);
}
/**
* 拉取订单评价数据
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String batchQueryComment(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.BATCH_QUERY_COMMENT), params, certFile, certPass);
}
/**
* 支付押金(人脸支付)
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String depositFacePay(Map<String, String> params) {
return execution(getReqUrl(Uri.DEPOSIT_FACE_PAY), params);
}
/**
* 支付押金(付款码支付)
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String depositMicroPay(Map<String, String> params) {
return execution(getReqUrl(Uri.DEPOSIT_MICRO_PAY), params);
}
/**
* 查询订单
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String depositOrderQuery(Map<String, String> params) {
return execution(getReqUrl(Uri.DEPOSIT_ORDER_QUERY), params);
}
/**
* 撤销订单
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String depositReverse(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.DEPOSIT_REVERSE), params, certPath, certPass);
}
/**
* 撤销订单
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String depositReverse(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.DEPOSIT_REVERSE), params, certFile, certPass);
}
/**
* 消费押金
*
* @param params 请求参数
* @param certPath 证书文件的目录
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String depositConsume(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.DEPOSIT_CONSUME), params, certPath, certPass);
}
/**
* 消费押金
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String depositConsume(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.DEPOSIT_CONSUME), params, certFile, certPass);
}
/**
* 申请退款(押金)
*
* @param params 请求参数
* @param certPath 证书文件的目录
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String depositRefund(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.DEPOSIT_REFUND), params, certPath, certPass);
}
/**
* 申请退款(押金)
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String depositRefund(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.DEPOSIT_REFUND), params, certFile, certPass);
}
/**
* 查询退款(押金)
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String depositRefundQuery(Map<String, String> params) {
return execution(getReqUrl(Uri.DEPOSIT_REFUND_QUERY), params);
}
/**
* 下载资金账单
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String downloadFundFlow(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.DOWNLOAD_FUND_FLOW), params, certPath, certPass);
}
/**
* 下载资金账单
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String downloadFundFlow(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.DOWNLOAD_FUND_FLOW), params, certFile, certPass);
}
/**
* 刷脸设备获取设备调用凭证
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String getAuthInfo(Map<String, String> params) {
return execution(getReqUrl(Uri.GET_AUTH_INFO, Domain.PAY_APP, false), params);
}
/**
* 刷脸支付
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String facePay(Map<String, String> params) {
return execution(getReqUrl(Uri.FACE_PAY), params);
}
/**
* 查询刷脸支付订单
*
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String facePayQuery(Map<String, String> params) {
return execution(getReqUrl(Uri.FACE_PAY_QUERY), params);
}
/**
* 刷脸支付撤销订单
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String facePayReverse(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.FACE_PAY_REVERSE), params, certPath, certPass);
}
/**
* 刷脸支付撤销订单
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String facePayReverse(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.FACE_PAY_REVERSE), params, certFile, certPass);
}
/**
* 发放普通红包
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String sendRedPack(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.SEND_RED_PACK), params, certPath, certPass);
}
/**
* 发放普通红包
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String sendRedPackByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.SEND_RED_PACK), params, certPath, certPass, protocol);
}
/**
* 发放普通红包
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String sendRedPack(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.SEND_RED_PACK), params, certFile, certPass);
}
/**
* 发放普通红包
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String sendRedPackByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.SEND_RED_PACK), params, certFile, certPass, protocol);
}
/**
* 发放裂变红包
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String sendGroupRedPack(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.SEND_GROUP_RED_PACK), params, certPath, certPass);
}
/**
* 发放裂变红包
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String sendGroupRedPackByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.SEND_GROUP_RED_PACK), params, certPath, certPass, protocol);
}
/**
* 发放裂变红包
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String sendGroupRedPack(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.SEND_GROUP_RED_PACK), params, certFile, certPass);
}
/**
* 发放裂变红包
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String sendGroupRedPackByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.SEND_GROUP_RED_PACK), params, certFile, certPass, protocol);
}
/**
* 查询红包记录
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String getHbInfo(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.GET_HB_INFO), params, certPath, certPass);
}
/**
* 查询红包记录
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String getHbInfo(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.GET_HB_INFO), params, certFile, certPass);
}
/**
* 小程序发放红包接口
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String sendMiniProgramRedPack(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.SEND_MINI_PROGRAM_HB), params, certPath, certPass);
}
/**
* 小程序发放红包接口
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String sendMiniProgramRedPackByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.SEND_MINI_PROGRAM_HB), params, certPath, certPass, protocol);
}
/**
* 小程序发放红包接口
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String sendMiniProgramRedPack(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.SEND_MINI_PROGRAM_HB), params, certFile, certPass);
}
/**
* 小程序发放红包接口
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String sendMiniProgramRedPackByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.SEND_MINI_PROGRAM_HB), params, certFile, certPass, protocol);
}
/**
* 发放企业红包
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String sendWorkWxRedPack(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.SEND_WORK_WX_RED_PACK), params, certPath, certPass);
}
/**
* 发放企业红包
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String sendWorkWxRedPackByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.SEND_WORK_WX_RED_PACK), params, certPath, certPass, protocol);
}
/**
* 发放企业红包
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String sendWorkWxRedPack(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.SEND_WORK_WX_RED_PACK), params, certFile, certPass);
}
/**
* 发放企业红包
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String sendWorkWxRedPackByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.SEND_WORK_WX_RED_PACK), params, certFile, certPass, protocol);
}
/**
* 查询向员工付款记录
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String queryWorkWxRedPack(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.QUERY_WORK_WX_RED_PACK), params, certPath, certPass);
}
/**
* 查询向员工付款记录
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String queryWorkWxRedPackByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.QUERY_WORK_WX_RED_PACK), params, certPath, certPass, protocol);
}
/**
* 查询向员工付款记录
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String queryWorkWxRedPack(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.QUERY_WORK_WX_RED_PACK), params, certFile, certPass);
}
/**
* 查询向员工付款记录
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String queryWorkWxRedPackByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.QUERY_WORK_WX_RED_PACK), params, certFile, certPass, protocol);
}
/**
* 向员工付款
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String trans2pocket(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.PAY_WWS_TRANS_2_POCKET), params, certPath, certPass);
}
/**
* 向员工付款
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String trans2pocketByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.PAY_WWS_TRANS_2_POCKET), params, certPath, certPass, protocol);
}
/**
* 向员工付款
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String trans2pocket(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.PAY_WWS_TRANS_2_POCKET), params, certFile, certPass);
}
/**
* 向员工付款
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String trans2pocketByProtocol(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.PAY_WWS_TRANS_2_POCKET), params, certFile, certPass, protocol);
}
/**
* 查询向员工付款记录
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String queryTrans2pocket(Map<String, String> params, String certPath, String certPass) {
return execution(getReqUrl(Uri.QUERY_WWS_TRANS_2_POCKET), params, certPath, certPass);
}
/**
* 查询向员工付款记录
*
* @param params 请求参数
* @param certPath 证书文件路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String queryTrans2pocketByProtocol(Map<String, String> params, String certPath, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.QUERY_WWS_TRANS_2_POCKET), params, certPath, certPass, protocol);
}
/**
* 查询向员工付款记录
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public static String queryTrans2pocket(Map<String, String> params, InputStream certFile, String certPass) {
return execution(getReqUrl(Uri.QUERY_WWS_TRANS_2_POCKET), params, certFile, certPass);
}
/**
* 查询向员工付款记录
*
* @param params 请求参数
* @param certFile 证书文件的 InputStream
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public static String queryTrans2pocket(Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return executionByProtocol(getReqUrl(Uri.QUERY_WWS_TRANS_2_POCKET), params, certFile, certPass, protocol);
}
/**
* @param url 请求url
* @param params 请求参数
* @return {@link String} 请求返回的结果
*/
public static String doGet(String url, Map<String, Object> params) {
return HttpKit.getDelegate().get(url, params);
}
/**
* get 请求
*
* @param url 请求url
* @param params 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public static WxHttpResponse get(String url, Map<String, Object> params, Map<String, String> headers) {
return HttpKit.getDelegate().get(url, params, headers);
}
/**
* get 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param serialNumber 公钥证书序列号
* @param params 请求参数
* @return {@link WxHttpResponse} 请求返回的结果
*/
public static WxHttpResponse get(String url, String authorization, String serialNumber, Map<String, Object> params) {
return get(url, params, getHeaders(authorization, serialNumber));
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public static WxHttpResponse post(String url, String data, Map<String, String> headers) {
return HttpKit.getDelegate().post(url, data, headers);
}
/**
* post 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param serialNumber 公钥证书序列号
* @param data 请求参数
* @return {@link WxHttpResponse} 请求返回的结果
*/
public static WxHttpResponse post(String url, String authorization, String serialNumber, String data) {
return post(url, data, getHeaders(authorization, serialNumber));
}
/**
* delete 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public static WxHttpResponse delete(String url, String data, Map<String, String> headers) {
return HttpKit.getDelegate().delete(url, data, headers);
}
/**
* delete 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param serialNumber 公钥证书序列号
* @param data 请求参数
* @return {@link WxHttpResponse} 请求返回的结果
*/
public static WxHttpResponse delete(String url, String authorization, String serialNumber, String data) {
return delete(url, data, getHeaders(authorization, serialNumber));
}
/**
* upload 请求
*
* @param url 请求url
* @param params 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public static WxHttpResponse upload(String url, Map<String, Object> params, Map<String, String> headers) {
return HttpKit.getDelegate().post(url, params, headers);
}
/**
* upload 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param serialNumber 公钥证书序列号
* @param data 请求参数
* @param file 上传文件
* @return {@link WxHttpResponse} 请求返回的结果
*/
public static WxHttpResponse upload(String url, String authorization, String serialNumber, String data, File file) {
Map<String, Object> paramMap = new HashMap<>(2);
paramMap.put("file", file);
paramMap.put("meta", data);
return upload(url, paramMap, getUploadHeaders(authorization, serialNumber));
}
/**
* put 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public static WxHttpResponse put(String url, String data, Map<String, String> headers) {
return HttpKit.getDelegate().put(url, data, headers);
}
/**
* put 请求
*
* @param url 请求url
* @param authorization 授权信息
* @param serialNumber 公钥证书序列号
* @param data 请求参数
* @return {@link WxHttpResponse} 请求返回的结果
*/
public static WxHttpResponse put(String url, String authorization, String serialNumber, String data) {
return put(url, data, getHeaders(authorization, serialNumber));
}
public static String doPost(String url, Map<String, String> params) {
return HttpKit.getDelegate().post(url, WxPayKit.toXml(params));
}
public static String doPostSsl(String url, Map<String, String> params, String certPath, String certPass) {
return HttpKit.getDelegate().post(url, WxPayKit.toXml(params), certPath, certPass);
}
public static String doPostSslByProtocol(String url, Map<String, String> params, String certPath, String certPass, String protocol) {
return HttpKit.getDelegate().post(url, WxPayKit.toXml(params), certPath, certPass, protocol);
}
public static String doPostSsl(String url, Map<String, String> params, InputStream certFile, String certPass) {
return HttpKit.getDelegate().post(url, WxPayKit.toXml(params), certFile, certPass);
}
public static String doPostSslByProtocol(String url, Map<String, String> params, InputStream certFile, String certPass, String protocol) {
return HttpKit.getDelegate().post(url, WxPayKit.toXml(params), certFile, certPass, protocol);
}
public static String doPostSsl(String url, Map<String, String> params, String certPath) {
if (params.isEmpty() || !params.containsKey("mch_id")) {
throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
}
String certPass = params.get("mch_id");
return doPostSsl(url, params, certPath, certPass);
}
public static String doPostSslByProtocol(String url, Map<String, String> params, String certPath, String protocol) {
if (params.isEmpty() || !params.containsKey("mch_id")) {
throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
}
String certPass = params.get("mch_id");
return doPostSslByProtocol(url, params, certPath, certPass, protocol);
}
public static String doPostSsl(String url, Map<String, String> params, InputStream certFile) {
if (params.isEmpty() || !params.containsKey("mch_id")) {
throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
}
String certPass = params.get("mch_id");
return doPostSsl(url, params, certFile, certPass);
}
public static String doPostSslByProtocol(String url, Map<String, String> params, InputStream certFile, String protocol) {
if (params.isEmpty() || !params.containsKey("mch_id")) {
throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
}
String certPass = params.get("mch_id");
return doPostSslByProtocol(url, params, certFile, certPass, protocol);
}
public static String doUploadSsl(String url, Map<String, String> params, String certPath, String certPass, String filePath) {
return HttpKit.getDelegate().upload(url, WxPayKit.toXml(params), certPath, certPass, filePath);
}
public static String doUploadSslByProtocol(String url, Map<String, String> params, String certPath, String certPass, String filePath, String protocol) {
return HttpKit.getDelegate().upload(url, WxPayKit.toXml(params), certPath, certPass, filePath, protocol);
}
public static String doUploadSsl(String url, Map<String, String> params, String certPath, String filePath) {
if (params.isEmpty() || !params.containsKey("mch_id")) {
throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
}
String certPass = params.get("mch_id");
return doUploadSsl(url, params, certPath, certPass, filePath);
}
public static String doUploadSslByProtocol(String url, Map<String, String> params, String certPath, String filePath, String protocol) {
if (params.isEmpty() || !params.containsKey("mch_id")) {
throw new RuntimeException("请求参数中必须包含 mch_id,如接口参考中不包 mch_id, 请使用其他同名构造方法。");
}
String certPass = params.get("mch_id");
return doUploadSslByProtocol(url, params, certPath, certPass, filePath, protocol);
}
private static final String OS = System.getProperty("os.name") + "/" + System.getProperty("os.version");
private static final String VERSION = System.getProperty("java.version");
public static Map<String, String> getBaseHeaders(String authorization) {
String userAgent = String.format(
"WeChatPay-IJPay-HttpClient/%s (%s) Java/%s",
WxPayApi.class.getPackage().getImplementationVersion(),
OS,
VERSION == null ? "Unknown" : VERSION);
Map<String, String> headers = new HashMap<>(5);
headers.put("Accept", ContentType.JSON.toString());
headers.put("Authorization", authorization);
headers.put("User-Agent", userAgent);
return headers;
}
public static Map<String, String> getHeaders(String authorization, String serialNumber) {
Map<String, String> headers = getBaseHeaders(authorization);
headers.put("Content-Type", ContentType.JSON.toString());
if (StrUtil.isNotEmpty(serialNumber)) {
headers.put("Wechatpay-Serial", serialNumber);
}
return headers;
}
public static Map<String, String> getUploadHeaders(String authorization, String serialNumber) {
Map<String, String> headers = getBaseHeaders(authorization);
headers.put("Content-Type", "multipart/form-data;boundary=\"boundary\"");
if (StrUtil.isNotEmpty(serialNumber)) {
headers.put("Wechatpay-Serial", serialNumber);
}
return headers;
}
/**
* 构建返回参数
*
* @param response {@link WxHttpResponse}
* @return {@link Map}
*/
public static Map<String, Object> buildResMap(WxHttpResponse response) {
if (response == null) {
return null;
}
Map<String, Object> map = new HashMap<>(6);
String timestamp = response.getHeader("Wechatpay-Timestamp");
String nonceStr = response.getHeader("Wechatpay-Nonce");
String serialNo = response.getHeader("Wechatpay-Serial");
String signature = response.getHeader("Wechatpay-Signature");
String body = response.getBody();
int status = response.getStatus();
map.put("timestamp", timestamp);
map.put("nonceStr", nonceStr);
map.put("serialNumber", serialNo);
map.put("signature", signature);
map.put("body", body);
map.put("status", status);
return map;
}
}
package com.smart.hospital.common.pay.enums;
public enum Domain {
/**
* 中国国内
*/
CHINA("https://api.mch.weixin.qq.com"),
/**
* 中国国内(备用域名)
*/
CHINA2("https://api2.mch.weixin.qq.com"),
/**
* 东南亚
*/
HK("https://apihk.mch.weixin.qq.com"),
/**
* 其它
*/
US("https://apius.mch.weixin.qq.com"),
/**
* 获取公钥
*/
FRAUD("https://fraud.mch.weixin.qq.com"),
/**
* 活动
*/
ACTION("https://action.weixin.qq.com"),
/**
* 刷脸支付
* PAY_APP
*/
PAY_APP("https://payapp.weixin.qq.com");
/**
* 域名
*/
private final String type;
Domain(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
package com.smart.hospital.common.pay.enums;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875</p>
*
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
*
* <p>商户平台模式</p>
*
* @author Javen
*/
public enum PayModel {
/**
* 商户模式
*/
BUSINESS_MODEL("BUSINESS_MODEL"),
/**
* 服务商模式
*/
SERVICE_MODE("SERVICE_MODE");
PayModel(String payModel) {
this.payModel = payModel;
}
/**
* 商户模式
*/
private final String payModel;
public String getPayModel() {
return payModel;
}
}
package com.smart.hospital.common.pay.enums;
public enum PayStatus {
PAY_ING(1,"微信接口调用前"),
PAY_SUC(2,"微信接口调用成功"),
PAY_FAIL(-1,"微信接口调用失败"),
;
private int code;
private String msg;
PayStatus(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
package com.smart.hospital.common.pay.enums;
/**
* 支付方式枚举
*/
public enum PaymentMethod {
WX_JSAPI("WX_JSAPI", "小程序/公众号支付"),
WX_APP("WX_APP", "APP支付"),
WX_NATIVE("WX_NATIVE", "二维码支付"),
WX_MICRO("WX_MICRO", "付款码支付"),
WX_REFUND("WX_REFUND", "退款"),
WX_CERT("WX_CERT", "微信获取平台证书"),
ALI_FACE("ALI_FACE", "当面付"),
ALI_APP("ALI_APP", "App支付"),
ALI_WEB("ALI_WEB", "手机网站支付"),
ALI_WAP("ALI_WAP", "电脑网站支付"),
ALI_SWIPING("ALI_SWIPING", "刷脸付"),
;
private String name;
private String describe;
PaymentMethod(String name, String describe) {
this.name = name;
this.describe = describe;
}
public String getDescribe() {
return describe;
}
public void setDescribe(String describe) {
this.describe = describe;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.smart.hospital.common.pay.enums;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875</p>
*
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
*
* <p>HTTP 请求的方法</p>
*
* @author Javen
*/
public enum RequestMethod {
/**
* 上传实质是 post 请求
*/
UPLOAD("POST"),
/**
* post 请求
*/
POST("POST"),
/**
* get 请求
*/
GET("GET"),
/**
* put 请求
*/
PUT("PUT"),
/**
* delete 请求
*/
DELETE("DELETE"),
/**
* options 请求
*/
OPTIONS("OPTIONS"),
/**
* head 请求
*/
HEAD("HEAD"),
/**
* trace 请求
*/
TRACE("TRACE"),
/**
* connect 请求
*/
CONNECT("CONNECT");
private final String method;
RequestMethod(String method) {
this.method = method;
}
@Override
public String toString() {
return this.method;
}
}
package com.smart.hospital.common.pay.enums;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875</p>
*
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
*
* <p>签名方式</p>
*
* @author Javen
*/
public enum SignType {
/**
* HMAC-SHA256 加密
*/
HMACSHA256("HMAC-SHA256"),
/**
* MD5 加密
*/
MD5("MD5"),
/**
* RSA
*/
RSA("RSA");
SignType(String type) {
this.type = type;
}
private final String type;
public String getType() {
return type;
}
@Override
public String toString() {
return type;
}
}
package com.smart.hospital.common.pay.enums;
/**
* 微信支付接口枚举
*/
public enum Uri {
/**
* 沙箱环境
*/
SAND_BOX_NEW("/sandboxnew"),
/**
* 获取沙箱环境验签秘钥
*/
GET_SIGN_KEY("/sandboxnew/pay/getsignkey"),
/**
* 统一下单
*/
UNIFIED_ORDER("/pay/unifiedorder"),
/**
* 提交付款码支付
*/
MICRO_PAY("/pay/micropay"),
/**
* 查询订单
*/
ORDER_QUERY("/pay/orderquery"),
/**
* 关闭订单
*/
CLOSE_ORDER("/pay/closeorder"),
/**
* 撤销订单
*/
REVERSE("/secapi/pay/reverse"),
/**
* 申请退款
*/
REFUND("/secapi/pay/refund"),
/**
* 查询退款
*/
REFUND_QUERY("/pay/refundquery"),
/**
* 下载对账单
*/
DOWNLOAD_BILL("/pay/downloadbill"),
/**
* 下载资金对账单
*/
DOWNLOAD_FUND_FLOW("/pay/downloadfundflow"),
/**
* 交易保障
*/
REPORT("/payitil/report"),
/**
* 转换短链接
*/
SHORT_URL("/tools/shorturl"),
/**
* 授权码查询 openId
*/
AUTH_CODE_TO_OPENID("/tools/authcodetoopenid"),
/**
* 拉取订单评价数据
*/
BATCH_QUERY_COMMENT("/billcommentsp/batchquerycomment"),
/**
* 企业付款
*/
TRANSFER("/mmpaymkttransfers/promotion/transfers"),
/**
* 查询企业付款
*/
GET_TRANSFER_INFO("/mmpaymkttransfers/gettransferinfo"),
/**
* 企业付款到银行卡
*/
TRANSFER_BANK("/mmpaysptrans/pay_bank"),
/**
* 查询企业付款到银行卡
*/
GET_TRANSFER_BANK_INFO("/mmpaysptrans/query_bank"),
/**
* 获取 RSA 加密公钥
*/
GET_PUBLIC_KEY("/risk/getpublickey"),
/**
* 发放红包
*/
SEND_RED_PACK("/mmpaymkttransfers/sendredpack"),
/**
* 发放裂变红包
*/
SEND_GROUP_RED_PACK("/mmpaymkttransfers/sendgroupredpack"),
/**
* 查询红包记录
*/
GET_HB_INFO("/mmpaymkttransfers/gethbinfo"),
/**
* 小程序发红包
*/
SEND_MINI_PROGRAM_HB("/mmpaymkttransfers/sendminiprogramhb"),
/**
* 发放代金券
*/
SEND_COUPON("/mmpaymkttransfers/send_coupon"),
/**
* 查询代金券批次
*/
QUERY_COUPON_STOCK("/mmpaymkttransfers/query_coupon_stock"),
/**
* 查询代金券信息
*/
QUERY_COUPONS_INFO("/mmpaymkttransfers/querycouponsinfo"),
/**
* 请求单次分账
*/
PROFIT_SHARING("/secapi/pay/profitsharing"),
/**
* 请求多次分账
*/
MULTI_PROFIT_SHARING("/secapi/pay/multiprofitsharing"),
/**
* 查询分账结果
*/
PROFIT_SHARING_QUERY("/pay/profitsharingquery"),
/**
* 添加分账接收方
*/
PROFITS_HARING_ADD_RECEIVER("/pay/profitsharingaddreceiver"),
/**
* 删除分账接收方
*/
PROFIT_SHARING_REMOVE_RECEIVER("/pay/profitsharingremovereceiver"),
/**
* 完结分账
*/
PROFIT_SHARING_FINISH("/secapi/pay/profitsharingfinish"),
/**
* 查询订单待分账金额
*/
PROFIT_SHARING_ORDER_AMOUNT_QUERY("/pay/profitsharingorderamountquery"),
/**
* 分账回退
*/
PROFIT_SHARING_RETURN("/secapi/pay/profitsharingreturn"),
/**
* 分账回退结果查询
*/
PROFIT_SHARING_RETURN_QUERY("/pay/profitsharingreturnquery"),
/**
* 支付押金(人脸支付)
*/
DEPOSIT_FACE_PAY("/deposit/facepay"),
/**
* 支付押金(付款码支付)
*/
DEPOSIT_MICRO_PAY("/deposit/micropay"),
/**
* 查询订单(押金)
*/
DEPOSIT_ORDER_QUERY("/deposit/orderquery"),
/**
* 撤销订单(押金)
*/
DEPOSIT_REVERSE("/deposit/reverse"),
/**
* 消费押金
*/
DEPOSIT_CONSUME("/deposit/consume"),
/**
* 申请退款(押金)
*/
DEPOSIT_REFUND("/deposit/refund"),
/**
* 查询退款(押金)
*/
DEPOSIT_REFUND_QUERY("deposit/refundquery"),
/**
* 公众号纯签约
*/
ENTRUST_WEB("/papay/entrustweb"),
/**
* 公众号纯签约(服务商模式)
*/
PARTNER_ENTRUST_WEB("/papay/partner/entrustweb"),
/**
* APP纯签约
*/
PRE_ENTRUST_WEB("/papay/preentrustweb"),
/**
* APP纯签约(服务商模式)
*/
PARTNER_PRE_ENTRUST_WEB("/papay/partner/preentrustweb"),
/**
* H5纯签约
*/
H5_ENTRUST_WEB("/papay/h5entrustweb"),
/**
* H5纯签约(服务商模式)
*/
PARTNER_H5_ENTRUST_WEB("/papay/partner/h5entrustweb"),
/**
* 支付中签约
*/
PAY_CONTRACT_ORDER("/pay/contractorder"),
/**
* 查询签约关系
*/
QUERY_ENTRUST_CONTRACT("/papay/querycontract"),
/**
* 查询签约关系(服务商模式)
*/
PARTNER_QUERY_ENTRUST_CONTRACT("/papay/partner/querycontract"),
/**
* 代扣申请扣款
*/
PAP_PAY_APPLY("/pay/pappayapply"),
/**
* 代扣申请扣款(服务商模式)
*/
PARTNER_PAP_PAY_APPLY("/pay/partner/pappayapply"),
/**
* 查询代扣订单
*/
PAP_ORDER_QUERY("/pay/paporderquery"),
/**
* 查询代扣订单
*/
PARTNER_PAP_ORDER_QUERY("/pay/partner/paporderquery"),
/**
* 代扣申请解约
*/
DELETE_ENTRUST_CONTRACT("/papay/deletecontract"),
/**
* 代扣申请解约(服务商模式)
*/
PARTNER_DELETE_ENTRUST_CONTRACT("/papay/partner/deletecontract"),
/**
* 刷脸获取调用凭证
*/
GET_AUTH_INFO("/face/get_wxpayface_authinfo"),
/**
* 刷脸支付
*/
FACE_PAY("/pay/facepay"),
/**
* 查询刷脸支付订单
*/
FACE_PAY_QUERY("/pay/facepayqueryy"),
/**
* 撤销刷脸支付订单
*/
FACE_PAY_REVERSE("/secapi/pay/facepayreverse"),
/**
* 小微商户申请入驻
*/
MICRO_SUBMIT("/applyment/micro/submit"),
/**
* 查询申请状态
*/
GET_MICRO_SUBMIT_STATE("/applyment/micro/getstate"),
/**
* 提交升级申请
*/
MICRO_SUBMIT_UPGRADE("/applyment/micro/submitupgrade"),
/**
* 查询升级申请单状态
*/
GET_MICRO_UPGRADE_STATE("/applyment/micro/getupgradestate"),
/**
* 查询提现状态
*/
QUERY_AUTO_WITH_DRAW_BY_DATE("/fund/queryautowithdrawbydate"),
/**
* 修改结算银行卡
*/
MICRO_MODIFY_ARCHIVES("/applyment/micro/modifyarchives"),
/**
* 重新发起提现
*/
RE_AUTO_WITH_DRAW_BY_DATE("/fund/reautowithdrawbydate"),
/**
* 修改联系信息
*/
MICRO_MODIFY_CONTACT_INFO("/applyment/micro/modifycontactinfo"),
/**
* 小微商户关注功能配置
*/
ADD_RECOMMEND_CONF("/secapi/mkt/addrecommendconf"),
/**
* 小微商户开发配置新增支付目录
*/
ADD_SUB_DEV_CONFIG("/secapi/mch/addsubdevconfig"),
/**
* 小微商户开发配置查询
*/
QUERY_SUB_DEV_CONFIG("/secapi/mch/querysubdevconfig"),
/**
* 小微商户图片上传
*/
MCH_UPLOAD_MEDIA("/secapi/mch/uploadmedia"),
/**
* 获取平台证书列表
*/
GET_CERTIFICATES("/v3/certificates"),
/**
* 营销专用-图片上传
*/
MARKETING_UPLOAD_MEDIA("/v3/marketing/favor/media/image-upload"),
/**
* 通用接口-图片上传
*/
MERCHANT_UPLOAD_MEDIA("/v3/merchant/media/upload"),
/**
* 通用接口-视频上传
*/
MERCHANT_VIDEO_UPLOAD("/v3/merchant/media/video_upload"),
/**
* 创建/查询支付分订单
*/
PAY_SCORE_SERVICE_ORDER("/v3/payscore/serviceorder"),
/**
* 取消支付分订单
*/
PAY_SCORE_SERVICE_ORDER_CANCEL("/v3/payscore/serviceorder/%s/cancel"),
/**
* 修改支付分订单金额
*/
PAY_SCORE_SERVICE_ORDER_MODIFY("/v3/payscore/serviceorder/%s/modify"),
/**
* 完结支付分订单
*/
PAY_SCORE_SERVICE_ORDER_COMPLETE("/v3/payscore/serviceorder/%s/complete"),
/**
* 支付分订单收款
*/
PAY_SCORE_SERVICE_ORDER_PAY("/v3/payscore/serviceorder/%s/pay"),
/**
* 同步服务订单信息
*/
PAY_SCORE_SERVICE_ORDER_SYNC("/v3/payscore/serviceorder/%s/sync"),
/**
* 查询用户支付分开启状态
*/
PAY_SCORE_USER_SERVICE_STATE("/v3/payscore/user-service-state"),
/**
* 商户解除用户授权关系
*/
PAY_SCORE_PERMISSIONS_TERMINATE("/payscore/users/%s/permissions/%s/terminate"),
/**
* 商户预授权
*/
PAY_SCORE_PERMISSIONS("/v3/payscore/permissions"),
/**
* 查询与用户授权记录(授权协议号)
*/
PAY_SCORE_PERMISSIONS_AUTHORIZATION_CODE("/v3/payscore/permissions/authorization-code/%s"),
/**
* 解除用户授权关系(授权协议号)
*/
PAY_SCORE_PERMISSIONS_AUTHORIZATION_CODE_TERMINATE("/v3/payscore/permissions/authorization-code/%s/terminate"),
/**
* 查询与用户授权记录(openid)
*/
PAY_SCORE_PERMISSIONS_OPENID("/v3/payscore/permissions/openid/%s"),
/**
* 解除用户授权关系(openid)
*/
PAY_SCORE_PERMISSIONS_OPENID_TERMINATE("/v3/payscore/permissions/openid/%s/terminate"),
/**
* 特约商户进件-提交申请单
*/
APPLY_4_SUB("/v3/applyment4sub/applyment/"),
/**
* 特约商户进件-通过业务申请编号查询申请状态
*/
GET_APPLY_STATE("/v3/applyment4sub/applyment/business_code/%s"),
/**
* 特约商户进件-通过申请单号查询申请状态
*/
GET_APPLY_STATE_BY_ID("/v3/applyment4sub/applyment/applyment_id/%s"),
/**
* 特约商户进件-修改结算帐号
*/
MODIFY_SETTLEMENT("/v3/apply4sub/sub_merchants/%s/modify-settlement"),
/**
* 特约商户进件-查询结算账户
*/
GET_SETTLEMENT("/v3/apply4sub/sub_merchants/%s/settlement"),
/**
* 商户开户意愿确认-提交申请单 OR 查询申请单审核结果
*/
MER_OPEN_APPLY_SUBMIT_OR_RESULT("/v3/apply4subject/applyment"),
/**
* 商户开户意愿确认-撤销申请单
*/
MER_OPEN_APPLY_CANCEL("/v3/apply4subject/applyment/%s/cancel"),
/**
* 商户开户意愿确认-获取商户开户意愿确认状态
*/
GET_MER_OPEN_APPLY_STATE("/v3/apply4subject/applyment/merchants/%s/state"),
/**
* 商业支付投诉-查询投诉信息
*/
MERCHANT_SERVICE_COMPLAINTS("/v3/merchant-service/complaints"),
/**
* 商业支付投诉-创建/查询/更新/删除投诉通知回调
*/
MERCHANT_SERVICE_COMPLAINTS_NOTIFICATIONS("/v3/merchant-service/complaint-notifications"),
/**
* 代金券-创建代金券批次
*/
CREATE_COUPON_STOCKS("/v3/marketing/favor/coupon-stocks"),
/**
* 代金券-激活代金券批次
*/
START_COUPON_STOCKS("/v3/marketing/favor/stocks/%s/start"),
/**
* 代金券-发放代金券
*/
COUPON_SEND("/v3/marketing/favor/users/%s/coupons"),
/**
* 代金券-暂停代金券批次
*/
PAUSE_COUPON_STOCKS("/v3/marketing/favor/stocks/%s/pause"),
/**
* 代金券-重启代金券批次
*/
RESTART_COUPON_STOCKS("/v3/marketing/favor/stocks/%s/restart"),
/**
* 代金券-条件查询批次列表
*/
QUERY_COUPON_STOCKS("/v3/marketing/favor/stocks"),
/**
* 代金券-查询批次详情
*/
QUERY_COUPON_STOCKS_INFO("/v3/marketing/favor/stocks/%s"),
/**
* 代金券-查询代金券详情
*/
QUERY_COUPON_INFO("/v3/marketing/favor/users/%s/coupons/%s"),
/**
* 代金券-查询代金券可用商户
*/
QUERY_COUPON_MERCHANTS("/v3/marketing/favor/stocks/%s/merchants"),
/**
* 代金券-查询代金券可用单品
*/
QUERY_COUPON_ITEMS("/v3/marketing/favor/stocks/%s/items"),
/**
* 代金券-根据商户号查用户的券
*/
QUERY_USER_COUPON("/v3/marketing/favor/users/%s/coupons"),
/**
* 代金券-下载批次核销明细
*/
COUPON_STOCKS_USER_FLOW_DOWNLOAD("/v3/marketing/favor/stocks/%s/use-flow"),
/**
* 代金券-下载批次退款明细
*/
COUPON_STOCKS_REFUND_FLOW_DOWNLOAD("/v3/marketing/favor/stocks/%s/refund-flow"),
/**
* 代金券-设置消息通知地址
*/
SETTING_COUPON_CALLBACKS("/v3/marketing/favor/callbacks"),
/**
* 商家券-创建商家券
*/
CREATE_BUSINESS_COUPON("/v3/marketing/busifavor/stocks"),
/**
* 发放消费卡
*/
SEND_BUSINESS_COUPON("/v3/marketing/busifavor/coupons/%s/send"),
/**
* H5 发券
*/
H5_SEND_COUPON("/busifavor/getcouponinfo"),
/**
* 商家券-查询商家券批次详情
*/
QUERY_BUSINESS_COUPON_STOCKS_INFO("/v3/marketing/busifavor/stocks/%s"),
/**
* 商家券-查询商家券批次详情
*/
USE_BUSINESS_COUPON("/v3/marketing/busifavor/coupons/use"),
/**
* 商家券-根据过滤条件查询用户券
*/
QUERY_BUSINESS_USER_COUPON("/v3/marketing/busifavor/users/%s/coupons"),
/**
* 商家券-查询用户单张券详情
*/
QUERY_BUSINESS_USER_COUPON_INFO("/v3/marketing/busifavor/users/%s/coupons/%s/appids/%s"),
/**
* 商家券-上传预存code
*/
BUSINESS_COUPON_UPLOAD_CODE("/v3/marketing/busifavor/stocks/%/couponcodes"),
/**
* 商家券-设置/查询商家券事件通知地址
*/
BUSINESS_COUPON_CALLBACKS("/v3/marketing/busifavor/callbacks"),
/**
* 关联订单信息
*/
BUSINESS_COUPON_ASSOCIATE("/v3/marketing/busifavor/coupons/associate"),
/**
* 取消关联订单信息
*/
BUSINESS_COUPON_DISASSOCIATE("/v3/marketing/busifavor/coupons/disassociate"),
/**
* 支付有礼-创建全场满额送活动
*/
PAY_GIFT_ACTIVITY("/v3/marketing/paygiftactivity/unique-threshold-activity"),
/**
* 支付有礼-获取支付有礼活动列表
*/
PAY_GIFT_ACTIVITY_GET("/v3/marketing/paygiftactivity/activities"),
/**
* 支付有礼-查询活动详情接口
*/
PAY_GIFT_ACTIVITY_INFO("/v3/marketing/paygiftactivity/activities/%s"),
/**
* 支付有礼-查询活动发券商户号
*/
PAY_GIFT_ACTIVITY_QUERY_MER("/v3/marketing/paygiftactivity/activities/%s/merchants"),
/**
* 支付有礼-查询活动指定商品列表
*/
PAY_GIFT_ACTIVITY_QUERY_GOODS("/v3/marketing/paygiftactivity/activities/%s/goods"),
/**
* 支付有礼-终止活动
*/
PAY_GIFT_ACTIVITY_TERMINATE("/v3/marketing/paygiftactivity/activities/%s/terminate"),
/**
* 支付有礼-新增活动发券商户号
*/
PAY_GIFT_ACTIVITY_ADD_MERCHANTS("/v3/marketing/paygiftactivity/activities/%s/merchants/add"),
/**
* 支付有礼-删除活动发券商户号
*/
PAY_GIFT_ACTIVITY_DELETE_MERCHANTS("/v3/marketing/paygiftactivity/activities/%s/merchants/delete"),
/**
* 点金计划-点金计划管理
*/
CHANGE_GOLD_PLAN_STATUS("/v3/goldplan/merchants/changegoldplanstatus"),
/**
* 点金计划-商家小票管理
*/
CHANGE_CUSTOM_PAGE_STATUS("/v3/goldplan/merchants/changecustompagestatus"),
/**
* 点金计划-同业过滤标签管理
*/
SET_ADVERTISING_INDUSTRY_FILTER("/v3/goldplan/merchants/set-advertising-industry-filter"),
/**
* 开通广告展示
*/
GOLD_PLAN_OPEN_ADVERTISING_SHOW("/v3/goldplan/merchants/open-advertising-show"),
/**
* 关闭广告展示
*/
GOLD_PLAN_CLOSE_ADVERTISING_SHOW("/v3/goldplan/merchants/close-advertising-show"),
/**
* 电商收付通-二级商户进件
*/
E_COMMERCE_APPLY("/v3/ecommerce/applyments/"),
/**
* 电商收付通-查询进件申请状态
*/
E_COMMERCE_APPLY_STATE("/v3/ecommerce/applyments/%s"),
/**
* 电商收付通-通过业务申请编号查询申请状态
*/
E_COMMERCE_APPLY_STATE_BY_NO("/v3/ecommerce/applyments/out-request-no/%s"),
/**
* 合单下单-APP支付
*/
COMBINE_TRANSACTIONS_APP("/v3/combine-transactions/app"),
/**
* 合单下单-JS支付
*/
COMBINE_TRANSACTIONS_JS("/v3/combine-transactions/jsapi"),
/**
* 合单下单-H5支付
*/
COMBINE_TRANSACTIONS_H5("/v3/combine-transactions/h5"),
/**
* 合单下单-Native支付
*/
COMBINE_TRANSACTIONS_NATIVE("/v3/combine-transactions/native"),
/**
* 合单下单-合单查询订单
*/
COMBINE_TRANSACTIONS_QUERY("/v3/combine-transactions/out-trade-no/%s"),
/**
* 合单下单-合单关闭订单
*/
COMBINE_TRANSACTIONS_CLOSE("/v3/combine-transactions/out-trade-no/%s/close"),
/**
* 电商收付通-补差接口-请求补差
*/
CREATE_SUBSIDIES("/v3/ecommerce/subsidies/create"),
/**
* 电商收付通-补差接口-请求补差回退
*/
RETURN_SUBSIDIES("/v3/ecommerce/subsidies/return"),
/**
* 电商收付通-补差接口-取消补差
*/
CANCEL_SUBSIDIES("/v3/ecommerce/subsidies/cancel"),
/**
* 电商收付通-分账接口-请求分账/查询分账结果
*/
PROFIT_SHARING_ORDERS("/v3/ecommerce/profitsharing/orders"),
/**
* 电商收付通-分账接口-查询分账回退结果
*/
PROFIT_SHARING_RETURN_ORDERS("/v3/ecommerce/profitsharing/returnorders"),
/**
* 电商收付通-分账接口-完结分账
*/
PROFIT_SHARING_FINISH_ORDER("/v3/ecommerce/profitsharing/finish-order"),
/**
* 添加分账接收方
*/
PROFIT_SHARING_RECEIVERS_ADD("/v3/ecommerce/profitsharing/receivers/add"),
/**
* 删除分账接收方
*/
PROFIT_SHARING_RECEIVERS_DELETE("/v3/ecommerce/profitsharing/receivers/delete"),
/**
* 电商收付通-退款接口-退款申请
*/
E_COMMERCE_REFUNDS("/v3/ecommerce/refunds/apply"),
/**
* 电商收付通-退款接口-通过微信支付退款单号查询退款
*/
QUERY_REFUND("/v3/ecommerce/refunds/id/%s"),
/**
* 电商收付通-退款接口-通过商户退款单号查询退款
*/
QUERY_REFUNDS_BY_REFUND_NO("/v3/ecommerce/refunds/out-refund-no/%s"),
/**
* 电商收付通-余额查询接口
*/
QUERY_BALANCE("/v3/ecommerce/fund/balance/%s"),
/**
* 查询二级商户账户日终余额
*/
QUERY_END_DAY_BALANCE("/v3/ecommerce/fund/enddaybalance/%s"),
/**
* 查询电商平台账户实时余额
*/
QUERY_MERCHANT_BALANCE("/v3/merchant/fund/balance/%s"),
/**
* 查询电商平台账户日终余额
*/
QUERY_MERCHANT_END_DAY_BALANCE("/v3/merchant/fund/dayendbalance/%s"),
/**
* 电商收付通-提现接口-账户余额提现
*/
WITHDRAW("/v3/ecommerce/fund/withdraw"),
/**
* 电商收付通-提现接口-提现状态查询
*/
QUERY_WITHDRAW("/v3/ecommerce/fund/withdraw/%s"),
/**
* 电商收付通-提现接口-商户提现单号查询
*/
QUERY_WITHDRAW_BY_OUT_REQUEST_NO("/v3/ecommerce/fund/withdraw/out-request-no/%s"),
/**
* 电商收付通-提现接口-电商平台提现
*/
MERCHANT_WITHDRAW("/v3/merchant/fund/withdraw"),
/**
* 电商收付通-提现接口-微信支付提现单号查询
*/
QUERY_MERCHANT_WITHDRAW("/v3/ecommerce/fund/withdraw/%s"),
/**
* 电商收付通-提现接口-商户提现单号查询
*/
QUERY_MERCHANT_WITHDRAW_BY_OUT_REQUEST_NO("/v3/merchant/fund/withdraw/out-request-no/%s"),
/**
* 电商收付通-提现接口-按日下载提现异常文件
*/
WITHDRAW_BILL("/v3/merchant/fund/withdraw/bill-type/%s"),
/**
* 申请二级商户资金账单API
*/
E_COMMERCE_FUND_FLOW_BILL("/v3/ecommerce/bill/fundflowbill"),
/**
* 申请交易账单
*/
TRADE_BILL("/v3/bill/tradebill"),
/**
* 申请资金账单
*/
FUND_FLOW_BILL("/v3/bill/fundflowbill"),
/**
* 下载账单
*/
BILL_DOWNLOAD("/v3/billdownload/file"),
/**
* 银行特约商户违规信息查询
*/
GET_VIOLATION("/risk/getviolation"),
/**
* 事前-风险商户核查接口
*/
QUERY_MCH_RISK("/mchrisk/querymchrisk"),
/**
* 事后-风险商户处理结果同步接口
*/
SYNC_MCH_RISK_RESULT("/mchrisk/syncmchriskresult"),
/**
* 间联模式查询商户审核状态开放接口
*/
BANK_QUERY_MCH_AUDIT_INFO("/mchrisk/bankquerymchauditinfo"),
/**
* 渠道商查询商户审核信息
*/
CHANNEL_QUERY_MCH_AUDIT_INFO("/mchrisk/channelquerymchauditinfo"),
/**
* 设置风险通知回调链接
*/
SET_MCH_RISK_CALLBACK("/mchrisk/setmchriskcallback"),
/**
* 向员工付款
*/
PAY_WWS_TRANS_2_POCKET("/mmpaymkttransfers/promotion/paywwsptrans2pocket"),
/**
* 查询向员工付款记录
*/
QUERY_WWS_TRANS_2_POCKET("/mmpaymkttransfers/promotion/querywwsptrans2pocket"),
/**
* 发放企业红包
*/
SEND_WORK_WX_RED_PACK("/mmpaymkttransfers/sendworkwxredpack"),
/**
* 查询企业红包记录
*/
QUERY_WORK_WX_RED_PACK("/mmpaymkttransfers/queryworkwxredpack"),
/**
* 查询/更新先享卡订单
*/
DISCOUNT_CARD_ORDER("/v3/discount-card/orders/%s"),
/**
* 查询先享卡订单
*/
DISCOUNT_CARD_ORDER_TRADE_NO("/v3/discount-card/orders/out-trade-no/%s"),
/**
* 服务人员注册
*/
SMART_GUIDE_GUIDES("/v3/smartguide/guides"),
/**
* 服务人员分配
*/
SMART_GUIDE_GUIDES_ASSIGN("/v3/smartguide/guides/%s/assign"),
/**
* 服务人员信息更新
*/
SMART_GUIDE_GUIDES_UPDATE("/v3/smartguide/guides/%s"),
/**
* 报关接口-订单附加信息提交接口
*/
CUSTOM_DECLARE_ORDER("/cgi-bin/mch/customs/customdeclareorder"),
/**
* 报关接口-订单附加信息查询接口
*/
CUSTOM_DECLARE_QUERY("/cgi-bin/mch/customs/customdeclarequery"),
/**
* 报关接口-订单附加信息重推接口
*/
CUSTOM_DECLARE_RE_DECLARE("/cgi-bin/mch/newcustoms/customdeclareredeclare"),
/**
* APP 下单 API
*/
APP_PAY("/v3/pay/transactions/app"),
PARTNER_APP_PAY("/v3/pay/partner/transactions/app"),
/**
* JS API 下单 API
*/
JS_API_PAY("/v3/pay/transactions/jsapi"),
PARTNER_JS_API_PAY("/v3/pay/partner/transactions/jsapi"),
/**
* Native 下单 API
*/
NATIVE_PAY("/v3/pay/transactions/native"),
PARTNER_NATIVE_PAY("/v3/pay/partner/transactions/native"),
/**
* H5 下单 API
*/
H5_PAY("/v3/pay/transactions/h5"),
PARTNER_H5_PAY("/v3/pay/partner/transactions/h5"),
/**
* 微信支付订单号查询
*/
ORDER_QUERY_BY_ID("/v3/pay/transactions/id/%s"),
PARTNER_ORDER_QUERY_BY_ID("/v3/pay/partner/transactions/id/%s"),
/**
* 商户订单号查询
*/
ORDER_QUERY_BY_NO("/v3/pay/transactions/out-trade-no/%s"),
PARTNER_ORDER_QUERY_BY_NO("/v3/pay/partner/transactions/out-trade-no/%s"),
/**
* 关闭订单
*/
CLOSE_ORDER_BY_NO("/v3/pay/transactions/out-trade-no/%s/close"),
PARTNER_CLOSE_ORDER_BY_NO("/v3/pay/partner/transactions/out-trade-no/%s/close"),
/**
* 申请退款
*/
DOMESTIC_REFUNDS("/v3/refund/domestic/refunds"),
/**
* 查询单笔退款
*/
DOMESTIC_REFUNDS_QUERY("/v3/refund/domestic/refunds/%s"),
/**
* 委托营销-建立合作关系
*/
PARTNERSHIPS_BUILD("/v3/marketing/partnerships/build"),
/**
* 委托营销-终止合作关系
*/
PARTNERSHIPS_TERMINATE("/v3/marketing/partnerships/terminate"),
/**
* 智慧商圈-商圈积分同步
*/
BUSINESS_CIRCLE_POINTS_NOTIFY("/v3/businesscircle/points/notify"),
/**
* 连锁品牌-分账-查询分账
*/
BRAND_PROFIT_SHARING_ORDERS("/v3/brand/profitsharing/orders"),
/**
* 连锁品牌-分账回退-查询分账回退
*/
BRAND_PROFIT_SHARING_RETURN_ORDERS("/v3/brand/profitsharing/returnorders"),
/**
* 连锁品牌-完结分账
*/
BRAND_PROFIT_SHARING_FINISH_ORDER("/v3/brand/profitsharing/finish-order"),
/**
* 查询订单剩余待分金额
*/
BRAND_PROFIT_SHARING_QUERY("/v3/brand/profitsharing/orders/%s/amounts"),
/**
* 查询最大分账比例
*/
BRAND_PROFIT_SHARING_CONFIGS("/v3/brand/profitsharing/brand-configs/%s"),
/**
* 连锁品牌-添加分账接收方
*/
BRAND_PROFIT_SHARING_RECEIVERS_ADD("/v3/brand/profitsharing/receivers/add"),
/**
* 连锁品牌-删除分账接收方
*/
BRAND_PROFIT_SHARING_RECEIVERS_DELETE("/v3/brand/profitsharing/receivers/delete"),
/**
* 预受理领卡
*/
DISCOUNT_CARD("/v3/discount-card/cards"),
/**
* 增加用户记录
*/
DISCOUNT_CARD_ADD_USER_RECORDS("/v3/discount-card/cards/%s/add-user-records"),
/**
* 查询先享卡订单
*/
DISCOUNT_CARD_GET("/v3/discount-card/cards/%s"),
/**
* 查询车牌服务开通信息
*/
VEHICLE_PARKING_SERVICES_FIND("/v3/vehicle/parking/services/find"),
/**
* 创建停车入场
*/
VEHICLE_PARKING("/v3/vehicle/parking/parkings"),
/**
* 扣费受理
*/
VEHICLE_TRANSACTIONS_PARKING("/v3/vehicle/transactions/parking"),
/**
* 查询订单
*/
VEHICLE_TRANSACTIONS_OUT_TRADE_NO("/v3/vehicle/transactions/out-trade-no/%s"),
/**
* 发起批量转账
*/
PARTNER_TRANSFER_BATCHES("/v3/partner-transfer/batches"),
/**
* 微信支付批次单号查询批次单
*/
PARTNER_TRANSFER_BATCHES_QUERY_BY_BATCH_ID("/v3/partner-transfer/batches/batch-id/%s"),
/**
* 微信支付明细单号查询明细单
*/
PARTNER_TRANSFER_BATCHES_QUERY_BY_DETAIL_ID("/v3/partner-transfer/batches/batch-id/%s/details/detail-id/%s"),
/**
* 商家批次单号查询批次单
*/
PARTNER_TRANSFER_BATCHES_QUERY_BY_OUT_BATCH_NO("/v3/partner-transfer/batches/out-batch-no/%s"),
/**
* 商家明细单号查询明细单
*/
PARTNER_TRANSFER_BATCHES_QUERY_DETAIL_BY_OUT_BATCH_NO("https://api.mch.weixin.qq.com/v3/partner-transfer/batches/out-batch-no/%s/details/out-detail-no/%s"),
/**
* 转账电子回单申请受理
*/
TRANSFER_BILL_RECEIPT("/v3/transfer/bill-receipt"),
/**
* 查询转账电子回单
*/
TRANSFER_BILL_RECEIPT_QUERY("/v3/transfer/bill-receipt/%s"),
/**
* 转账明细电子回单受理/查询转账明细电子回单受理结果
*/
TRANSFER_BILL_RECEIPT_DETAIL("/v3/transfer-detail/electronic-receipts"),
/**
* 特约商户银行来账查询
*/
PARTNER_INCOME_RECORDS("/v3/merchantfund/partner/income-records"),
/**
* 服务商银行来账查询
*/
MERCHANT_INCOME_RECORDS("/v3/merchantfund/merchant/income-records"),
/**
* 请求分账
*/
V3_PROFIT_SHARING_ORDERS("/v3/profitsharing/orders"),
/**
* 查询分账结果
*/
V3_PROFIT_SHARING_ORDERS_QUERY("/v3/profitsharing/orders/%s"),
/**
* 请求分账回退
*/
V3_PROFIT_SHARING_RETURN_ORDERS("/v3/profitsharing/return-orders"),
/**
* 查询分账回退结果
*/
V3_PROFIT_SHARING_RETURN_ORDERS_QUERY("/v3/profitsharing/return-orders/%s"),
/**
* 解冻剩余资金
*/
PROFIT_SHARING_UNFREEZE("/v3/profitsharing/orders/unfreeze"),
/**
* 查询剩余待分金额
*/
PROFIT_SHARING_UNFREEZE_QUERY("/v3/profitsharing/transactions/%s/amounts"),
/**
* 查询最大分账比例
*/
PROFIT_SHARING_MERCHANT_CONFIGS("/v3/profitsharing/merchant-configs/%s"),
/**
* 添加分账接收方
*/
V3_PROFIT_SHARING_RECEIVERS_ADD("/v3/profitsharing/receivers/add"),
/**
* 删除分账接收方
*/
V3_PROFIT_SHARING_RECEIVERS_DELETE("/v3/profitsharing/receivers/delete"),
/**
* 申请分账账单
*/
PROFIT_SHARING_BILLS("/v3/profitsharing/bills"),
/**
* 查询投诉单列表
*/
MERCHANT_SERVICE_COMPLAINTS_V2("/v3/merchant-service/complaints-v2"),
/**
* 查询投诉单详情
*/
MERCHANT_SERVICE_COMPLAINTS_DETAIL("/v3/merchant-service/complaints-v2/%s"),
/**
* 查询投诉协商历史
*/
MERCHANT_SERVICE_COMPLAINTS_NEGOTIATION_HISTORY("/v3/merchant-service/complaints-v2/%s/negotiation-historys"),
/**
* 提交回复
*/
MERCHANT_SERVICE_COMPLAINTS_RESPONSE("/v3/merchant-service/complaints-v2/%s/response"),
/**
* 商户上传反馈图片
*/
MERCHANT_SERVICE_IMAGES_UPLOAD("/v3/merchant-service/images/upload"),
/**
* 反馈处理完成
*/
MERCHANT_SERVICE_COMPLAINTS_COMPLETE("/v3/merchant-service/complaints-v2/%s/complete"),
;
/**
* 类型
*/
private final String type;
Uri(String type) {
this.type = type;
}
public String getType() {
return type;
}
@Override
public String toString() {
return type;
}
}
package com.smart.hospital.common.pay.exception;
/**
* 没有适用的支付处理器
*/
public class NoApplyHandlerException extends RuntimeException {
public NoApplyHandlerException() {
}
public NoApplyHandlerException(String message) {
super(message);
}
public NoApplyHandlerException(String message, Throwable cause) {
super(message, cause);
}
public NoApplyHandlerException(Throwable cause) {
super(cause);
}
}
package com.smart.hospital.common.pay.exception;
public class PayException extends RuntimeException {
public PayException() {
}
public PayException(String message) {
super(message);
}
public PayException(String message, Throwable cause) {
super(message, cause);
}
}
package com.smart.hospital.common.pay.factory;
import com.smart.hospital.common.pay.source.PayAttribute;
import com.smart.hospital.common.pay.source.PayAttributeSource;
import com.smart.hospital.common.pay.strategy.PayStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.UsesJava7;
import java.io.Serializable;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@Slf4j
public class PayClientProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = 1L;
/**
* 代理的接口类
*/
private final Class<T> clientInterface;
/**
* 注解解析器
*/
private final PayAttributeSource payAttributeSource;
/**
* 支付策略
*/
private final PayStrategy payStrategy;
public PayClientProxy(Class<T> clientInterface, PayAttributeSource payAttributeSource, PayStrategy payStrategy) {
this.clientInterface = clientInterface;
this.payAttributeSource = payAttributeSource;
this.payStrategy = payStrategy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
// 解析注解信息
PayAttribute attr = parseAnnotationMetaInfo(method);
// 调用支付
return getPayStrategy().doExecute(attr, clientInterface, method, args);
}
@UsesJava7
private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
throws Throwable {
final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
.getDeclaredConstructor(Class.class, int.class);
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
final Class<?> declaringClass = method.getDeclaringClass();
return constructor
.newInstance(declaringClass,
MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
| MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
.unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
}
/**
* Backport of java.lang.reflect.Method#isDefault()
*/
private boolean isDefaultMethod(Method method) {
return (method.getModifiers()
& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
&& method.getDeclaringClass().isInterface();
}
private PayAttribute parseAnnotationMetaInfo(Method method) {
return getPayAttributeSource().getPayAttribute(method, clientInterface);
}
public PayAttributeSource getPayAttributeSource() {
return payAttributeSource;
}
public PayStrategy getPayStrategy() {
return payStrategy;
}
}
package com.smart.hospital.common.pay.factory;
import org.springframework.beans.factory.FactoryBean;
public class PayFactoryBean<T> extends PayFactoryBeanSupport implements FactoryBean<T> {
private Class<T> clientInterface;
public PayFactoryBean() {
}
public PayFactoryBean(Class<T> clientInterface) {
this.clientInterface = clientInterface;
}
@Override
public T getObject() throws Exception {
return registerClient();
}
@Override
public Class<?> getObjectType() {
return this.clientInterface;
}
@Override
public boolean isSingleton() {
return true;
}
private T registerClient() {
PayProxyFactory<T> payProxyFactory = new PayProxyFactory<>(this.clientInterface);
return payProxyFactory.newInstance(getPayAttributeSource(), getPayStrategy());
}
}
package com.smart.hospital.common.pay.factory;
import com.smart.hospital.common.pay.source.PayAttributeSource;
import com.smart.hospital.common.pay.strategy.PayStrategy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import static org.springframework.util.Assert.notNull;
public abstract class PayFactoryBeanSupport implements InitializingBean, ApplicationContextAware {
ApplicationContext applicationContext;
/**
* 资源解析器
*/
private PayAttributeSource payAttributeSource;
/**
* 支付策略
*/
private PayStrategy payStrategy;
public PayAttributeSource getPayAttributeSource() {
return payAttributeSource;
}
public void setPayAttributeSource(PayAttributeSource payAttributeSource) {
this.payAttributeSource = payAttributeSource;
}
public PayStrategy getPayStrategy() {
return payStrategy;
}
public void setPayStrategy(PayStrategy payStrategy) {
this.payStrategy = payStrategy;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
// notNull(this.payAttributeSource, "Property 'payAttributeSource' are required");
if (this.payAttributeSource == null) {
this.payAttributeSource = applicationContext.getBean(PayAttributeSource.class);
notNull(this.payAttributeSource, "Property 'payAttributeSource' are required");
}
if (this.payStrategy == null) {
this.payStrategy = applicationContext.getBean(PayStrategy.class);
}
}
}
package com.smart.hospital.common.pay.factory;
import com.smart.hospital.common.pay.source.PayAttributeSource;
import com.smart.hospital.common.pay.strategy.PayStrategy;
import java.lang.reflect.Proxy;
public class PayProxyFactory<T> {
private final Class<T> clientInterface;
public PayProxyFactory(Class<T> clientInterface) {
this.clientInterface = clientInterface;
}
@SuppressWarnings("unchecked")
protected T newInstance(PayClientProxy<T> payClientProxy) {
return (T) Proxy.newProxyInstance(clientInterface.getClassLoader(), new Class[]{clientInterface}, payClientProxy);
}
protected T newInstance(PayAttributeSource payAttributeSource, PayStrategy payStrategy) {
PayClientProxy<T> payClientProxy = new PayClientProxy<>(clientInterface, payAttributeSource,payStrategy);
return newInstance(payClientProxy);
}
}
package com.smart.hospital.common.pay.model;
import com.alipay.api.AlipayObject;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 阿里下单模型
*/
@Data
@Accessors(chain = true)
public class AliUnifiedOrderModel<T extends AlipayObject> {
/**
* 支付宝官方下单模型
*/
private T alipayObject;
/**
* 交易订单号
*/
private String outTradeNo;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class Amount {
/**
* 总金额
*/
private int total;
/**
* 货币类型
*/
private String currency;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
@Data
@Accessors(chain = true)
public class Detail {
/**
* 订单原价
*/
private int cost_price;
/**
* 商品小票ID
*/
private String invoice_id;
/**
* 单品列表
*/
private List<GoodsDetail> goods_detail;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class GoodsDetail {
/**
* 商户侧商品编码
*/
private String merchant_goods_id;
/**
* 微信侧商品编码
*/
private String wechatpay_goods_id;
/**
* 商品名称
*/
private String goods_name;
/**
* 商品数量
*/
private int quantity;
/**
* 商品单价
*/
private int unit_price;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class H5Info {
/**
* 场景类型
*/
private String type;
/**
* 应用名称
*/
private String app_name;
/**
* 网站URL
*/
private String app_url;
/**
* iOS 平台 BundleID
*/
private String bundle_id;
/**
* Android 平台 PackageName
*/
private String package_name;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class Payer {
/**
* 用户标识
*/
private String openid;
/**
* 用户服务标识
*/
private String sp_openid;
/**
* 用户子标识
*/
private String sub_openid;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class SceneInfo {
/**
* 用户终端IP
*/
private String payer_client_ip;
/**
* 商户端设备号
*/
private String device_id;
/**
* 商户门店信息
*/
private StoreInfo store_info;
/**
* H5 场景信息
*/
private H5Info h5_info;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class SettleInfo {
/**
* 是否指定分账
*/
private boolean profit_sharing;
/**
* 补差金额
*/
private int subsidy_amount;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class StoreInfo {
/**
* 门店编号
*/
private String id;
/**
* 门店名称
*/
private String name;
/**
* 地区编码
*/
private String area_code;
/**
* 详细地址
*/
private String address;
}
package com.smart.hospital.common.pay.model;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.CaseInsensitiveMap;
import cn.hutool.core.util.StrUtil;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
public class WxHttpResponse implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 响应体
*/
private String body;
/**
* 响应状态
*/
private int status;
/**
* 响应头
*/
private Map<String, List<String>> headers;
public WxHttpResponse() {
}
public WxHttpResponse(String body, int status, Map<String, List<String>> headers) {
this.body = body;
this.status = status;
this.headers = headers;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public Map<String, List<String>> getHeaders() {
return headers;
}
public void setHeaders(Map<String, List<String>> headers) {
this.headers = headers;
}
public String getHeader(String name) {
List<String> values = this.headerList(name);
return CollectionUtil.isEmpty(values) ? null : values.get(0);
}
private List<String> headerList(String name) {
if (StrUtil.isBlank(name)) {
return null;
} else {
CaseInsensitiveMap<String, List<String>> headersIgnoreCase = new CaseInsensitiveMap<>(getHeaders());
return headersIgnoreCase.get(name.trim());
}
}
@Override
public String toString() {
return "WxHttpResponse{" +
"body='" + body + '\'' +
", status=" + status +
", headers=" + headers +
'}';
}
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* V3 微信申请退款-金额信息
*/
@Data
@Accessors(chain = true)
public class WxRefundAmount {
/**
* 总金额
*/
private int total;
/**
* 货币类型
*/
private String currency;
/**
* 退款金额
*/
private int refund;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 微信退款详情
*/
@Data
@Accessors(chain = true)
public class WxRefundGoodsDetail {
/**
* 商户侧商品编码
*/
private String merchant_goods_id;
/**
* 微信侧商品编码
*/
private String wechatpay_goods_id;
/**
* 商品名称
*/
private String goods_name;
/**
* 商品单价
*/
private int unit_price;
/**
* 商品退款金额
*/
private int refund_amount;
/**
* 商品退货数量
*/
private int refund_quantity;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.List;
/**
* V3 微信申请退款 Model
* 参数说明:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_9.shtml
*/
@Data
@Accessors(chain = true)
public class WxRefundModel {
/**
* 微信支付订单号
*/
private String transaction_id;
/**
* 商户订单号
*/
private String out_trade_no;
/**
* 商户退款单号
*/
private String out_refund_no;
/**
* 退款原因
*/
private String reason;
/**
* 退款结果回调url
*/
private String notify_url;
/**
* 退款资金来源
*/
private String funds_account;
/**
* 金额信息
*/
private WxRefundAmount amount;
/**
* 退款商品
*/
private List<WxRefundGoodsDetail> goods_detail;
}
package com.smart.hospital.common.pay.model;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class WxUnifiedOrderModel {
/**
* 公众号ID
*/
private String appid;
/**
* 服务商公众号ID
*/
private String sp_appid;
/**
* 直连商户号
*/
private String mchid;
/**
* 服务商户号
*/
private String sp_mchid;
/**
* 子商户公众号ID
*/
private String sub_appid;
/**
* 子商户号
*/
private String sub_mchid;
/**
* 商品描述
*/
private String description;
/**
* 商户订单号
*/
private String out_trade_no;
/**
* 交易结束时间
*/
private String time_expire;
/**
* 附加数据
*/
private String attach;
/**
* 通知地址
*/
private String notify_url;
/**
* 订单优惠标记
*/
private String goods_tag;
/**
* 结算信息
*/
private SettleInfo settle_info;
/**
* 订单金额
*/
private Amount amount;
/**
* 支付者
*/
private Payer payer;
/**
* 优惠功能
*/
private Detail detail;
/**
* 场景信息
*/
private SceneInfo scene_info;
}
package com.smart.hospital.common.pay.parser;
import com.smart.hospital.common.pay.annotation.ALI;
import com.smart.hospital.common.pay.annotation.UNION;
import com.smart.hospital.common.pay.annotation.WX;
import com.smart.hospital.common.pay.source.PayAttribute;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
public abstract class AbstractPayAnnotationParser implements PayAnnotationParser {
/**
* 注解中的参数信息
*/
protected final String PAYMENT_METHOD_NAME = "payment";
protected final String VERSION_NAME = "version";
protected final String URL_PREFIX_NAME = "prefix";
protected final String URL_SUFFIX_NAME = "suffix";
protected final String REQUEST_METHOD_NAME = "method";
protected final String MODEL_NAME = "model";
/**
* 所有的所注解类型
*/
private static final Class<? extends Annotation>[] PAY_ANNOTATION_CLASSES = new Class[]{WX.class, ALI.class, UNION.class};
@Override
public PayAttribute parsePayAnnotation(AnnotatedElement element) {
for (Class<? extends Annotation> clazz : PAY_ANNOTATION_CLASSES) {
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(element, clazz, false, false);
if (attributes != null) {
return parsePayAnnotation(attributes);
}
}
return null;
}
protected abstract PayAttribute parsePayAnnotation(AnnotationAttributes attributes);
}
package com.smart.hospital.common.pay.parser;
import com.smart.hospital.common.pay.enums.*;
import com.smart.hospital.common.pay.source.DefaultPayAttribute;
import com.smart.hospital.common.pay.source.PayAttribute;
import org.springframework.core.annotation.AnnotationAttributes;
public class DefaultPayAnnotationParser extends AbstractPayAnnotationParser {
@Override
protected PayAttribute parsePayAnnotation(AnnotationAttributes attributes) {
// 支付方式
PaymentMethod paymentMethod = attributes.getEnum(PAYMENT_METHOD_NAME);
// 支付版本号
String version = attributes.getString(VERSION_NAME);
// 请求路径前缀
Domain prefix = null;
if (attributes.containsKey(URL_PREFIX_NAME)) {
prefix = attributes.getEnum(URL_PREFIX_NAME);
}
// 请求路径前缀
Uri suffix = null;
if (attributes.containsKey(URL_SUFFIX_NAME)) {
suffix = attributes.getEnum(URL_SUFFIX_NAME);
}
// 请求方式
RequestMethod requestMethod = attributes.getEnum(REQUEST_METHOD_NAME);
// 商户平台模式
PayModel model = attributes.getEnum(MODEL_NAME);
return new DefaultPayAttribute(paymentMethod, version, prefix, suffix, requestMethod, model);
}
}
package com.smart.hospital.common.pay.parser;
import com.smart.hospital.common.pay.source.PayAttribute;
import java.lang.reflect.AnnotatedElement;
public interface PayAnnotationParser {
/**
* 解析指定方法或则类的注解信息
*
* @param element
* @return
*/
PayAttribute parsePayAnnotation(AnnotatedElement element);
}
package com.smart.hospital.common.pay.prop;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 微信v3支付属性
*/
@ConfigurationProperties(prefix = "wx.v3")
public class WxPayV3Properties {
private String appId;
private String keyPath;
private String certPath;
private String certP12Path;
private String platformCertPath;
private String mchId;
private String apiKey;
private String apiKey3;
private String domain;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getKeyPath() {
return keyPath;
}
public void setKeyPath(String keyPath) {
this.keyPath = keyPath;
}
public String getCertPath() {
return certPath;
}
public void setCertPath(String certPath) {
this.certPath = certPath;
}
public String getCertP12Path() {
return certP12Path;
}
public void setCertP12Path(String certP12Path) {
this.certP12Path = certP12Path;
}
public String getPlatformCertPath() {
return platformCertPath;
}
public void setPlatformCertPath(String platformCertPath) {
this.platformCertPath = platformCertPath;
}
public String getMchId() {
return mchId;
}
public void setMchId(String mchId) {
this.mchId = mchId;
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getApiKey3() {
return apiKey3;
}
public void setApiKey3(String apiKey3) {
this.apiKey3 = apiKey3;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
}
package com.smart.hospital.common.pay.source;
import org.springframework.core.MethodClassKey;
import org.springframework.lang.Nullable;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public abstract class AbstractPayAttributeSource implements PayAttributeSource {
private final Map<Object, PayAttribute> attributeCache = new ConcurrentHashMap<>(16);
@Override
public PayAttribute getPayAttribute(Method method, Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// 从本地缓存中读取
Object cacheKey = getCacheKey(method, targetClass);
PayAttribute payAttribute = this.attributeCache.get(cacheKey);
if (payAttribute != null) {
return payAttribute;
}
// 解析注解信息
PayAttribute attr = computePayAttribute(method, targetClass);
if (attr != null) {
// 将信息放入本地缓存
this.attributeCache.put(cacheKey, attr);
}
return attr;
}
protected PayAttribute computePayAttribute(Method method, Class<?> targetClass) {
PayAttribute payAttribute = findPayAttribute(method);
if (payAttribute != null) {
return payAttribute;
}
return null;
}
protected abstract PayAttribute findPayAttribute(Method method);
protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
return new MethodClassKey(method, targetClass);
}
}
package com.smart.hospital.common.pay.source;
import com.smart.hospital.common.pay.parser.DefaultPayAnnotationParser;
import com.smart.hospital.common.pay.parser.PayAnnotationParser;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class AnnotationPayAttributeSource extends AbstractPayAttributeSource {
/**
* 委托的注解解析器
*/
private List<PayAnnotationParser> annotationParsers = new ArrayList<>();
public AnnotationPayAttributeSource(List<PayAnnotationParser> annotationParsers) {
if (annotationParsers == null || annotationParsers.isEmpty()) {
this.annotationParsers.add(new DefaultPayAnnotationParser());
}
this.annotationParsers = annotationParsers;
}
@Override
protected PayAttribute findPayAttribute(Method method) {
for (PayAnnotationParser parser : annotationParsers) {
PayAttribute attr = parser.parsePayAnnotation(method);
if (attr != null) {
return attr;
}
}
return null;
}
}
package com.smart.hospital.common.pay.source;
import com.smart.hospital.common.pay.enums.*;
import org.springframework.http.HttpMethod;
public class DefaultPayAttribute implements PayAttribute {
private final PaymentMethod paymentMethod;
private final PayModel payModel;
private final String version;
private final Domain prefix;
private final Uri suffix;
private final RequestMethod requestMethod;
public DefaultPayAttribute(PaymentMethod paymentMethod, String version, Domain prefix, Uri suffix, RequestMethod requestMethod, PayModel payModel) {
this.paymentMethod = paymentMethod;
this.version = version;
this.prefix = prefix;
this.suffix = suffix;
this.requestMethod = requestMethod;
this.payModel = payModel;
}
@Override
public PaymentMethod getPayment() {
return paymentMethod;
}
@Override
public String getVersion() {
return this.version;
}
@Override
public Domain getPrefix() {
return this.prefix;
}
@Override
public Uri getSuffix() {
return this.suffix;
}
@Override
public RequestMethod getRequestMethod() {
return this.requestMethod;
}
@Override
public PayModel getModel() {
return this.payModel;
}
@Override
public String toString() {
return "DefaultPayAttribute{" +
"paymentMethod=" + paymentMethod +
", payModel=" + payModel +
", version='" + version + '\'' +
", prefix=" + prefix +
", suffix=" + suffix +
", requestMethod=" + requestMethod +
'}';
}
}
package com.smart.hospital.common.pay.source;
import com.smart.hospital.common.pay.enums.*;
/**
* 支付注解属性
*/
public interface PayAttribute {
/**
* 获取支付方式
*
* @return
*/
PaymentMethod getPayment();
/**
* 商户平台模式
*
* @return
*/
PayModel getModel();
/**
* 获取支付版本号
*
* @return
*/
String getVersion();
/**
* 获取调用的url路径前缀
*
* @return
*/
Domain getPrefix();
/**
* 获取url后缀
*
* @return
*/
Uri getSuffix();
/**
* 获取调用方式(post/get)
*
* @return
*/
RequestMethod getRequestMethod();
}
package com.smart.hospital.common.pay.source;
import java.lang.reflect.Method;
/**
* 支付属性资源解析器接口
*/
public interface PayAttributeSource {
/**
* 从方法上获取注解属性信息
*
* @param method
* @param targetClass
* @return
*/
PayAttribute getPayAttribute(Method method, Class<?> targetClass);
}
package com.smart.hospital.common.pay.strategy;
import com.smart.hospital.common.pay.source.PayAttribute;
import com.smart.hospital.common.pay.strategy.builder.HandlerFactoryBuilder;
import com.smart.hospital.common.pay.strategy.factory.StrategyFactory;
import com.smart.hospital.common.pay.strategy.handler.StrategyHandler;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
@Slf4j
public abstract class AbstractPayStrategy implements PayStrategy {
private HandlerFactoryBuilder factoryBuilder;
@Override
public StrategyHandler getHandler(PayAttribute attribute) {
StrategyFactory factory = factoryBuilder.build();
return factory.canApply(attribute);
}
@Override
public Object wrap(Class<?> clientInterface, Method method, Object arg) {
return arg;
}
protected boolean check(Object arg) {
return true;
}
public HandlerFactoryBuilder getFactoryBuilder() {
return factoryBuilder;
}
public void setFactoryBuilder(HandlerFactoryBuilder factoryBuilder) {
this.factoryBuilder = factoryBuilder;
}
}
package com.smart.hospital.common.pay.strategy;
import com.smart.hospital.common.pay.source.PayAttribute;
import com.smart.hospital.common.pay.strategy.handler.StrategyHandler;
import java.lang.reflect.Method;
/**
* 支付策略
*/
public interface PayStrategy {
/**
* 获取执行策略
*
* @param attribute
* @return
*/
StrategyHandler getHandler(PayAttribute attribute);
/**
* 参数解析
*
* @return
*/
Object wrap(Class<?> clientInterface, Method method, Object arg);
/**
* 执行逻辑
*
* @param attribute
* @param clientInterface
* @param method
* @param args
* @return
*/
Object doExecute(PayAttribute attribute, Class<?> clientInterface, Method method, Object[] args);
}
package com.smart.hospital.common.pay.strategy;
import com.smart.hospital.common.pay.exception.NoApplyHandlerException;
import com.smart.hospital.common.pay.exception.PayException;
import com.smart.hospital.common.pay.source.PayAttribute;
import com.smart.hospital.common.pay.strategy.handler.StrategyHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import java.lang.reflect.Method;
import static org.springframework.util.Assert.notNull;
@Slf4j
public class PayStrategyManager extends AbstractPayStrategy implements InitializingBean {
@Override
public Object doExecute(PayAttribute attribute, Class<?> clientInterface, Method method, Object[] args) {
StrategyHandler handler = getHandler(attribute);
if (handler != null) {
if (args != null && args.length > 0) {
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
if (!check(arg)) {
throw new PayException("参数错误!");
}
args[i] = wrap(clientInterface, method, args[i]);
}
}
handler.beforeExecute(attribute, clientInterface, method, args);
Object result = null;
try {
result = handler.execute(attribute, args);
} catch (Exception e) {
// 4.异常处理
log.info("调用支付下单接口出现异常:{}", e.getLocalizedMessage());
handler.exception(attribute, clientInterface, method, args, e);
throw new PayException("支付异常 : " + e.getLocalizedMessage());
}
handler.afterExecute(attribute, clientInterface, method, args, result);
return result;
}
throw new NoApplyHandlerException("No StrategyHandler for method : " + method.getName());
}
@Override
public void afterPropertiesSet() throws Exception {
notNull(getFactoryBuilder(), "Property 'HandlerFactoryBuilder' are required");
}
}
package com.smart.hospital.common.pay.strategy;
import com.smart.hospital.common.pay.prop.WxPayV3Properties;
import com.smart.hospital.common.pay.strategy.handler.StrategyHandler;
import org.springframework.beans.factory.InitializingBean;
import java.util.List;
public class StrategyPropertiesCustomizer implements InitializingBean {
private WxPayV3Properties wxPayV3Properties;
private List<StrategyHandler> handlers;
public StrategyPropertiesCustomizer(WxPayV3Properties wxPayV3Properties, List<StrategyHandler> handlers) {
this.wxPayV3Properties = wxPayV3Properties;
this.handlers = handlers;
}
@Override
public void afterPropertiesSet() throws Exception {
if (handlers != null && !handlers.isEmpty()) {
for (StrategyHandler handler : handlers) {
handler.setProperties(wxPayV3Properties);
}
}
}
}
package com.smart.hospital.common.pay.strategy.builder;
import com.smart.hospital.common.pay.strategy.factory.StrategyFactory;
public interface HandlerFactoryBuilder {
StrategyFactory build();
}
package com.smart.hospital.common.pay.strategy.builder;
import com.smart.hospital.common.pay.strategy.factory.StrategyFactory;
import com.smart.hospital.common.pay.strategy.factory.StrategyHandlerFactory;
import com.smart.hospital.common.pay.strategy.handler.StrategyHandler;
import java.util.ArrayList;
import java.util.List;
public class PayHandlerFactoryBuilder implements HandlerFactoryBuilder {
private List<StrategyHandler> strategyHandlers = new ArrayList<>();
public PayHandlerFactoryBuilder() {
}
public PayHandlerFactoryBuilder(List<StrategyHandler> strategyHandlers) {
if (strategyHandlers != null && !strategyHandlers.isEmpty()) {
this.strategyHandlers.addAll(strategyHandlers);
}
}
@Override
public StrategyFactory build() {
return new StrategyHandlerFactory(strategyHandlers);
}
public void addStrategyHandler(StrategyHandler handler) {
strategyHandlers.add(handler);
}
public List<StrategyHandler> getStrategyHandlers() {
return strategyHandlers;
}
public void setStrategyHandlers(List<StrategyHandler> strategyHandlers) {
this.strategyHandlers = strategyHandlers;
}
}
package com.smart.hospital.common.pay.strategy.factory;
import com.smart.hospital.common.pay.source.PayAttribute;
import com.smart.hospital.common.pay.strategy.handler.StrategyHandler;
/**
* 策略工厂接口类
*/
public interface StrategyFactory {
/**
* 构建处理器
*
* @param attribute
* @return
*/
StrategyHandler canApply(PayAttribute attribute);
}
package com.smart.hospital.common.pay.strategy.factory;
import com.smart.hospital.common.pay.source.PayAttribute;
import com.smart.hospital.common.pay.strategy.handler.StrategyHandler;
import java.util.List;
public class StrategyHandlerFactory implements StrategyFactory {
private final List<StrategyHandler> strategyHandlers;
public StrategyHandlerFactory(List<StrategyHandler> strategyHandlers) {
this.strategyHandlers = strategyHandlers;
}
@Override
public StrategyHandler canApply(PayAttribute attribute) {
if (strategyHandlers == null || strategyHandlers.isEmpty()) {
return null;
}
for (StrategyHandler strategyHandler : strategyHandlers) {
if (strategyHandler.apply(attribute)) {
return strategyHandler;
}
}
return null;
}
}
package com.smart.hospital.common.pay.strategy.handler;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.smart.hospital.common.pay.prop.WxPayV3Properties;
import com.smart.hospital.common.pay.util.PayKit;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public abstract class AbstractStrategyHandler implements StrategyHandler {
protected final int OK = 200;
private WxPayV3Properties wxPayV3Properties;
private final Map<String, String> localCache = new ConcurrentHashMap<>(16);
public AbstractStrategyHandler(WxPayV3Properties wxPayV3Properties) {
this.wxPayV3Properties = wxPayV3Properties;
}
public AbstractStrategyHandler() {
}
protected String getSerialNumber() {
String num = localCache.get(wxPayV3Properties.getAppId());
if (StrUtil.isNotBlank(num)) {
return num;
}
// 获取证书序列号
X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream(wxPayV3Properties.getCertPath()));
String serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
localCache.put(wxPayV3Properties.getAppId(), serialNo);
return serialNo;
}
public WxPayV3Properties getWxPayV3Properties() {
return wxPayV3Properties;
}
@Override
public void setProperties(WxPayV3Properties wxPayV3Properties) {
this.wxPayV3Properties = wxPayV3Properties;
}
}
package com.smart.hospital.common.pay.strategy.handler;
import com.smart.hospital.common.pay.prop.WxPayV3Properties;
import com.smart.hospital.common.pay.source.PayAttribute;
import java.lang.reflect.Method;
/**
* 策略处理器
*/
public interface StrategyHandler {
/**
* 适用
*
* @param attribute
* @return
*/
boolean apply(PayAttribute attribute);
/**
* 执行前
*
* @param attribute
* @param clientInterface
* @param method
* @param args
* @return
*/
default Object beforeExecute(PayAttribute attribute, Class<?> clientInterface, Method method, Object[] args) {
return null;
}
/**
* 执行接口调用
*
* @param params
* @return
*/
Object execute(PayAttribute attribute, Object... params) throws Exception;
/**
* 执行后
*
* @param attribute
* @param clientInterface
* @param method
* @param args
* @param result
* @return
*/
default Object afterExecute(PayAttribute attribute, Class<?> clientInterface, Method method, Object[] args, Object result) {
return null;
}
default Object exception(PayAttribute attribute, Class<?> clientInterface, Method method, Object[] args, Exception ex) {
return null;
}
/**
* 设置参数
*/
void setProperties(WxPayV3Properties wxPayV3Properties);
}
package com.smart.hospital.common.pay.strategy.handler;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.smart.hospital.common.pay.core.wx.WxPayApi;
import com.smart.hospital.common.pay.enums.PaymentMethod;
import com.smart.hospital.common.pay.model.WxHttpResponse;
import com.smart.hospital.common.pay.prop.WxPayV3Properties;
import com.smart.hospital.common.pay.source.PayAttribute;
import com.smart.hospital.common.pay.util.AesUtil;
import com.smart.hospital.common.pay.util.PayKit;
import com.smart.hospital.common.pay.util.WxPayKit;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
/**
* 微信获取平台证书
*/
@Slf4j
public class WxCertV3StrategyHandler extends AbstractStrategyHandler {
public WxCertV3StrategyHandler(WxPayV3Properties wxPayV3Properties) {
super(wxPayV3Properties);
}
public WxCertV3StrategyHandler() {
}
@Override
public Object execute(PayAttribute attribute, Object... params) throws Exception {
log.info("微信获取平台证书...");
WxHttpResponse response = WxPayApi.v3(attribute.getRequestMethod(),
attribute.getPrefix().getType(),
attribute.getSuffix().getType(),
getWxPayV3Properties().getMchId(),
getSerialNumber(),
null,
getWxPayV3Properties().getKeyPath(),
"");
if (response != null) {
log.info("获取证书的基础信息为:{}", response);
saveCert(response);
}
return response;
}
@Override
public boolean apply(PayAttribute attribute) {
return attribute.getPayment() == PaymentMethod.WX_CERT;
}
private void saveCert(WxHttpResponse response) throws Exception {
String timestamp = response.getHeader("Wechatpay-Timestamp");
String nonceStr = response.getHeader("Wechatpay-Nonce");
String serialNumber = response.getHeader("Wechatpay-Serial");
String signature = response.getHeader("Wechatpay-Signature");
String body = response.getBody();
int status = response.getStatus();
log.info("serialNumber: {}", serialNumber);
log.info("status: {}", status);
log.info("body: {}", body);
int isOk = 200;
if (status == isOk) {
JSONObject jsonObject = JSONUtil.parseObj(body);
JSONArray dataArray = jsonObject.getJSONArray("data");
// 默认认为只有一个平台证书
JSONObject encryptObject = dataArray.getJSONObject(0);
JSONObject encryptCertificate = encryptObject.getJSONObject("encrypt_certificate");
String associatedData = encryptCertificate.getStr("associated_data");
String cipherText = encryptCertificate.getStr("ciphertext");
String nonce = encryptCertificate.getStr("nonce");
String serialNo = encryptObject.getStr("serial_no");
final String platSerialNo = savePlatformCert(associatedData, nonce, cipherText, getWxPayV3Properties().getPlatformCertPath());
log.info("平台证书序列号: {} serialNo: {}", platSerialNo, serialNo);
}
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, getWxPayV3Properties().getPlatformCertPath());
System.out.println("verifySignature:" + verifySignature);
}
private String savePlatformCert(String associatedData, String nonce, String cipherText, String certPath) {
try {
AesUtil aesUtil = new AesUtil(getWxPayV3Properties().getApiKey3().getBytes(StandardCharsets.UTF_8));
// 平台证书密文解密
// encrypt_certificate 中的 associated_data nonce ciphertext
String publicKey = aesUtil.decryptToString(
associatedData.getBytes(StandardCharsets.UTF_8),
nonce.getBytes(StandardCharsets.UTF_8),
cipherText
);
// 保存证书
FileWriter writer = new FileWriter(certPath);
writer.write(publicKey);
// 获取平台证书序列号
X509Certificate certificate = PayKit.getCertificate(new ByteArrayInputStream(publicKey.getBytes()));
return certificate.getSerialNumber().toString(16).toUpperCase();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
}
package com.smart.hospital.common.pay.strategy.handler;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.smart.hospital.common.pay.constant.Version;
import com.smart.hospital.common.pay.core.wx.WxPayApi;
import com.smart.hospital.common.pay.enums.PaymentMethod;
import com.smart.hospital.common.pay.exception.PayException;
import com.smart.hospital.common.pay.model.WxHttpResponse;
import com.smart.hospital.common.pay.model.WxUnifiedOrderModel;
import com.smart.hospital.common.pay.prop.WxPayV3Properties;
import com.smart.hospital.common.pay.source.PayAttribute;
import com.smart.hospital.common.pay.util.WxPayKit;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
import java.util.Map;
/**
* 微信jsapi-v3支付
*/
@Slf4j
public class WxJsapiV3StrategyHandler extends AbstractStrategyHandler {
public WxJsapiV3StrategyHandler(WxPayV3Properties wxPayV3Properties) {
super(wxPayV3Properties);
}
public WxJsapiV3StrategyHandler() {
}
@Override
public Object beforeExecute(PayAttribute attribute, Class<?> clientInterface, Method method, Object[] args) {
return null;
}
@Override
public Object execute(PayAttribute attribute, Object... params) throws Exception {
Object param = params[0];
log.info("统一下单参数 {}", JSONUtil.toJsonStr(param));
WxUnifiedOrderModel model = null;
if (param instanceof WxUnifiedOrderModel) {
model = (WxUnifiedOrderModel) param;
model.setAppid(getWxPayV3Properties().getAppId())
.setMchid(getWxPayV3Properties().getMchId())
.setNotify_url(getWxPayV3Properties().getDomain().concat("/v3/payNotify"))
// .setTime_expire(timeExpire)
;
}
if (model == null) {
throw new PayException("参数错误");
}
WxHttpResponse response = WxPayApi.v3(attribute.getRequestMethod(),
attribute.getPrefix().getType(),
attribute.getSuffix().getType(),
getWxPayV3Properties().getMchId(),
getSerialNumber(),
null,
getWxPayV3Properties().getKeyPath(),
JSONUtil.toJsonStr(model));
if (response.getStatus() == OK) {
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, getWxPayV3Properties().getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
if (verifySignature) {
String body = response.getBody();
JSONObject jsonObject = JSONUtil.parseObj(body);
String prepayId = jsonObject.getStr("prepay_id");
Map<String, String> map = WxPayKit.jsApiCreateSign(getWxPayV3Properties().getAppId(), prepayId, getWxPayV3Properties().getKeyPath());
log.info("唤起支付参数:{}", map);
return JSONUtil.toJsonStr(map);
}
}
throw new PayException("调用" + attribute.getPayment().getDescribe() + "失败!");
}
@Override
public boolean apply(PayAttribute attribute) {
return attribute.getPayment() == PaymentMethod.WX_JSAPI && Version.WX_V3.equals(attribute.getVersion());
}
}
package com.smart.hospital.common.pay.strategy.handler;
import cn.hutool.json.JSONUtil;
import com.smart.hospital.common.pay.core.wx.WxPayApi;
import com.smart.hospital.common.pay.enums.PaymentMethod;
import com.smart.hospital.common.pay.exception.PayException;
import com.smart.hospital.common.pay.model.WxHttpResponse;
import com.smart.hospital.common.pay.model.WxRefundModel;
import com.smart.hospital.common.pay.prop.WxPayV3Properties;
import com.smart.hospital.common.pay.source.PayAttribute;
import com.smart.hospital.common.pay.util.WxPayKit;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class WxRefundStrategyHandler extends AbstractStrategyHandler {
public WxRefundStrategyHandler(WxPayV3Properties wxPayV3Properties) {
super(wxPayV3Properties);
}
public WxRefundStrategyHandler() {
}
@Override
public Object execute(PayAttribute attribute, Object... params) throws Exception {
Object param = params[0];
log.info("退款参数 {}", param);
WxRefundModel refundModel = (WxRefundModel) param;
refundModel.setNotify_url(getWxPayV3Properties().getDomain().concat("/v3/refundNotify"));
WxHttpResponse response = WxPayApi.v3(
attribute.getRequestMethod(),
attribute.getPrefix().getType(),
attribute.getSuffix().getType(),
getWxPayV3Properties().getMchId(),
getSerialNumber(),
null,
getWxPayV3Properties().getKeyPath(),
JSONUtil.toJsonStr(refundModel)
);
if (response.getStatus() == OK) {
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(response, getWxPayV3Properties().getPlatformCertPath());
log.info("verifySignature: {}", verifySignature);
log.info("退款响应 {}", response);
if (verifySignature) {
return response.getBody();
}
}
throw new PayException("退款失败!");
}
@Override
public boolean apply(PayAttribute attribute) {
return attribute.getPayment() == PaymentMethod.WX_REFUND;
}
}
package com.smart.hospital.common.pay.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.ssl.SSLSocketFactoryBuilder;
import com.smart.hospital.common.pay.model.WxHttpResponse;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.Map;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付等常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875</p>
*
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
*
* <p>Http 代理类</p>
*
* @author Javen
*/
public abstract class AbstractHttpDelegate {
/**
* get 请求
*
* @param url 请求url
* @return {@link String} 请求返回的结果
*/
public String get(String url) {
return HttpUtil.get(url);
}
/**
* get 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @return {@link String} 请求返回的结果
*/
public String get(String url, Map<String, Object> paramMap) {
return HttpUtil.get(url, paramMap);
}
/**
* get 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public WxHttpResponse get(String url, Map<String, Object> paramMap, Map<String, String> headers) {
WxHttpResponse response = new WxHttpResponse();
HttpResponse httpResponse = getToResponse(url, paramMap, headers);
response.setBody(httpResponse.body());
response.setStatus(httpResponse.getStatus());
response.setHeaders(httpResponse.headers());
return response;
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data) {
return HttpUtil.post(url, data);
}
/**
* post 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @return {@link String} 请求返回的结果
*/
public String post(String url, Map<String, Object> paramMap) {
return HttpUtil.post(url, paramMap);
}
/**
* post 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public WxHttpResponse post(String url, Map<String, Object> paramMap, Map<String, String> headers) {
WxHttpResponse response = new WxHttpResponse();
HttpResponse httpResponse = postToResponse(url, headers, paramMap);
response.setBody(httpResponse.body());
response.setStatus(httpResponse.getStatus());
response.setHeaders(httpResponse.headers());
return response;
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public WxHttpResponse post(String url, String data, Map<String, String> headers) {
WxHttpResponse response = new WxHttpResponse();
HttpResponse httpResponse = postToResponse(url, headers, data);
response.setBody(httpResponse.body());
response.setStatus(httpResponse.getStatus());
response.setHeaders(httpResponse.headers());
return response;
}
/**
* patch 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public WxHttpResponse patch(String url, Map<String, Object> paramMap, Map<String, String> headers) {
WxHttpResponse response = new WxHttpResponse();
HttpResponse httpResponse = patchToResponse(url, headers, paramMap);
response.setBody(httpResponse.body());
response.setStatus(httpResponse.getStatus());
response.setHeaders(httpResponse.headers());
return response;
}
/**
* patch 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public WxHttpResponse patch(String url, String data, Map<String, String> headers) {
WxHttpResponse response = new WxHttpResponse();
HttpResponse httpResponse = patchToResponse(url, headers, data);
response.setBody(httpResponse.body());
response.setStatus(httpResponse.getStatus());
response.setHeaders(httpResponse.headers());
return response;
}
/**
* delete 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public WxHttpResponse delete(String url, Map<String, Object> paramMap, Map<String, String> headers) {
WxHttpResponse response = new WxHttpResponse();
HttpResponse httpResponse = deleteToResponse(url, headers, paramMap);
response.setBody(httpResponse.body());
response.setStatus(httpResponse.getStatus());
response.setHeaders(httpResponse.headers());
return response;
}
/**
* delete 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public WxHttpResponse delete(String url, String data, Map<String, String> headers) {
WxHttpResponse response = new WxHttpResponse();
HttpResponse httpResponse = deleteToResponse(url, headers, data);
response.setBody(httpResponse.body());
response.setStatus(httpResponse.getStatus());
response.setHeaders(httpResponse.headers());
return response;
}
/**
* put 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public WxHttpResponse put(String url, Map<String, Object> paramMap, Map<String, String> headers) {
WxHttpResponse response = new WxHttpResponse();
HttpResponse httpResponse = putToResponse(url, headers, paramMap);
response.setBody(httpResponse.body());
response.setStatus(httpResponse.getStatus());
response.setHeaders(httpResponse.headers());
return response;
}
/**
* put 请求
*
* @param url 请求url
* @param data 请求参数
* @param headers 请求头
* @return {@link WxHttpResponse} 请求返回的结果
*/
public WxHttpResponse put(String url, String data, Map<String, String> headers) {
WxHttpResponse response = new WxHttpResponse();
HttpResponse httpResponse = putToResponse(url, headers, data);
response.setBody(httpResponse.body());
response.setStatus(httpResponse.getStatus());
response.setHeaders(httpResponse.headers());
return response;
}
/**
* 上传文件
*
* @param url 请求url
* @param data 请求参数
* @param certPath 证书路径
* @param certPass 证书密码
* @param filePath 上传文件路径
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public String upload(String url, String data, String certPath, String certPass, String filePath, String protocol) {
try {
File file = FileUtil.newFile(filePath);
return HttpRequest.post(url)
.setSSLSocketFactory(SSLSocketFactoryBuilder
.create()
.setProtocol(protocol)
.setKeyManagers(getKeyManager(certPass, certPath, null))
.setSecureRandom(new SecureRandom())
.build()
)
.header("Content-Type", "multipart/form-data;boundary=\"boundary\"")
.form("file", file)
.form("meta", data)
.execute()
.body();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 上传文件
*
* @param url 请求url
* @param data 请求参数
* @param certPath 证书路径
* @param certPass 证书密码
* @param filePath 上传文件路径
* @return {@link String} 请求返回的结果
*/
public String upload(String url, String data, String certPath, String certPass, String filePath) {
return upload(url, data, certPath, certPass, filePath, SSLSocketFactoryBuilder.TLSv1);
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param certPath 证书路径
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data, String certPath, String certPass, String protocol) {
try {
return HttpRequest.post(url)
.setSSLSocketFactory(SSLSocketFactoryBuilder
.create()
.setProtocol(protocol)
.setKeyManagers(getKeyManager(certPass, certPath, null))
.setSecureRandom(new SecureRandom())
.build()
)
.body(data)
.execute()
.body();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param certPath 证书路径
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data, String certPath, String certPass) {
return post(url, data, certPath, certPass, SSLSocketFactoryBuilder.TLSv1);
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param certFile 证书文件输入流
* @param certPass 证书密码
* @param protocol 协议
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data, InputStream certFile, String certPass, String protocol) {
try {
return HttpRequest.post(url)
.setSSLSocketFactory(SSLSocketFactoryBuilder
.create()
.setProtocol(protocol)
.setKeyManagers(getKeyManager(certPass, null, certFile))
.setSecureRandom(new SecureRandom())
.build()
)
.body(data)
.execute()
.body();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* post 请求
*
* @param url 请求url
* @param data 请求参数
* @param certFile 证书文件输入流
* @param certPass 证书密码
* @return {@link String} 请求返回的结果
*/
public String post(String url, String data, InputStream certFile, String certPass) {
return post(url, data, certFile, certPass, SSLSocketFactoryBuilder.TLSv1);
}
/**
* get 请求
*
* @param url 请求url
* @param paramMap 请求参数
* @param headers 请求头
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse getToResponse(String url, Map<String, Object> paramMap, Map<String, String> headers) {
return HttpRequest.get(url)
.addHeaders(headers)
.form(paramMap)
.execute();
}
/**
* post 请求
*
* @param url 请求url
* @param headers 请求头
* @param data 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse postToResponse(String url, Map<String, String> headers, String data) {
return HttpRequest.post(url)
.addHeaders(headers)
.body(data)
.execute();
}
/**
* post 请求
*
* @param url 请求url
* @param headers 请求头
* @param paramMap 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse postToResponse(String url, Map<String, String> headers, Map<String, Object> paramMap) {
return HttpRequest.post(url)
.addHeaders(headers)
.form(paramMap)
.execute();
}
/**
* patch 请求
*
* @param url 请求url
* @param headers 请求头
* @param paramMap 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse patchToResponse(String url, Map<String, String> headers, Map<String, Object> paramMap) {
return HttpRequest.patch(url)
.addHeaders(headers)
.form(paramMap)
.execute();
}
/**
* patch 请求
*
* @param url 请求url
* @param headers 请求头
* @param data 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse patchToResponse(String url, Map<String, String> headers, String data) {
return HttpRequest.patch(url)
.addHeaders(headers)
.body(data)
.execute();
}
/**
* delete 请求
*
* @param url 请求url
* @param headers 请求头
* @param data 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse deleteToResponse(String url, Map<String, String> headers, String data) {
return HttpRequest.delete(url)
.addHeaders(headers)
.body(data)
.execute();
}
/**
* delete 请求
*
* @param url 请求url
* @param headers 请求头
* @param paramMap 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse deleteToResponse(String url, Map<String, String> headers, Map<String, Object> paramMap) {
return HttpRequest.delete(url)
.addHeaders(headers)
.form(paramMap)
.execute();
}
/**
* put 请求
*
* @param url 请求url
* @param headers 请求头
* @param data 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse putToResponse(String url, Map<String, String> headers, String data) {
return HttpRequest.put(url)
.addHeaders(headers)
.body(data)
.execute();
}
/**
* put 请求
*
* @param url 请求url
* @param headers 请求头
* @param paramMap 请求参数
* @return {@link HttpResponse} 请求返回的结果
*/
private HttpResponse putToResponse(String url, Map<String, String> headers, Map<String, Object> paramMap) {
return HttpRequest.put(url)
.addHeaders(headers)
.form(paramMap)
.execute();
}
private KeyManager[] getKeyManager(String certPass, String certPath, InputStream certFile) throws Exception {
KeyStore clientStore = KeyStore.getInstance("PKCS12");
if (certFile != null) {
clientStore.load(certFile, certPass.toCharArray());
} else {
clientStore.load(new FileInputStream(certPath), certPass.toCharArray());
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, certPass.toCharArray());
return kmf.getKeyManagers();
}
}
package com.smart.hospital.common.pay.util;
import cn.hutool.core.codec.Base64;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875</p>
*
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
*
* <p>工具类 AesUtil</p>
*
* @author 微信
*/
public class AesUtil {
static final int KEY_LENGTH_BYTE = 32;
static final int TAG_LENGTH_BIT = 128;
private final byte[] aesKey;
/**
* @param key APIv3 密钥
*/
public AesUtil(byte[] key) {
if (key.length != KEY_LENGTH_BYTE) {
throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
}
this.aesKey = key;
}
/**
* 证书和回调报文解密
*
* @param associatedData associated_data
* @param nonce nonce
* @param cipherText ciphertext
* @return {String} 平台证书明文
* @throws GeneralSecurityException 异常
*/
public String decryptToString(byte[] associatedData, byte[] nonce, String cipherText) throws GeneralSecurityException {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData);
return new String(cipher.doFinal(Base64.decode(cipherText)), StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
}
package com.smart.hospital.common.pay.util;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875</p>
*
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
*
* <p>Http 工具类</p>
*
* @author Javen
*/
public class HttpKit {
private static AbstractHttpDelegate delegate = new DefaultHttpKit();
public static AbstractHttpDelegate getDelegate() {
return delegate;
}
public static void setDelegate(AbstractHttpDelegate delegate) {
HttpKit.delegate = delegate;
}
public static String readData(HttpServletRequest request) {
BufferedReader br = null;
try {
StringBuilder result = new StringBuilder();
br = request.getReader();
for (String line; (line = br.readLine()) != null; ) {
if (result.length() > 0) {
result.append("\n");
}
result.append(line);
}
return result.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 将同步通知的参数转化为Map
*
* @param request {@link HttpServletRequest}
* @return 转化后的 Map
*/
public static Map<String, String> toMap(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
params.put(name, valueStr);
}
return params;
}
}
/**
* 使用 huTool 实现的 Http 工具类
*
* @author Javen
*/
class DefaultHttpKit extends AbstractHttpDelegate {
}
package com.smart.hospital.common.pay.util;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.io.resource.Resource;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HmacAlgorithm;
import com.smart.hospital.common.pay.enums.RequestMethod;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.*;
import java.util.*;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875</p>
*
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
*
* <p>IJPay 工具类</p>
*
* @author Javen
*/
public class PayKit {
/**
* 生成16进制的 sha256 字符串
*
* @param data 数据
* @param key 密钥
* @return sha256 字符串
*/
public static String hmacSha256(String data, String key) {
return SecureUtil.hmac(HmacAlgorithm.HmacSHA256, key).digestHex(data);
}
/**
* SHA1加密文件,生成16进制SHA1字符串<br>
*
* @param dataFile 被加密文件
* @return SHA1 字符串
*/
public static String sha1(File dataFile) {
return SecureUtil.sha1(dataFile);
}
/**
* SHA1加密,生成16进制SHA1字符串<br>
*
* @param data 数据
* @return SHA1 字符串
*/
public static String sha1(InputStream data) {
return SecureUtil.sha1(data);
}
/**
* SHA1加密,生成16进制SHA1字符串<br>
*
* @param data 数据
* @return SHA1 字符串
*/
public static String sha1(String data) {
return SecureUtil.sha1(data);
}
/**
* 生成16进制 MD5 字符串
*
* @param data 数据
* @return MD5 字符串
*/
public static String md5(String data) {
return SecureUtil.md5(data);
}
/**
* AES 解密
*
* @param base64Data 需要解密的数据
* @param key 密钥
* @return 解密后的数据
*/
public static String decryptData(String base64Data, String key) {
return SecureUtil.aes(md5(key).toLowerCase().getBytes()).decryptStr(base64Data);
}
/**
* AES 加密
*
* @param data 需要加密的数据
* @param key 密钥
* @return 加密后的数据
*/
public static String encryptData(String data, String key) {
return SecureUtil.aes(md5(key).toLowerCase().getBytes()).encryptBase64(data.getBytes());
}
/**
* 简化的UUID,去掉了横线,使用性能更好的 ThreadLocalRandom 生成UUID
*
* @return 简化的 UUID,去掉了横线
*/
public static String generateStr() {
return IdUtil.fastSimpleUUID();
}
/**
* 雪花算法
*
* @param workerId 终端ID
* @param dataCenterId 数据中心ID
* @return {@link Snowflake}
*/
public static Snowflake getSnowflake(long workerId, long dataCenterId) {
return IdUtil.getSnowflake(workerId, dataCenterId);
}
/**
* 把所有元素排序
*
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, String> params) {
return createLinkString(params, false);
}
/**
* @param params 需要排序并参与字符拼接的参数组
* @param encode 是否进行URLEncoder
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, String> params, boolean encode) {
return createLinkString(params, "&", encode);
}
/**
* @param params 需要排序并参与字符拼接的参数组
* @param connStr 连接符号
* @param encode 是否进行URLEncoder
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, String> params, String connStr, boolean encode) {
return createLinkString(params, connStr, encode, false);
}
public static String createLinkString(Map<String, String> params, String connStr, boolean encode, boolean quotes) {
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
StringBuilder content = new StringBuilder();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
// 拼接时,不包括最后一个&字符
if (i == keys.size() - 1) {
if (quotes) {
content.append(key).append("=").append('"').append(encode ? urlEncode(value) : value).append('"');
} else {
content.append(key).append("=").append(encode ? urlEncode(value) : value);
}
} else {
if (quotes) {
content.append(key).append("=").append('"').append(encode ? urlEncode(value) : value).append('"').append(connStr);
} else {
content.append(key).append("=").append(encode ? urlEncode(value) : value).append(connStr);
}
}
}
return content.toString();
}
/**
* URL 编码
*
* @param src 需要编码的字符串
* @return 编码后的字符串
*/
public static String urlEncode(String src) {
try {
return URLEncoder.encode(src, CharsetUtil.UTF_8).replace("+", "%20");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
/**
* 遍历 Map 并构建 xml 数据
*
* @param params 需要遍历的 Map
* @param prefix xml 前缀
* @param suffix xml 后缀
* @return xml 字符串
*/
public static StringBuffer forEachMap(Map<String, String> params, String prefix, String suffix) {
StringBuffer xml = new StringBuffer();
if (StrUtil.isNotEmpty(prefix)) {
xml.append(prefix);
}
for (Map.Entry<String, String> entry : params.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
// 略过空值
if (StrUtil.isEmpty(value)) {
continue;
}
xml.append("<").append(key).append(">");
xml.append(entry.getValue());
xml.append("</").append(key).append(">");
}
if (StrUtil.isNotEmpty(suffix)) {
xml.append(suffix);
}
return xml;
}
/**
* 微信下单 map to xml
*
* @param params Map 参数
* @return xml 字符串
*/
public static String toXml(Map<String, String> params) {
StringBuffer xml = forEachMap(params, "<xml>", "</xml>");
return xml.toString();
}
/**
* 针对支付的 xml,没有嵌套节点的简单处理
*
* @param xmlStr xml 字符串
* @return 转化后的 Map
*/
public static Map<String, String> xmlToMap(String xmlStr) {
XmlHelper xmlHelper = XmlHelper.of(xmlStr);
return xmlHelper.toMap();
}
/**
* 构造签名串
*
* @param method {@link RequestMethod} GET,POST,PUT等
* @param url 请求接口 /v3/certificates
* @param timestamp 获取发起请求时的系统当前时间戳
* @param nonceStr 随机字符串
* @param body 请求报文主体
* @return 待签名字符串
*/
public static String buildSignMessage(RequestMethod method, String url, long timestamp, String nonceStr, String body) {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add(method.toString());
arrayList.add(url);
arrayList.add(String.valueOf(timestamp));
arrayList.add(nonceStr);
arrayList.add(body);
return buildSignMessage(arrayList);
}
/**
* 构造签名串
*
* @param timestamp 应答时间戳
* @param nonceStr 应答随机串
* @param body 应答报文主体
* @return 应答待签名字符串
*/
public static String buildSignMessage(String timestamp, String nonceStr, String body) {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add(timestamp);
arrayList.add(nonceStr);
arrayList.add(body);
return buildSignMessage(arrayList);
}
/**
* 构造签名串
*
* @param signMessage 待签名的参数
* @return 构造后带待签名串
*/
public static String buildSignMessage(ArrayList<String> signMessage) {
if (signMessage == null || signMessage.size() <= 0) {
return null;
}
StringBuilder sbf = new StringBuilder();
for (String str : signMessage) {
sbf.append(str).append("\n");
}
return sbf.toString();
}
/**
* v3 接口创建签名
*
* @param signMessage 待签名的参数
* @param keyPath key.pem 证书路径
* @return 生成 v3 签名
* @throws Exception 异常信息
*/
public static String createSign(ArrayList<String> signMessage, String keyPath) throws Exception {
return createSign(buildSignMessage(signMessage), keyPath);
}
/**
* v3 接口创建签名
*
* @param signMessage 待签名的参数
* @param privateKey 商户私钥
* @return 生成 v3 签名
* @throws Exception 异常信息
*/
public static String createSign(ArrayList<String> signMessage, PrivateKey privateKey) throws Exception {
return createSign(buildSignMessage(signMessage), privateKey);
}
/**
* v3 接口创建签名
*
* @param signMessage 待签名的参数
* @param keyPath key.pem 证书路径
* @return 生成 v3 签名
* @throws Exception 异常信息
*/
public static String createSign(String signMessage, String keyPath) throws Exception {
if (StrUtil.isEmpty(signMessage)) {
return null;
}
// 获取商户私钥
PrivateKey privateKey = PayKit.getPrivateKey(keyPath);
// 生成签名
return RsaKit.encryptByPrivateKey(signMessage, privateKey);
}
/**
* v3 接口创建签名
*
* @param signMessage 待签名的参数
* @param privateKey 商户私钥
* @return 生成 v3 签名
* @throws Exception 异常信息
*/
public static String createSign(String signMessage, PrivateKey privateKey) throws Exception {
if (StrUtil.isEmpty(signMessage)) {
return null;
}
// 生成签名
return RsaKit.encryptByPrivateKey(signMessage, privateKey);
}
/**
* 获取授权认证信息
*
* @param mchId 商户号
* @param serialNo 商户API证书序列号
* @param nonceStr 请求随机串
* @param timestamp 时间戳
* @param signature 签名值
* @param authType 认证类型,目前为WECHATPAY2-SHA256-RSA2048
* @return 请求头 Authorization
*/
public static String getAuthorization(String mchId, String serialNo, String nonceStr, String timestamp, String signature, String authType) {
Map<String, String> params = new HashMap<>(5);
params.put("mchid", mchId);
params.put("serial_no", serialNo);
params.put("nonce_str", nonceStr);
params.put("timestamp", timestamp);
params.put("signature", signature);
return authType.concat(" ").concat(createLinkString(params, ",", false, true));
}
/**
* 获取商户私钥
*
* @param keyPath 商户私钥证书路径
* @return {@link String} 商户私钥
* @throws Exception 异常信息
*/
public static String getPrivateKeyStr(String keyPath) throws Exception {
return RsaKit.getPrivateKeyStr(getPrivateKey(keyPath));
}
/**
* 获取商户私钥
*
* @param keyPath 商户私钥证书路径
* @return {@link PrivateKey} 商户私钥
* @throws Exception 异常信息
*/
public static PrivateKey getPrivateKey(String keyPath) throws Exception {
String originalKey = FileUtil.readUtf8String(keyPath);
return getPrivateKeyByKeyContent(originalKey);
}
/**
* 获取商户私钥
*
* @param originalKey 私钥文本内容
* @return {@link PrivateKey} 商户私钥
* @throws Exception 异常信息
*/
public static PrivateKey getPrivateKeyByKeyContent(String originalKey) throws Exception {
String privateKey = originalKey
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
return RsaKit.loadPrivateKey(privateKey);
}
/**
* 获取证书
*
* @param inputStream 证书文件
* @return {@link X509Certificate} 获取证书
*/
public static X509Certificate getCertificate(InputStream inputStream) {
try {
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
cert.checkValidity();
return cert;
} catch (CertificateExpiredException e) {
throw new RuntimeException("证书已过期", e);
} catch (CertificateNotYetValidException e) {
throw new RuntimeException("证书尚未生效", e);
} catch (CertificateException e) {
throw new RuntimeException("无效的证书", e);
}
}
/**
* 公钥加密
*
* @param data 待加密数据
* @param certificate 平台公钥证书
* @return 加密后的数据
* @throws Exception 异常信息
*/
public static String rsaEncryptOAEP(String data, X509Certificate certificate) throws Exception {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
byte[] cipherData = cipher.doFinal(dataByte);
return Base64.encode(cipherData);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("无效的证书", e);
} catch (IllegalBlockSizeException | BadPaddingException e) {
throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
}
}
/**
* 私钥解密
*
* @param cipherText 加密字符
* @param privateKey 私钥
* @return 解密后的数据
* @throws Exception 异常信息
*/
public static String rsaDecryptOAEP(String cipherText, PrivateKey privateKey) throws Exception {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] data = Base64.decode(cipherText);
return new String(cipher.doFinal(data), StandardCharsets.UTF_8);
} catch (NoSuchPaddingException | NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("无效的私钥", e);
} catch (BadPaddingException | IllegalBlockSizeException e) {
throw new BadPaddingException("解密失败");
}
}
/**
* 传入 classPath 静态资源路径返回文件输入流
*
* @param classPath 静态资源路径
* @return InputStream
*/
public static InputStream getFileToStream(String classPath) {
Resource resource = new ClassPathResource(classPath);
return resource.getStream();
}
/**
* 传入 classPath 静态资源路径返回绝对路径
*
* @param classPath 静态资源路径
* @return 绝对路径
*/
public static String getAbsolutePath(String classPath) {
return new ClassPathResource(classPath).getAbsolutePath();
}
}
package com.smart.hospital.common.pay.util;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;
import java.util.HashMap;
import java.util.Map;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875</p>
*
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
*
* <p>RSA 非对称加密工具类</p>
*
* @author Javen
*/
public class RsaKit {
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
/**
* 加密算法RSA
*/
private static final String KEY_ALGORITHM = "RSA";
/**
* 生成公钥和私钥
*
* @throws Exception 异常信息
*/
public static Map<String, String> getKeys() throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
String publicKeyStr = getPublicKeyStr(publicKey);
String privateKeyStr = getPrivateKeyStr(privateKey);
Map<String, String> map = new HashMap<String, String>(2);
map.put("publicKey", publicKeyStr);
map.put("privateKey", privateKeyStr);
System.out.println("公钥\r\n" + publicKeyStr);
System.out.println("私钥\r\n" + privateKeyStr);
return map;
}
/**
* 使用模和指数生成RSA公钥
* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
* /None/NoPadding】
*
* @param modulus 模
* @param exponent 公钥指数
* @return {@link RSAPublicKey}
*/
public static RSAPublicKey getPublicKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 使用模和指数生成RSA私钥
* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA
* /None/NoPadding】
*
* @param modulus 模
* @param exponent 指数
* @return {@link RSAPrivateKey}
*/
public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
try {
BigInteger b1 = new BigInteger(modulus);
BigInteger b2 = new BigInteger(exponent);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 公钥加密
*
* @param data 需要加密的数据
* @param publicKey 公钥
* @return 加密后的数据
* @throws Exception 异常信息
*/
public static String encryptByPublicKey(String data, String publicKey) throws Exception {
return encryptByPublicKey(data, publicKey, "RSA/ECB/PKCS1Padding");
}
/**
* 公钥加密
*
* @param data 需要加密的数据
* @param publicKey 公钥
* @return 加密后的数据
* @throws Exception 异常信息
*/
public static String encryptByPublicKeyByWx(String data, String publicKey) throws Exception {
return encryptByPublicKey(data, publicKey, "RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
}
/**
* 公钥加密
*
* @param data 需要加密的数据
* @param publicKey 公钥
* @param fillMode 填充模式
* @return 加密后的数据
* @throws Exception 异常信息
*/
public static String encryptByPublicKey(String data, String publicKey, String fillMode) throws Exception {
byte[] dataByte = data.getBytes(StandardCharsets.UTF_8);
byte[] keyBytes = Base64.decode(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key key = keyFactory.generatePublic(x509KeySpec);
// 对数据加密
Cipher cipher = Cipher.getInstance(fillMode);
cipher.init(Cipher.ENCRYPT_MODE, key);
int inputLen = dataByte.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(dataByte, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(dataByte, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return StrUtil.str(Base64.encode(encryptedData));
}
/**
* 私钥签名
*
* @param data 需要加密的数据
* @param privateKey 私钥
* @return 加密后的数据
* @throws Exception 异常信息
*/
public static String encryptByPrivateKey(String data, String privateKey) throws Exception {
PKCS8EncodedKeySpec priPkcs8 = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey priKey = keyFactory.generatePrivate(priPkcs8);
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initSign(priKey);
signature.update(data.getBytes(StandardCharsets.UTF_8));
byte[] signed = signature.sign();
return StrUtil.str(Base64.encode(signed));
}
/**
* 私钥签名
*
* @param data 需要加密的数据
* @param privateKey 私钥
* @return 加密后的数据
* @throws Exception 异常信息
*/
public static String encryptByPrivateKey(String data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initSign(privateKey);
signature.update(data.getBytes(StandardCharsets.UTF_8));
byte[] signed = signature.sign();
return StrUtil.str(Base64.encode(signed));
}
/**
* 公钥验证签名
*
* @param data 需要加密的数据
* @param sign 签名
* @param publicKey 公钥
* @return 验证结果
* @throws Exception 异常信息
*/
public static boolean checkByPublicKey(String data, String sign, String publicKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
byte[] encodedKey = Base64.decode(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initVerify(pubKey);
signature.update(data.getBytes(StandardCharsets.UTF_8));
return signature.verify(Base64.decode(sign.getBytes(StandardCharsets.UTF_8)));
}
/**
* 公钥验证签名
*
* @param data 需要加密的数据
* @param sign 签名
* @param publicKey 公钥
* @return 验证结果
* @throws Exception 异常信息
*/
public static boolean checkByPublicKey(String data, String sign, PublicKey publicKey) throws Exception {
Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initVerify(publicKey);
signature.update(data.getBytes(StandardCharsets.UTF_8));
return signature.verify(Base64.decode(sign.getBytes(StandardCharsets.UTF_8)));
}
/**
* 私钥解密
*
* @param data 需要解密的数据
* @param privateKey 私钥
* @return 解密后的数据
* @throws Exception 异常信息
*/
public static String decryptByPrivateKey(String data, String privateKey) throws Exception {
return decryptByPrivateKey(data, privateKey, "RSA/ECB/PKCS1Padding");
}
/**
* 私钥解密
*
* @param data 需要解密的数据
* @param privateKey 私钥
* @return 解密后的数据
* @throws Exception 异常信息
*/
public static String decryptByPrivateKeyByWx(String data, String privateKey) throws Exception {
return decryptByPrivateKey(data, privateKey, "RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING");
}
/**
* 私钥解密
*
* @param data 需要解密的数据
* @param privateKey 私钥
* @param fillMode 填充模式
* @return 解密后的数据
* @throws Exception 异常信息
*/
public static String decryptByPrivateKey(String data, String privateKey, String fillMode) throws Exception {
byte[] encryptedData = Base64.decode(data);
byte[] keyBytes = Base64.decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key key = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(fillMode);
cipher.init(Cipher.DECRYPT_MODE, key);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return new String(decryptedData);
}
/**
* 从字符串中加载公钥
*
* @param publicKeyStr 公钥数据字符串
* @throws Exception 异常信息
*/
public static PublicKey loadPublicKey(String publicKeyStr) throws Exception {
try {
byte[] buffer = Base64.decode(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("公钥非法");
} catch (NullPointerException e) {
throw new Exception("公钥数据为空");
}
}
/**
* 从字符串中加载私钥<br>
* 加载时使用的是PKCS8EncodedKeySpec(PKCS#8编码的Key指令)。
*
* @param privateKeyStr 私钥
* @return {@link PrivateKey}
* @throws Exception 异常信息
*/
public static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
try {
byte[] buffer = Base64.decode(privateKeyStr);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
return keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("私钥非法");
} catch (NullPointerException e) {
throw new Exception("私钥数据为空");
}
}
public static String getPrivateKeyStr(PrivateKey privateKey) {
return Base64.encode(privateKey.getEncoded());
}
public static String getPublicKeyStr(PublicKey publicKey) {
return Base64.encode(publicKey.getEncoded());
}
public static void main(String[] args) throws Exception {
Map<String, String> keys = getKeys();
String publicKey = keys.get("publicKey");
String privateKey = keys.get("privateKey");
String content = "我是Javen,I am Javen";
String encrypt = encryptByPublicKey(content, publicKey);
String decrypt = decryptByPrivateKey(encrypt, privateKey);
System.out.println("加密之后:" + encrypt);
System.out.println("解密之后:" + decrypt);
System.out.println("======华丽的分割线=========");
content = "我是Javen,I am Javen";
encrypt = encryptByPublicKeyByWx(content, publicKey);
decrypt = decryptByPrivateKeyByWx(encrypt, privateKey);
System.out.println("加密之后:" + encrypt);
System.out.println("解密之后:" + decrypt);
//OPPO
String sign = encryptByPrivateKey(content, privateKey);
System.out.println("加密之后:" + sign);
System.out.println(checkByPublicKey(content, sign, publicKey));
}
}
package com.smart.hospital.common.pay.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.smart.hospital.common.pay.enums.RequestMethod;
import com.smart.hospital.common.pay.enums.SignType;
import com.smart.hospital.common.pay.model.WxHttpResponse;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/**
* <p>IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
*
* <p>不依赖任何第三方 mvc 框架,仅仅作为工具使用简单快速完成支付模块的开发,可轻松嵌入到任何系统里。 </p>
*
* <p>IJPay 交流群: 723992875</p>
*
* <p>Node.js 版: https://gitee.com/javen205/TNWX</p>
*
* <p>微信支付工具类</p>
*
* @author Javen
*/
public class WxPayKit {
private static final String FIELD_SIGN = "sign";
private static final String FIELD_SIGN_TYPE = "sign_type";
public static String hmacSha256(String data, String key) {
return PayKit.hmacSha256(data, key);
}
public static String md5(String data) {
return PayKit.md5(data);
}
/**
* AES 解密
*
* @param base64Data 需要解密的数据
* @param key 密钥
* @return 解密后的数据
*/
public static String decryptData(String base64Data, String key) {
return PayKit.decryptData(base64Data, key);
}
/**
* AES 加密
*
* @param data 需要加密的数据
* @param key 密钥
* @return 加密后的数据
*/
public static String encryptData(String data, String key) {
return PayKit.encryptData(data, key);
}
public static String generateStr() {
return PayKit.generateStr();
}
/**
* 支付异步通知时校验 sign
*
* @param params 参数
* @param partnerKey 支付密钥
* @return {boolean}
*/
public static boolean verifyNotify(Map<String, String> params, String partnerKey) {
String sign = params.get("sign");
String localSign = createSign(params, partnerKey, SignType.MD5);
return sign.equals(localSign);
}
/**
* 支付异步通知时校验 sign
*
* @param params 参数
* @param partnerKey 支付密钥
* @param signType {@link SignType}
* @return {@link Boolean} 验证签名结果
*/
public static boolean verifyNotify(Map<String, String> params, String partnerKey, SignType signType) {
String sign = params.get("sign");
String localSign = createSign(params, partnerKey, signType);
return sign.equals(localSign);
}
/**
* 生成签名
*
* @param params 需要签名的参数
* @param partnerKey 密钥
* @param signType 签名类型
* @return 签名后的数据
*/
public static String createSign(Map<String, String> params, String partnerKey, SignType signType) {
if (signType == null) {
signType = SignType.MD5;
}
// 生成签名前先去除sign
params.remove(FIELD_SIGN);
String tempStr = PayKit.createLinkString(params);
String stringSignTemp = tempStr + "&key=" + partnerKey;
if (signType == SignType.MD5) {
return md5(stringSignTemp).toUpperCase();
} else {
return hmacSha256(stringSignTemp, partnerKey).toUpperCase();
}
}
/**
* 生成签名
*
* @param params 需要签名的参数
* @param secret 企业微信支付应用secret
* @return 签名后的数据
*/
public static String createSign(Map<String, String> params, String secret) {
// 生成签名前先去除sign
params.remove(FIELD_SIGN);
String tempStr = PayKit.createLinkString(params);
String stringSignTemp = tempStr + "&secret=" + secret;
return md5(stringSignTemp).toUpperCase();
}
/**
* 构建签名
*
* @param params 需要签名的参数
* @param partnerKey 密钥
* @param signType 签名类型
* @return 签名后的 Map
*/
public static Map<String, String> buildSign(Map<String, String> params, String partnerKey, SignType signType) {
return buildSign(params, partnerKey, signType, true);
}
/**
* 构建签名
*
* @param params 需要签名的参数
* @param partnerKey 密钥
* @param signType 签名类型
* @param haveSignType 签名是否包含 sign_type 字段
* @return 签名后的 Map
*/
public static Map<String, String> buildSign(Map<String, String> params, String partnerKey, SignType signType, boolean haveSignType) {
if (haveSignType) {
params.put(FIELD_SIGN_TYPE, signType.getType());
}
String sign = createSign(params, partnerKey, signType);
params.put(FIELD_SIGN, sign);
return params;
}
public static StringBuffer forEachMap(Map<String, String> params, String prefix, String suffix) {
return PayKit.forEachMap(params, prefix, suffix);
}
/**
* 微信下单 map to xml
*
* @param params Map 参数
* @return xml 字符串
*/
public static String toXml(Map<String, String> params) {
return PayKit.toXml(params);
}
/**
* 针对支付的 xml,没有嵌套节点的简单处理
*
* @param xmlStr xml 字符串
* @return 转化后的 Map
*/
public static Map<String, String> xmlToMap(String xmlStr) {
return PayKit.xmlToMap(xmlStr);
}
/**
* <p>生成二维码链接</p>
* <p>原生支付接口模式一(扫码模式一)</p>
*
* @param sign 签名
* @param appId 公众账号ID
* @param mchId 商户号
* @param productId 商品ID
* @param timeStamp 时间戳
* @param nonceStr 随机字符串
* @return {String}
*/
public static String bizPayUrl(String sign, String appId, String mchId, String productId, String timeStamp, String nonceStr) {
String rules = "weixin://wxpay/bizpayurl?sign=Temp&appid=Temp&mch_id=Temp&product_id=Temp&time_stamp=Temp&nonce_str=Temp";
return replace(rules, "Temp", sign, appId, mchId, productId, timeStamp, nonceStr);
}
/**
* <p>生成二维码链接</p>
* <p>原生支付接口模式一(扫码模式一)</p>
*
* @param partnerKey 密钥
* @param appId 公众账号ID
* @param mchId 商户号
* @param productId 商品ID
* @param timeStamp 时间戳
* @param nonceStr 随机字符串
* @param signType 签名类型
* @return {String}
*/
public static String bizPayUrl(String partnerKey, String appId, String mchId, String productId, String timeStamp, String nonceStr, SignType signType) {
HashMap<String, String> map = new HashMap<>(5);
map.put("appid", appId);
map.put("mch_id", mchId);
map.put("time_stamp", StrUtil.isEmpty(timeStamp) ? Long.toString(System.currentTimeMillis() / 1000) : timeStamp);
map.put("nonce_str", StrUtil.isEmpty(nonceStr) ? WxPayKit.generateStr() : nonceStr);
map.put("product_id", productId);
return bizPayUrl(createSign(map, partnerKey, signType), appId, mchId, productId, timeStamp, nonceStr);
}
/**
* <p>生成二维码链接</p>
* <p>原生支付接口模式一(扫码模式一)</p>
*
* @param partnerKey 密钥
* @param appId 公众账号ID
* @param mchId 商户号
* @param productId 商品ID
* @return {String}
*/
public static String bizPayUrl(String partnerKey, String appId, String mchId, String productId) {
String timeStamp = Long.toString(System.currentTimeMillis() / 1000);
String nonceStr = WxPayKit.generateStr();
HashMap<String, String> map = new HashMap<>(5);
map.put("appid", appId);
map.put("mch_id", mchId);
map.put("time_stamp", timeStamp);
map.put("nonce_str", nonceStr);
map.put("product_id", productId);
return bizPayUrl(createSign(map, partnerKey, null), appId, mchId, productId, timeStamp, nonceStr);
}
/**
* 替换url中的参数
*
* @param str 原始字符串
* @param regex 表达式
* @param args 替换字符串
* @return {String}
*/
public static String replace(String str, String regex, String... args) {
for (String arg : args) {
str = str.replaceFirst(regex, arg);
}
return str;
}
/**
* 判断接口返回的 code
*
* @param codeValue code 值
* @return 是否是 SUCCESS
*/
public static boolean codeIsOk(String codeValue) {
return StrUtil.isNotEmpty(codeValue) && "SUCCESS".equals(codeValue);
}
/**
* <p>公众号支付-预付订单再次签名</p>
* <p>注意此处签名方式需与统一下单的签名类型一致</p>
*
* @param prepayId 预付订单号
* @param appId 应用编号
* @param partnerKey API Key
* @param signType 签名方式
* @return 再次签名后的 Map
*/
public static Map<String, String> prepayIdCreateSign(String prepayId, String appId, String partnerKey, SignType signType) {
Map<String, String> packageParams = new HashMap<>(6);
packageParams.put("appId", appId);
packageParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
packageParams.put("nonceStr", String.valueOf(System.currentTimeMillis()));
packageParams.put("package", "prepay_id=" + prepayId);
if (signType == null) {
signType = SignType.MD5;
}
packageParams.put("signType", signType.getType());
String packageSign = WxPayKit.createSign(packageParams, partnerKey, signType);
packageParams.put("paySign", packageSign);
return packageParams;
}
/**
* JS 调起支付签名
*
* @param appId 应用编号
* @param prepayId 预付订单号
* @param keyPath key.pem 证书路径
* @return 唤起支付需要的参数
* @throws Exception 错误信息
*/
public static Map<String, String> jsApiCreateSign(String appId, String prepayId, String keyPath) throws Exception {
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = String.valueOf(System.currentTimeMillis());
String packageStr = "prepay_id=" + prepayId;
Map<String, String> packageParams = new HashMap<>(6);
packageParams.put("appId", appId);
packageParams.put("timeStamp", timeStamp);
packageParams.put("nonceStr", nonceStr);
packageParams.put("package", packageStr);
packageParams.put("signType", SignType.RSA.toString());
ArrayList<String> list = new ArrayList<>();
list.add(appId);
list.add(timeStamp);
list.add(nonceStr);
list.add(packageStr);
String packageSign = PayKit.createSign(
PayKit.buildSignMessage(list),
keyPath
);
packageParams.put("paySign", packageSign);
return packageParams;
}
/**
* <p>APP 支付-预付订单再次签名</p>
* <p>注意此处签名方式需与统一下单的签名类型一致</p>
*
* @param appId 应用编号
* @param partnerId 商户号
* @param prepayId 预付订单号
* @param partnerKey API Key
* @param signType 签名方式
* @return 再次签名后的 Map
*/
public static Map<String, String> appPrepayIdCreateSign(String appId, String partnerId, String prepayId, String partnerKey, SignType signType) {
Map<String, String> packageParams = new HashMap<>(8);
packageParams.put("appid", appId);
packageParams.put("partnerid", partnerId);
packageParams.put("prepayid", prepayId);
packageParams.put("package", "Sign=WXPay");
packageParams.put("noncestr", String.valueOf(System.currentTimeMillis()));
packageParams.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
if (signType == null) {
signType = SignType.MD5;
}
String packageSign = createSign(packageParams, partnerKey, signType);
packageParams.put("sign", packageSign);
return packageParams;
}
/**
* App 调起支付签名
*
* @param appId 应用编号
* @param partnerId 商户编号
* @param prepayId 预付订单号
* @param keyPath key.pem 证书路径
* @return 唤起支付需要的参数
* @throws Exception 错误信息
*/
public static Map<String, String> appCreateSign(String appId, String partnerId, String prepayId, String keyPath) throws Exception {
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = String.valueOf(System.currentTimeMillis());
Map<String, String> packageParams = new HashMap<>(8);
packageParams.put("appid", appId);
packageParams.put("partnerid", partnerId);
packageParams.put("prepayid", prepayId);
packageParams.put("package", "Sign=WXPay");
packageParams.put("timestamp", timeStamp);
packageParams.put("noncestr", nonceStr);
packageParams.put("signType", SignType.RSA.toString());
ArrayList<String> list = new ArrayList<>();
list.add(appId);
list.add(timeStamp);
list.add(nonceStr);
list.add(prepayId);
String packageSign = PayKit.createSign(
PayKit.buildSignMessage(list),
keyPath
);
packageParams.put("sign", packageSign);
return packageParams;
}
/**
* <p>小程序-预付订单再次签名</p>
* <p>注意此处签名方式需与统一下单的签名类型一致</p>
*
* @param appId 应用编号
* @param prepayId 预付订单号
* @param partnerKey API Key
* @param signType 签名方式
* @return 再次签名后的 Map
*/
public static Map<String, String> miniAppPrepayIdCreateSign(String appId, String prepayId, String partnerKey, SignType signType) {
Map<String, String> packageParams = new HashMap<>(6);
packageParams.put("appId", appId);
packageParams.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
packageParams.put("nonceStr", String.valueOf(System.currentTimeMillis()));
packageParams.put("package", "prepay_id=" + prepayId);
if (signType == null) {
signType = SignType.MD5;
}
packageParams.put("signType", signType.getType());
String packageSign = createSign(packageParams, partnerKey, signType);
packageParams.put("paySign", packageSign);
return packageParams;
}
/**
* 构建 v3 接口所需的 Authorization
*
* @param method {@link RequestMethod} 请求方法
* @param urlSuffix 可通过 WxApiType 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param keyPath key.pem 证书路径
* @param body 接口请求参数
* @param nonceStr 随机字符库
* @param timestamp 时间戳
* @param authType 认证类型
* @return {@link String} 返回 v3 所需的 Authorization
* @throws Exception 异常信息
*/
public static String buildAuthorization(RequestMethod method, String urlSuffix, String mchId,
String serialNo, String keyPath, String body, String nonceStr,
long timestamp, String authType) throws Exception {
// 构建签名参数
String buildSignMessage = PayKit.buildSignMessage(method, urlSuffix, timestamp, nonceStr, body);
String signature = PayKit.createSign(buildSignMessage, keyPath);
// 根据平台规则生成请求头 authorization
return PayKit.getAuthorization(mchId, serialNo, nonceStr, String.valueOf(timestamp), signature, authType);
}
/**
* 构建 v3 接口所需的 Authorization
*
* @param method {@link RequestMethod} 请求方法
* @param urlSuffix 可通过 WxApiType 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param privateKey 商户私钥
* @param body 接口请求参数
* @param nonceStr 随机字符库
* @param timestamp 时间戳
* @param authType 认证类型
* @return {@link String} 返回 v3 所需的 Authorization
* @throws Exception 异常信息
*/
public static String buildAuthorization(RequestMethod method, String urlSuffix, String mchId,
String serialNo, PrivateKey privateKey, String body, String nonceStr,
long timestamp, String authType) throws Exception {
// 构建签名参数
String buildSignMessage = PayKit.buildSignMessage(method, urlSuffix, timestamp, nonceStr, body);
String signature = PayKit.createSign(buildSignMessage, privateKey);
// 根据平台规则生成请求头 authorization
return PayKit.getAuthorization(mchId, serialNo, nonceStr, String.valueOf(timestamp), signature, authType);
}
/**
* 构建 v3 接口所需的 Authorization
*
* @param method {@link RequestMethod} 请求方法
* @param urlSuffix 可通过 WxApiType 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param keyPath key.pem 证书路径
* @param body 接口请求参数
* @return {@link String} 返回 v3 所需的 Authorization
* @throws Exception 异常信息
*/
public static String buildAuthorization(RequestMethod method, String urlSuffix, String mchId,
String serialNo, String keyPath, String body) throws Exception {
long timestamp = System.currentTimeMillis() / 1000;
String authType = "WECHATPAY2-SHA256-RSA2048";
String nonceStr = PayKit.generateStr();
return buildAuthorization(method, urlSuffix, mchId, serialNo, keyPath, body, nonceStr, timestamp, authType);
}
/**
* 构建 v3 接口所需的 Authorization
*
* @param method {@link RequestMethod} 请求方法
* @param urlSuffix 可通过 WxApiType 来获取,URL挂载参数需要自行拼接
* @param mchId 商户Id
* @param serialNo 商户 API 证书序列号
* @param privateKey key.pem 证书路径
* @param body 接口请求参数
* @return {@link String} 返回 v3 所需的 Authorization
* @throws Exception 异常信息
*/
public static String buildAuthorization(RequestMethod method, String urlSuffix, String mchId,
String serialNo, PrivateKey privateKey, String body) throws Exception {
long timestamp = System.currentTimeMillis() / 1000;
String authType = "WECHATPAY2-SHA256-RSA2048";
String nonceStr = PayKit.generateStr();
return buildAuthorization(method, urlSuffix, mchId, serialNo, privateKey, body, nonceStr, timestamp, authType);
}
/**
* 验证签名
*
* @param map 接口请求返回的 Map
* @param certPath 平台证书路径
* @return 签名结果
* @throws Exception 异常信息
*/
@Deprecated
public static boolean verifySignature(Map<String, Object> map, String certPath) throws Exception {
String signature = (String) map.get("signature");
String body = (String) map.get("body");
String nonceStr = (String) map.get("nonceStr");
String timestamp = (String) map.get("timestamp");
return verifySignature(signature, body, nonceStr, timestamp, FileUtil.getInputStream(certPath));
}
/**
* 验证签名
*
* @param response 接口请求返回的 {@link WxHttpResponse}
* @param certPath 平台证书路径
* @return 签名结果
* @throws Exception 异常信息
*/
public static boolean verifySignature(WxHttpResponse response, String certPath) throws Exception {
String timestamp = response.getHeader("Wechatpay-Timestamp");
String nonceStr = response.getHeader("Wechatpay-Nonce");
String signature = response.getHeader("Wechatpay-Signature");
String body = response.getBody();
return verifySignature(signature, body, nonceStr, timestamp, FileUtil.getInputStream(certPath));
}
/**
* 验证签名
*
* @param response 接口请求返回的 {@link WxHttpResponse}
* @param certInputStream 平台证书
* @return 签名结果
* @throws Exception 异常信息
*/
public static boolean verifySignature(WxHttpResponse response, InputStream certInputStream) throws Exception {
String timestamp = response.getHeader("Wechatpay-Timestamp");
String nonceStr = response.getHeader("Wechatpay-Nonce");
String signature = response.getHeader("Wechatpay-Signature");
String body = response.getBody();
return verifySignature(signature, body, nonceStr, timestamp, certInputStream);
}
/**
* 验证签名
*
* @param map 接口请求返回的 Map
* @param certInputStream 平台证书输入流
* @return 签名结果
* @throws Exception 异常信息
*/
@Deprecated
public static boolean verifySignature(Map<String, Object> map, InputStream certInputStream) throws Exception {
String signature = (String) map.get("signature");
String body = (String) map.get("body");
String nonceStr = (String) map.get("nonceStr");
String timestamp = (String) map.get("timestamp");
return verifySignature(signature, body, nonceStr, timestamp, certInputStream);
}
/**
* 验证签名
*
* @param signature 待验证的签名
* @param body 应答主体
* @param nonce 随机串
* @param timestamp 时间戳
* @param publicKey 微信支付平台公钥
* @return 签名结果
* @throws Exception 异常信息
*/
public static boolean verifySignature(String signature, String body, String nonce, String timestamp, String publicKey) throws Exception {
String buildSignMessage = PayKit.buildSignMessage(timestamp, nonce, body);
return RsaKit.checkByPublicKey(buildSignMessage, signature, publicKey);
}
/**
* 验证签名
*
* @param signature 待验证的签名
* @param body 应答主体
* @param nonce 随机串
* @param timestamp 时间戳
* @param publicKey {@link PublicKey} 微信支付平台公钥
* @return 签名结果
* @throws Exception 异常信息
*/
public static boolean verifySignature(String signature, String body, String nonce, String timestamp, PublicKey publicKey) throws Exception {
String buildSignMessage = PayKit.buildSignMessage(timestamp, nonce, body);
return RsaKit.checkByPublicKey(buildSignMessage, signature, publicKey);
}
/**
* 验证签名
*
* @param signature 待验证的签名
* @param body 应答主体
* @param nonce 随机串
* @param timestamp 时间戳
* @param certInputStream 微信支付平台证书输入流
* @return 签名结果
* @throws Exception 异常信息
*/
public static boolean verifySignature(String signature, String body, String nonce, String timestamp, InputStream certInputStream) throws Exception {
String buildSignMessage = PayKit.buildSignMessage(timestamp, nonce, body);
// 获取证书
X509Certificate certificate = PayKit.getCertificate(certInputStream);
PublicKey publicKey = certificate.getPublicKey();
return RsaKit.checkByPublicKey(buildSignMessage, signature, publicKey);
}
/**
* v3 支付异步通知验证签名
*
* @param serialNo 证书序列号
* @param body 异步通知密文
* @param signature 签名
* @param nonce 随机字符串
* @param timestamp 时间戳
* @param key api 密钥
* @param certInputStream 平台证书
* @return 异步通知明文
* @throws Exception 异常信息
*/
public static String verifyNotify(String serialNo, String body, String signature, String nonce,
String timestamp, String key, InputStream certInputStream) throws Exception {
// 获取平台证书序列号
X509Certificate certificate = PayKit.getCertificate(certInputStream);
String serialNumber = certificate.getSerialNumber().toString(16).toUpperCase();
System.out.println(serialNumber);
// 验证证书序列号
if (serialNumber.equals(serialNo)) {
boolean verifySignature = WxPayKit.verifySignature(signature, body, nonce, timestamp,
certificate.getPublicKey());
if (verifySignature) {
JSONObject resultObject = JSONUtil.parseObj(body);
JSONObject resource = resultObject.getJSONObject("resource");
String cipherText = resource.getStr("ciphertext");
String nonceStr = resource.getStr("nonce");
String associatedData = resource.getStr("associated_data");
AesUtil aesUtil = new AesUtil(key.getBytes(StandardCharsets.UTF_8));
// 密文解密
return aesUtil.decryptToString(
associatedData.getBytes(StandardCharsets.UTF_8),
nonceStr.getBytes(StandardCharsets.UTF_8),
cipherText
);
} else {
throw new Exception("签名错误");
}
} else {
throw new Exception("证书序列号错误");
}
}
/**
* v3 支付异步通知验证签名
*
* @param serialNo 证书序列号
* @param body 异步通知密文
* @param signature 签名
* @param nonce 随机字符串
* @param timestamp 时间戳
* @param key api 密钥
* @param certPath 平台证书路径
* @return 异步通知明文
* @throws Exception 异常信息
*/
public static String verifyNotify(String serialNo, String body, String signature, String nonce,
String timestamp, String key, String certPath) throws Exception {
BufferedInputStream inputStream = FileUtil.getInputStream(certPath);
return verifyNotify(serialNo, body, signature, nonce, timestamp, key, inputStream);
}
}
package com.smart.hospital.common.pay.util;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
/**
* xpath解析xml
*
* <pre>
* 文档地址:
* http://www.w3school.com.cn/xpath/index.asp
* </pre>
* @author L.cm
*/
public class XmlHelper {
private final XPath path;
private final Document doc;
private XmlHelper(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory dbf = getDocumentBuilderFactory();
// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all
// XML entity attacks are prevented
// Xerces 2 only -
// http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// If you can't completely disable DTDs, then at least do the following:
// Xerces 1 -
// http://xerces.apache.org/xerces-j/features.html#external-general-entities
// Xerces 2 -
// http://xerces.apache.org/xerces2-j/features.html#external-general-entities
// JDK7+ - http://xml.org/sax/features/external-general-entities
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
// Xerces 1 -
// http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
// Xerces 2 -
// http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
// JDK7+ - http://xml.org/sax/features/external-parameter-entities
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
// Disable external DTDs as well
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and
// Entity Attacks"
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(inputSource);
path = getXpathFactory().newXPath();
}
private static XmlHelper create(InputSource inputSource) {
try {
return new XmlHelper(inputSource);
} catch (ParserConfigurationException | SAXException | IOException e) {
throw new RuntimeException(e);
}
}
public static XmlHelper of(InputStream is) {
InputSource inputSource = new InputSource(is);
return create(inputSource);
}
public static XmlHelper of(File file) {
InputSource inputSource = new InputSource(file.toURI().toASCIIString());
return create(inputSource);
}
public static XmlHelper of(String xmlStr) {
StringReader sr = new StringReader(xmlStr.trim());
InputSource inputSource = new InputSource(sr);
XmlHelper xmlHelper = create(inputSource);
sr.close();
return xmlHelper;
}
private Object evalXpath(String expression, Object item, QName returnType) {
item = null == item ? doc : item;
try {
return path.evaluate(expression, item, returnType);
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
}
}
/**
* 获取String
*
* @param expression 路径
* @return String
*/
public String getString(String expression) {
return (String) evalXpath(expression, null, XPathConstants.STRING);
}
/**
* 获取Boolean
*
* @param expression 路径
* @return String
*/
public Boolean getBoolean(String expression) {
return (Boolean) evalXpath(expression, null, XPathConstants.BOOLEAN);
}
/**
* 获取Number
*
* @param expression 路径
* @return {Number}
*/
public Number getNumber(String expression) {
return (Number) evalXpath(expression, null, XPathConstants.NUMBER);
}
/**
* 获取某个节点
*
* @param expression 路径
* @return {Node}
*/
public Node getNode(String expression) {
return (Node) evalXpath(expression, null, XPathConstants.NODE);
}
/**
* 获取子节点
*
* @param expression 路径
* @return NodeList
*/
public NodeList getNodeList(String expression) {
return (NodeList) evalXpath(expression, null, XPathConstants.NODESET);
}
/**
* 获取String
*
* @param node 节点
* @param expression 相对于node的路径
* @return String
*/
public String getString(Object node, String expression) {
return (String) evalXpath(expression, node, XPathConstants.STRING);
}
/**
* 获取
*
* @param node 节点
* @param expression 相对于node的路径
* @return String
*/
public Boolean getBoolean(Object node, String expression) {
return (Boolean) evalXpath(expression, node, XPathConstants.BOOLEAN);
}
/**
* 获取
*
* @param node 节点
* @param expression 相对于node的路径
* @return {Number}
*/
public Number getNumber(Object node, String expression) {
return (Number) evalXpath(expression, node, XPathConstants.NUMBER);
}
/**
* 获取某个节点
*
* @param node 节点
* @param expression 路径
* @return {Node}
*/
public Node getNode(Object node, String expression) {
return (Node) evalXpath(expression, node, XPathConstants.NODE);
}
/**
* 获取子节点
*
* @param node 节点
* @param expression 相对于node的路径
* @return NodeList
*/
public NodeList getNodeList(Object node, String expression) {
return (NodeList) evalXpath(expression, node, XPathConstants.NODESET);
}
/**
* 针对没有嵌套节点的简单处理
*
* @return map集合
*/
public Map<String, String> toMap() {
Element root = doc.getDocumentElement();
// 将节点封装成map形式
NodeList list = root.getChildNodes();
Map<String, String> params = new HashMap<String, String>(list.getLength());
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
params.put(node.getNodeName(), node.getTextContent());
}
// 含有空白符会生成一个#text参数
params.remove("#text");
return params;
}
private static DocumentBuilderFactory getDocumentBuilderFactory() {
return XmlHelperHolder.documentBuilderFactory;
}
private static XPathFactory getXpathFactory() {
return XmlHelperHolder.xPathFactory;
}
/**
* 内部类单例
*/
private static class XmlHelperHolder {
private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
private static XPathFactory xPathFactory = XPathFactory.newInstance();
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.smart.hospital.common.pay.PayAutoConfiguration
fxkcfxkcfxkcfxkcfxkcfxkcfxkcfxkc
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIID9jCCAt6gAwIBAgIUcmxYCz0Y2KqLbgd/db4LgpfSdPYwDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
Q0EwHhcNMjExMjA4MTEwNjQ4WhcNMjYxMjA3MTEwNjQ4WjCBhzETMBEGA1UEAwwK
MTYwMDgxNjYyMDEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTMwMQYDVQQL
DCrmuZbljJfnpo/pkavnp5HliJvkv6Hmga/mioDmnK/mnInpmZDlhazlj7gxCzAJ
BgNVBAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAKWgHAyl0joojJsyyvKhp65RyHE9BAbJjNmKUeK5zJga2e/L
UVDjzn/+eY4dVl5UtomNn1qZGk8sMPKM/0srHhD4tjdCY2ratzgURg5onX9Fhxit
Xu/MBRRjZEmTedPboJSYmiRHIx0Xqh1q1RM4YCnVxDjzzpkmrNOe95Ad6M2qe0ba
9xypyfeOAnNA7Y/vSGlLsZxa7BeViH2pjzGb+lFDjoA5sH9SAOYGqUBK1Zi8032g
UdC6pRs3vZFjIZ/akkgL8UEi2eId5zHnT8EEukbCi9KUBBpW7QlinpQWrFQisxGh
p4kudBN23pea1+/wiU1Aq8inR9SIiey5ldizYFcCAwEAAaOBgTB/MAkGA1UdEwQC
MAAwCwYDVR0PBAQDAgTwMGUGA1UdHwReMFwwWqBYoFaGVGh0dHA6Ly9ldmNhLml0
cnVzLmNvbS5jbi9wdWJsaWMvaXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2
QUQzOTc1NDk4NDZDMDFDM0U4RUJEMjANBgkqhkiG9w0BAQsFAAOCAQEAeMf+5BXz
w5BK47Rt0i8+yTMLX3FPV++rKZYGOxhLSctXARzhkZ44xsSRFz9wRHH1g1LsSy08
Nhnna4SDQ8rdKfNqrRQP4B0rz1aMxjxdhx/zBN/l8G3l7nswhKxGxu3haLWGzv3I
ugEpKjScJqlKoBNVFNq9HY/cQgBrP9YF8jnW1ivsG386/GzEOT8T0nKLc/umLDiF
kzjB8e6MzPqRetmpcLO6uJSpQl4ALUWrs04teetkNUmJFhTOJzkYazvDkvIlurC2
Ynif0xVyCMpL1rnoB4MvRvDXpfJLh+gIBR2KD2Ab0z6hSxEs1xTAWzN76oXs7viQ
HqMAUJYN6fx6Wg==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCloBwMpdI6KIyb
MsryoaeuUchxPQQGyYzZilHiucyYGtnvy1FQ485//nmOHVZeVLaJjZ9amRpPLDDy
jP9LKx4Q+LY3QmNq2rc4FEYOaJ1/RYcYrV7vzAUUY2RJk3nT26CUmJokRyMdF6od
atUTOGAp1cQ4886ZJqzTnveQHejNqntG2vccqcn3jgJzQO2P70hpS7GcWuwXlYh9
qY8xm/pRQ46AObB/UgDmBqlAStWYvNN9oFHQuqUbN72RYyGf2pJIC/FBItniHecx
50/BBLpGwovSlAQaVu0JYp6UFqxUIrMRoaeJLnQTdt6Xmtfv8IlNQKvIp0fUiIns
uZXYs2BXAgMBAAECggEAM+N5Ziz9M+NISccb9e/XTLGqjm+DN20lh3HiPZngEzc2
V/3mt+Tm6Qqcon1mdZ8soOORrRySNYOuwg6SXMZhYQfKbn2KEAv9osAXQqRb02fA
72ZBe/b7EGwjGznszQbdxDAa+oqe4ZpsXVL+9kqPNgwWsZEQhMKtGo+PF8OHEAd7
ypEK8KwnBtHJ59NHfLe/F3j4nIoXsNP5FLjZiYmzI3dxuItMfv0GniA3gp4MewBQ
Tj1u7WG3sPTlveU+DgZsV6JWDWyWDzbSTnxzj0tIKySy+8AuDOx4dmobO2tCj6K4
2OOH4x2W1mm5lJU4foLmeGVLk0hEmEoA8IXMhLuwoQKBgQDcsjeUJZqbSPt5mNm4
7gP2gNQVILupvdglCnNsT0E+mlLGzY8qF2r14W//dCAb9Py2Dg8Db5DNRGCwLYEb
spZouweOJGhA1t9zREVE6o2pgPQJ6u4/tLfzCip3xtuK3IopPN2H6pXgzEmjIvNa
5kEN5LOejt32C8lx3WNdj6l89QKBgQDAHq1kcJytRfpP4KwjoC7mlx975ZG9meGS
nyA2tDsnrQiOC2DMmVugf72LSiCpd7PODjFvXFFUVvUXoRcWywwTO1dON+CCDgag
Jk367mszza0EEZn5f5LXDLP3c+00LvbXyb1H++QCZVfS/fh4J1Fb2OspvwAINsja
lZyUBU7YmwKBgHYqbhvCbp+KWitnLdwYhMKtg+C0IAbogRyEFfz+Cn8Mfhm34lm1
JC32wNLUSITvjYeky2EZkTx2yhZKpwA/hM0apxbyY2ekJQxAl54owCTryL6urVYq
2vskjEyJiu802jzuO+cUMZ+lgh/5DLe05UwdEhdpg2rEMN3ondVwoF0pAoGAHs0M
SX0QcWs1rVa84l1NB6UU5B0zF22zT3l5hauxjDPemj9SvpqbqQixz8ILqH/LcO6v
mEX5uAbU9nvaIspc3jx2S9EDinZLM6PQfrl4sG56HZvgzrJYTWf49mQ8lFAvPPtY
AFFvBb9PrEERc9oB3jLRyPiZPbfizcCMwOJ0+J8CgYEA1oum68XiSs2whM1KaprB
S+fVQ0NnPzb75zpE0acz6AtdVTcMcXwHs+GjRDp2US2Yaqn0EGRc531sNKWj6VAC
DiwwbUX4RVcMPrdQ4QQwoLKihaahgemKJEyFTfJ9H3B09ZbxaUQ38sYkDEMN5WNo
tLXru6iCtkU2l2dF652YxpY=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIID3DCCAsSgAwIBAgIUNRtfU6XfI/zGgY08O/bdzqRWQVAwDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
Q0EwHhcNMjAwNzA4MDU1MzM1WhcNMjUwNzA3MDU1MzM1WjBuMRgwFgYDVQQDDA9U
ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl
bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo
ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx89u21vSoaIB62QPw
QfL6v/cuWqB+jYQEtZ7G1bgP78aHYi1QLwXYMyrD4Buelgh4EvkZYpMG+HJwqBUu
0fGWFGlpfgHL1F7bAZPBZPn1dDln4S9NPltExwsnYhwjSBvohpFmlL+IdmIN3foL
/XzLykAxqgjHfXA/8bVf7Cin9wvtXFKBY7EtKYhe4xmZvYQroN9uLsLaur6abXIU
yVXItly5Ml/j5rFLIAUey7P5g4NqQXx+XK07AlBiQ8G6f4WcX5YRxHyV74T3a1AX
+7RdClvwnCODKOLa6+104bsk68Wf2tkq1ONEsUFK0q9cmqJ117Qvt5dMZ1Sr1WwM
jgfDAgMBAAGjgYEwfzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE8DBlBgNVHR8EXjBc
MFqgWKBWhlRodHRwOi8vZXZjYS5pdHJ1cy5jb20uY24vcHVibGljL2l0cnVzY3Js
P0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFEMzk3NTQ5ODQ2QzAxQzNFOEVCRDIwDQYJ
KoZIhvcNAQELBQADggEBALVlpWMFw6TAiTyQ588GYxKvbXesku1irfdMyS1mKqVC
HKtwOYp84vWT8fjXc2nZRECJfLVslOQf719J0doPNIfLyiLOM3FBZLmy4aC82ILG
A112wWLv8v3E5HH/GtW323dIwz3JKWVLbk+iAn1QJlT7HoLal84XlCVJZ2QStIpM
9zotT5RloinSxCq5y522vEtvQIhMY3yyQmMBC10A6YFUft4+eTwru36HlU+Cl+tr
zaoAT1FyoHx4zR6dGAbxp+tNgZjg+ZwfZXZlwzhDtNwwfX0Yv/0UP5sQ/ih1OuMC
f1yHDu8N0S2NZJadZZXgSzwoeqJZQlXmEe3VnEitbDc=
-----END CERTIFICATE-----
\ No newline at end of file
......@@ -102,10 +102,6 @@
<groupId>com.smart.hospital</groupId>
<artifactId>smart-common-mq</artifactId>
</dependency>
<dependency>
<groupId>com.smart.hospital</groupId>
<artifactId>smart-common-pay</artifactId>
</dependency>
</dependencies>
<build>
......
package com.smart.hospital.admin.controller.upms;
import cn.hutool.core.util.StrUtil;
import com.smart.hospital.common.core.util.R;
import com.smart.hospital.common.pay.client.PayClient;
import com.smart.hospital.common.pay.model.*;
import com.smart.hospital.common.pay.util.PayKit;
import com.smart.hospital.common.security.annotation.Inner;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Api(value = "支付测试", tags = {"支付测试"})
@RestController
@AllArgsConstructor
@RequestMapping("/pay")
public class PayController {
@Autowired
PayClient payClient;
@Inner(value = false)
@ApiOperation(value = "支付")
@GetMapping(value = "/do")
public R pay() {
return R.ok(payClient.wxJsapiPay(new WxUnifiedOrderModel()
.setDescription("支付测试")
.setOut_trade_no(PayKit.generateStr())
.setAttach("挂号支付测试")
.setAmount(new Amount().setTotal(1))
.setPayer(new Payer().setOpenid("oRkq_4okxD_JqZxcElrifwJe5jEs"))));
}
@Inner(value = false)
@ApiOperation(value = "退款")
@GetMapping(value = "/refund")
public R refund(@RequestParam(required = false) String transactionId, @RequestParam(required = false) String outTradeNo) {
String outRefundNo = PayKit.generateStr();
log.info("商户退款单号: {}", outRefundNo);
List<WxRefundGoodsDetail> list = new ArrayList<>();
WxRefundGoodsDetail refundGoodsDetail = new WxRefundGoodsDetail()
.setMerchant_goods_id("123")
.setGoods_name("测试退款")
.setUnit_price(1)
.setRefund_amount(1)
.setRefund_quantity(1);
list.add(refundGoodsDetail);
WxRefundModel refundModel = new WxRefundModel()
.setOut_refund_no(outRefundNo)
.setReason("测试退款")
.setAmount(new WxRefundAmount().setRefund(1).setTotal(1).setCurrency("CNY"))
.setGoods_detail(list);
if (StrUtil.isNotEmpty(transactionId)) {
refundModel.setTransaction_id(transactionId);
}
if (StrUtil.isNotEmpty(outTradeNo)) {
refundModel.setOut_trade_no(outTradeNo);
}
return R.ok(payClient.wxRefund(refundModel));
}
@Inner(value = false)
@ApiOperation(value = "获取平台证书")
@GetMapping(value = "/cert")
public R cert() {
return R.ok(payClient.wxPlatformCert());
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment