赞
踩
1.配置沙箱密钥并获取沙箱账号密码
1)打开支付宝开放平台主页https://open.alipay.com/platform/home.htm并登陆
2)打开https://opendocs.alipay.com/open/291/105971下载密钥生成工具
3)生成密钥(应用私钥就是下面alipay.properties中的merchantPrivateKey)
4)打开https://openhome.alipay.com/platform/appDaily.htm?tab=info设置支付宝公钥
下面是我已经设置好的
将应用公钥复制上去生成的支付宝公钥就是alipay.properties中的alipayPublicKey
5)记住沙箱账号密码
准备工作完成,接下来创建java工程
工程目录结构
pom.xml
<?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"> <modelVersion>4.0.0</modelVersion> <groupId>com.wl.alipay</groupId> <artifactId>alipay</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring-boot-version>2.0.8.RELEASE</spring-boot-version> <slf4j-api-version>1.7.5</slf4j-api-version> <commons-lang-version>3.6</commons-lang-version> <MainClass>com.wl.alipay.PayApplication</MainClass> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk --> <dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-easysdk</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring-boot-version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j-api-version}</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang-version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>${spring-boot-version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot-version}</version> <configuration> <mainClass>${MainClass}</mainClass> <layout>JAR</layout> </configuration> <!-- repackage 生成两个 jar.original --> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> <!-- 指定maven 打包java 版本 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> <!-- maven 编译打包resource 和 java 目录下所有文件 maven默认资源路径是resources --> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.*</include> <include>*.*</include> </includes> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.*</include> <include>*.*</include> </includes> </resource> </resources> </build> </project>
application.properties
server.port=80
alipay.properties
启动类
package com.wl.alipay; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; /** * Created by Administrator on 2020/12/9. */ @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class //不使用数据库 },scanBasePackages = "com.wl") public class PayApplication { public static void main(String[] args) { SpringApplication app = new SpringApplication(PayApplication.class); app.setWebApplicationType(WebApplicationType.SERVLET); app.run(args); } }
config
package com.wl.alipay.config; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.PropertiesFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import java.io.IOException; import java.util.Properties; /** * Created by Administrator on 2020/12/5. */ @Configuration public class AliPayConfig { private static final Logger logger = LoggerFactory.getLogger(AliPayConfig.class); @Bean public Properties aliPayProperties() throws IOException{ PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); propertiesFactoryBean.setLocation(new ClassPathResource("/alipay.properties")); propertiesFactoryBean.afterPropertiesSet(); return propertiesFactoryBean.getObject(); } }
package com.wl.alipay.config; /** * Created by Administrator on 2020/12/5. */ public class AliPayConstant { public static final String appId = "appId"; public static final String alipayPublicKey = "alipayPublicKey"; public static final String merchantCertPath = "merchantCertPath"; public static final String alipayCertPath = "alipayCertPath"; public static final String alipayRootCertPath = "alipayRootCertPath"; public static final String gatewayHost = "gatewayHost"; public static final String protocol = "protocol"; public static final String signType = "signType"; public static final String merchantPrivateKey = "merchantPrivateKey"; public static final String notifyUrl = "notifyUrl"; public static final String encryptKey = "encryptKey"; public static final String timeoutExpress = "timeoutExpress"; public static final String webReturnUrl = "webReturnUrl"; }
关键的服务类
package com.wl.alipay.service; //import com.alipay.easysdk.payment.app.models.AlipayTradeAppPayResponse; import com.alipay.easysdk.factory.Factory; import com.alipay.easysdk.kernel.Config; import com.alipay.easysdk.payment.app.models.AlipayTradeAppPayResponse; import com.alipay.easysdk.payment.common.models.*; import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse; import com.alipay.easysdk.payment.wap.models.AlipayTradeWapPayResponse; import com.wl.alipay.config.AliPayConstant; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Properties; /** * Created by Administrator on 2019/8/2. */ @Service public class AliPayService { private static final Logger logger = LoggerFactory.getLogger(AliPayService.class); private Properties aliPayProperties; @Autowired public AliPayService(Properties aliPayProperties){ this.aliPayProperties =aliPayProperties; //设置Factory 全局参数 { Config config = new Config(); config.appId = aliPayProperties.getProperty(AliPayConstant.appId); if(StringUtils.isNotBlank(aliPayProperties.getProperty(AliPayConstant.alipayPublicKey))) { config.alipayPublicKey = aliPayProperties.getProperty(AliPayConstant.alipayPublicKey); }else{ //如果采用非证书模式,则无需赋值下面的三个证书路径,改为赋值如上的支付宝公钥字符串即可 String merchantCertPath = aliPayProperties.getProperty(AliPayConstant.merchantCertPath); String alipayCertPath = aliPayProperties.getProperty(AliPayConstant.alipayCertPath); String alipayRootCertPath = aliPayProperties.getProperty(AliPayConstant.alipayRootCertPath); if(StringUtils.isNotBlank(merchantCertPath) && StringUtils.isNotBlank(alipayCertPath) && StringUtils.isNotBlank(alipayRootCertPath)){ config.merchantCertPath = merchantCertPath; config.alipayCertPath = merchantCertPath; config.alipayRootCertPath = alipayRootCertPath; }else { logger.error("merchantCertPath:{},alipayCertPath:{},alipayRootCertPath:{}" ,merchantCertPath,alipayCertPath,alipayRootCertPath); } } config.gatewayHost = aliPayProperties.getProperty(AliPayConstant.gatewayHost); config.protocol = aliPayProperties.getProperty(AliPayConstant.protocol); config.signType = aliPayProperties.getProperty(AliPayConstant.signType); config.merchantPrivateKey = aliPayProperties.getProperty(AliPayConstant.merchantPrivateKey); config.notifyUrl = aliPayProperties.getProperty(AliPayConstant.notifyUrl); //可设置AES密钥,调用AES加解密相关接口时需要(可选) config.encryptKey = aliPayProperties.getProperty(AliPayConstant.encryptKey); Factory.setOptions(config); } } /** * 对应 alipay.trade.app.pay 接口 * 构造交易数据供商户app到支付宝下单 */ public AlipayTradeAppPayResponse createAppTradeForm(String subject ,String tradeNo,String totalAmount) throws Exception { return Factory.Payment.App() //单独设置超时时间 默认15分钟 .optional("timeout_express",aliPayProperties.getProperty(AliPayConstant.timeoutExpress,"15m")) .pay(subject,tradeNo,totalAmount); } /** * 对应alipay.trade.page.pay 接口 * 构造交易数据供pc端到支付宝下单 */ public AlipayTradePagePayResponse createWebTradeForm(String subject ,String tradeNo,String totalAmount,String returnUrl) throws Exception{ return Factory.Payment.Page() //单独设置超时时间 默认15分钟 .optional("timeout_express",aliPayProperties.getProperty(AliPayConstant.timeoutExpress,"15m")) .pay(subject,tradeNo,totalAmount, returnUrl); } /** * alipay.trade.wap.pay * 构造交易数据供wap端到支付宝下单 */ public AlipayTradeWapPayResponse createWapTradeForm(String subject , String tradeNo, String totalAmount,String quitUrl, String returnUrl) throws Exception{ return Factory.Payment.Wap() //单独设置超时时间 默认15分钟 .optional("timeout_express",aliPayProperties.getProperty(AliPayConstant.timeoutExpress,"15m")) .pay(subject,tradeNo,totalAmount,quitUrl ,returnUrl); } /** * 对应alipay.trade.query(统一收单线下交易查询) */ public AlipayTradeQueryResponse queryTrade(String tradeNo) throws Exception { return Factory.Payment.Common().query(tradeNo); } /** * alipay.trade.cancel */ public AlipayTradeCancelResponse cancelTrade(String tradeNo) throws Exception{ return Factory.Payment.Common().cancel(tradeNo); } /** * alipay.trade.close(统一收单交易关闭接口) */ public AlipayTradeCloseResponse closeTrade(String tradeNo) throws Exception{ return Factory.Payment.Common().close(tradeNo); } /** * alipay.trade.refund(统一收单交易退款接口) */ public AlipayTradeRefundResponse refundTrade(String tradeNo,String refundAmount) throws Exception{ return Factory.Payment.Common().refund(tradeNo,refundAmount); } /** * alipay.trade.fastpay.refund.query(统一收单交易退款查询) */ public AlipayTradeFastpayRefundQueryResponse refundQuery(String tradeNo,String outRequestNo) throws Exception{ return Factory.Payment.Common().queryRefund(tradeNo,outRequestNo); } }
注意以上几个接口只带了几个必要的参数,如果想要设置更多的请求参数,可以使用对应Client的batchOptional或optional方法设置(在下面会讲如何设置复杂的参数)
下面仅以pc端支付测试(使用app端支付测试需要与app开发人员联调)
新建AliPayController
package com.wl.alipay.controller; import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse; import com.wl.alipay.service.AliPayService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Created by Administrator on 2020/12/9. */ @RestController @RequestMapping("/api/alipay/") public class AliPayController { private AliPayService aliPayService; @Autowired public AliPayController(AliPayService aliPayService){ this.aliPayService = aliPayService; } @RequestMapping("createWebTrade") public void createWebTrade(HttpServletResponse response) throws Exception{ String tradeNo = "20150320011541010101"; String subject = "iphone11 128G"; String totalAmount = "0.1"; String returnUrl = "http://localhost/api/alipay/webReturnUrl"; AlipayTradePagePayResponse pagePayResponse = aliPayService.createWebTradeForm(tradeNo,subject,totalAmount,returnUrl); response.setContentType("text/html;charset=utf-8"); response.getWriter().write(pagePayResponse.getBody());// 直接将完整的表单html输出到页面 response.getWriter().flush(); response.getWriter().close(); } @RequestMapping(value = "webReturnUrl",method = RequestMethod.GET) public Object webTradeReturnUrl(HttpServletRequest request){ System.out.println(request.getParameterMap()); return request.getParameterMap(); } }
访问http://localhost/api/alipay/createWebTrade即可跳到支付页面
支付成功后同步返回数据到http://localhost/api/alipay/webReturnUrl(支付宝推荐以异步回调通知为准)
启动项目
访问http://localhost/api/alipay/createWebTrade 如下
使用之前的沙箱帐户名和密码登陆
输入支付密码并确认付款
最后跳转到后台页面返回数据
测试成功
上面AliPayService中的参数都是alipay-easysdk中必须的参数,众所周知alipay的参数少则几个多则数十个,显然上面的接口是没法满足我们个性化需求的。下面介绍如何设置可选的参数
还是以alipay.trade.page.pay接口为例,参考alipay文档 我们将所有参数封装到对象里面去
参考alipay-sdk-java jar包中 com.alipay.api.domain包下的AlipayTradePagePayModel类
新建注解
package com.wl.alipay.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by Administrator on 2020/12/5. */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.METHOD}) public @interface NameInMap { /** * 支付宝请求参数中可选map中的key 例如 totalAmount 对应 total_amount */ String value(); /** * 数据类型(默认String) */ Class type() default String.class; }
一个请求对象里面有十几个小的对象实在是多
这里只贴CreateWebTradeRequest
package com.wl.alipay.domain; import com.wl.alipay.annotation.NameInMap; import java.io.Serializable; import java.util.List; /** * Created by Administrator on 2020/12/8. */ public class CreateWebTradeRequest implements Serializable{ /** * 支付成功后同步跳转的页面,是一个http/https开头的字符串(返回同步参数) * */ private String returnUrl; /** * 商户订单号 * 必填 */ private String tradeNo; /** * 销售产品码,与支付宝签约的产品码名称。注:目前电脑支付场景下仅支持FAST_INSTANT_TRADE_PAY * 必填 */ @NameInMap(value = "product_code") private String productCode; /** * 订单总金额,单位为元,精确到小数点后两位,取值范围为 [0.01,100000000]。金额不能为0 * 必填 */ private String totalAmount; /** * 订单标题 * 必填 */ private String subject; /** * 绝对超时时间,格式为 yyyy-MM-dd HH:mm:ss * 可选 */ @NameInMap(value = "time_expire") private String timeExpire; /** * 订单包含的商品列表信息,json数组格式,其它说明详见商品明细说明 * 可选 */ @NameInMap(value = "goods_detail",type = List.class) private List<GoodsDetail> goodsDetail; /** * 公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。 * 支付宝会在异步通知时将该参数原样返回。本参数必须进行 UrlEncode 之后才可以发送给支付宝。 * 可选 */ @NameInMap(value = "passback_params") private String passbackParams; /** * 业务扩展参数 json对象 * 可选 */ @NameInMap(value = "extend_params",type = ExtendParams.class) private ExtendParams extendParams; /** * 商品类型 0-虚拟类商品,1-实物类商品 注:虚拟类商品不支持使用花呗渠道 * 可选 */ @NameInMap(value = "goods_type") private String goodsType; /** * 优惠参数 注:仅与支付宝协商后可用 * 可选 maxLength 512 */ @NameInMap(value = "promo_params") private String promoParams; /** * 描述分账信息,json格式,详见分账参数说明 */ @NameInMap(value = "royalty_info",type = RoyaltyInfo.class) private RoyaltyInfo royaltyInfo; /** * 间连受理商户信息体,当前只对特殊银行机构特定场景下使用此字段 */ @NameInMap(value = "sub_merchant",type = SubMerchant.class) private SubMerchant subMerchant; /** * 商户原始订单号,最大长度限制32位 */ @NameInMap(value = "merchant_order_no") private String merchantOrderNo; /** * 可用渠道,用户只能在指定渠道范围内支付,多个渠道以逗号分割 * 注,与disable_pay_channels互斥 * 渠道列表:https://docs.open.alipay.com/common/wifww7 */ @NameInMap(value = "enable_pay_channels") private String enablePayChannels; /** * 商户门店编号 */ @NameInMap(value = "store_id") private String storeId; /** * 禁用渠道,用户不可用指定渠道支付,多个渠道以逗号分割 * 注,与enable_pay_channels互斥 * 渠道列表:https://docs.open.alipay.com/common/wifww7 */ @NameInMap(value = "disable_pay_channels") private String disablePayChannels; /** *PC扫码支付的方式,支持前置模式和 * 跳转模式。 * 前置模式是将二维码前置到商户 * 的订单确认页的模式。需要商户在 * 自己的页面中以 iframe 方式请求 * 支付宝页面。具体分为以下几种: * 0:订单码-简约前置模式,对应 iframe 宽度不能小于600px,高度不能小于300px; * 1:订单码-前置模式,对应iframe 宽度不能小于 300px,高度不能小于600px; * 3:订单码-迷你前置模式,对应 iframe 宽度不能小于 75px,高度不能小于75px; * 4:订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小。 * * 跳转模式下,用户的扫码界面是由支付宝生成的,不在商户的域名下。 * 2:订单码-跳转模式 */ @NameInMap(value = "qr_pay_mode") private String qrPayMode; /** * 商户自定义二维码宽度 * 注:qr_pay_mode=4时该参数生效 */ @NameInMap(value = "qrcode_width") private String qrcodeWidth; /** * 描述结算信息,json格式,详见结算参数说明 */ @NameInMap(value = "settle_info",type = SettleInfo.class) private SettleInfo settleInfo; /** * 开票信息 */ @NameInMap(value = "invoice_info",type = InvoiceInfo.class) private InvoiceInfo invoiceInfo; /** * 签约参数,支付后签约场景使用 与app的SingParams 参数大致相同 */ @NameInMap(value = "agreement_sign_params",type = AgreementSignParams.class) private AgreementSignParams agreementSignParams; /** * 请求后页面的集成方式。 * 取值范围: * 1. ALIAPP:支付宝钱包内 * 2. PCWEB:PC端访问 * 默认值为PCWEB。 */ @NameInMap(value = "integration_type") private String integrationType; /** * 请求来源地址。如果使用ALIAPP的集成方式,用户中途取消支付会返回该地址。 */ @NameInMap(value = "request_from_url") private String requestFromUrl; /** * 商户传入业务信息,具体值要和支付宝约定,应用于安全,营销等参数直传场景,格式为json格式 * https://opendocs.alipay.com/open/204/fx8ebu#%E9%9B%86%E6%88%90%E6%96%B9%E5%BC%8F */ @NameInMap(value = "business_params") private String businessParams; /** * 外部指定买家 * 可选 */ @NameInMap(value = "ext_user_info",type = ExtUserInfo.class) private ExtUserInfo extUserInfo; public String getReturnUrl() { return returnUrl; } public void setReturnUrl(String returnUrl) { this.returnUrl = returnUrl; } public String getTradeNo() { return tradeNo; } public void setTradeNo(String tradeNo) { this.tradeNo = tradeNo; } public String getProductCode() { return productCode; } public void setProductCode(String productCode) { this.productCode = productCode; } public String getTotalAmount() { return totalAmount; } public void setTotalAmount(String totalAmount) { this.totalAmount = totalAmount; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getTimeExpire() { return timeExpire; } public void setTimeExpire(String timeExpire) { this.timeExpire = timeExpire; } public List<GoodsDetail> getGoodsDetail() { return goodsDetail; } public void setGoodsDetail(List<GoodsDetail> goodsDetail) { this.goodsDetail = goodsDetail; } public String getPassbackParams() { return passbackParams; } public void setPassbackParams(String passbackParams) { this.passbackParams = passbackParams; } public ExtendParams getExtendParams() { return extendParams; } public void setExtendParams(ExtendParams extendParams) { this.extendParams = extendParams; } public String getGoodsType() { return goodsType; } public void setGoodsType(String goodsType) { this.goodsType = goodsType; } public String getPromoParams() { return promoParams; } public void setPromoParams(String promoParams) { this.promoParams = promoParams; } public RoyaltyInfo getRoyaltyInfo() { return royaltyInfo; } public void setRoyaltyInfo(RoyaltyInfo royaltyInfo) { this.royaltyInfo = royaltyInfo; } public SubMerchant getSubMerchant() { return subMerchant; } public void setSubMerchant(SubMerchant subMerchant) { this.subMerchant = subMerchant; } public String getMerchantOrderNo() { return merchantOrderNo; } public void setMerchantOrderNo(String merchantOrderNo) { this.merchantOrderNo = merchantOrderNo; } public String getEnablePayChannels() { return enablePayChannels; } public void setEnablePayChannels(String enablePayChannels) { this.enablePayChannels = enablePayChannels; } public String getStoreId() { return storeId; } public void setStoreId(String storeId) { this.storeId = storeId; } public String getDisablePayChannels() { return disablePayChannels; } public void setDisablePayChannels(String disablePayChannels) { this.disablePayChannels = disablePayChannels; } public String getQrPayMode() { return qrPayMode; } public void setQrPayMode(String qrPayMode) { this.qrPayMode = qrPayMode; } public String getQrcodeWidth() { return qrcodeWidth; } public void setQrcodeWidth(String qrcodeWidth) { this.qrcodeWidth = qrcodeWidth; } public SettleInfo getSettleInfo() { return settleInfo; } public void setSettleInfo(SettleInfo settleInfo) { this.settleInfo = settleInfo; } public InvoiceInfo getInvoiceInfo() { return invoiceInfo; } public void setInvoiceInfo(InvoiceInfo invoiceInfo) { this.invoiceInfo = invoiceInfo; } public AgreementSignParams getAgreementSignParams() { return agreementSignParams; } public void setAgreementSignParams(AgreementSignParams agreementSignParams) { this.agreementSignParams = agreementSignParams; } public String getIntegrationType() { return integrationType; } public void setIntegrationType(String integrationType) { this.integrationType = integrationType; } public String getRequestFromUrl() { return requestFromUrl; } public void setRequestFromUrl(String requestFromUrl) { this.requestFromUrl = requestFromUrl; } public String getBusinessParams() { return businessParams; } public void setBusinessParams(String businessParams) { this.businessParams = businessParams; } public ExtUserInfo getExtUserInfo() { return extUserInfo; } public void setExtUserInfo(ExtUserInfo extUserInfo) { this.extUserInfo = extUserInfo; } }
NameInMap中的value就是对应文档的字段
如果是List集合 NameInMap中需要设置type=List.class
如果是复杂对象需要设置type=Class.class
将对象转换为Map<String,Object>的集合的工具类(Map中的key 就是上面NameInMap中value的值)
package com.wl.alipay.util; import com.wl.alipay.annotation.NameInMap; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by Administrator on 2020/12/5. */ public class AliPayUtil { public static Map<String,Object> genBatchOptionals(Object request) throws Exception{ Map<String,Object> optionals = new HashMap<>(); Class<?> clazz = request.getClass(); convertMap(optionals,clazz,request); return optionals; } //只有特定类型的clazz 才能调用此方法,这里没有校验类型 private static void convertMap(Map<String,Object> options,Class clazz,Object target) throws Exception{ //todo 缓存field Field[] fields = clazz.getDeclaredFields(); for(Field field : fields){ NameInMap nameInMap = field.getAnnotation(NameInMap.class); if(nameInMap != null){ field.setAccessible(true); String key = nameInMap.value(); Object value = field.get(target); if(value != null) { if (nameInMap.type() == String.class) { options.put(key, value); } else if (nameInMap.type() == List.class) { //集合 List<Object> values = (List<Object>) value; // List<Object> list = new ArrayList<>(); options.put(key,list); for(Object o : values){ if(isBasicType(o)){ //基本数据类型或者String list.add(o); }else{ Map<String, Object> innerOptions = new HashMap<>(); list.add(innerOptions); convertMap(innerOptions, o.getClass(), o); } } } else { //对象 Map<String, Object> innerOptions = new HashMap<>(); options.put(key, innerOptions); convertMap(innerOptions, nameInMap.type(), value); } } } } } //String 也算 private static boolean isBasicType(Object o) { return o instanceof String || o instanceof Character || o instanceof Integer || o instanceof Long || o instanceof Byte || o instanceof Double || o instanceof Float || o instanceof Boolean; } }
修改上面createWebTradeForm接口如下
/**
* 对应alipay.trade.page.pay 接口
* 构造交易数据供pc端到支付宝下单
*/
public AlipayTradePagePayResponse createWebTradeForm(CreateWebTradeRequest request) throws Exception{
return Factory.Payment.Page().batchOptional(AliPayUtil.genBatchOptionals(request))
//单独设置超时时间 默认15分钟
.optional("timeout_express",aliPayProperties.getProperty(AliPayConstant.timeoutExpress,"15m"))
.pay(request.getSubject(),request.getTradeNo(),request.getTotalAmount(),
"http://localhost/api/alipay/webReturnUrl");
}
batchOptional就是批量设置请求可选参数的方法
测试genBatchOptionals方法
测试数据
package com.wl.alipay; import com.fasterxml.jackson.databind.ObjectMapper; import com.wl.alipay.domain.*; import com.wl.alipay.util.AliPayUtil; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * Created by Administrator on 2020/12/10. */ public class Test { public static void main(String[] args) throws Exception{ CreateWebTradeRequest request = new CreateWebTradeRequest(); request.setTimeExpire("2016-12-31 10:05"); { ExtendParams extendParams = new ExtendParams(); extendParams.setSysServiceProviderId("2088511833207846"); extendParams.setHbFqSellerPercent("100"); extendParams.setHbFqNum("3"); extendParams.setCardType("S0JP0000"); request.setExtendParams(extendParams); } { SettleInfo settleInfo = new SettleInfo(); settleInfo.setSettlePeriodTime("7d"); List<SettleDetailInfo> list = new ArrayList<>(); SettleDetailInfo detailInfo = new SettleDetailInfo(); detailInfo.setAmount("0.1"); detailInfo.setSettleEntityId("2088****;st_001"); detailInfo.setTransInType("cardAliasNo"); detailInfo.setTransIn("A0001"); list.add(detailInfo); settleInfo.setSettleDetailInfos(list); request.setSettleInfo(settleInfo); } request.setSubject("iphone11"); request.setMerchantOrderNo("20161008001"); { InvoiceInfo invoiceInfo = new InvoiceInfo(); invoiceInfo.setDetails("invoiceInfo"); { InvoiceKeyInfo keyInfo = new InvoiceKeyInfo(); keyInfo.setInvoiceMerchantName("merchantName"); keyInfo.setTaxNum("10"); keyInfo.setSupportInvoice(true); invoiceInfo.setKeyInfo(keyInfo); } request.setInvoiceInfo(invoiceInfo); } { RoyaltyInfo royaltyInfo = new RoyaltyInfo(); royaltyInfo.setRoyaltyType("ROYALTY"); { List<RoyaltyDetailInfos> list = new ArrayList<>(); { RoyaltyDetailInfos infos = new RoyaltyDetailInfos(); infos.setAmount("0.1"); infos.setSerialNo(1L); infos.setTransIn("wwwwwww"); list.add(infos); list.add(infos); } royaltyInfo.setRoyaltyDetailInfos(list); } request.setRoyaltyInfo(royaltyInfo); } { List<GoodsDetail> list = new ArrayList<>(); GoodsDetail goodsDetail = new GoodsDetail(); goodsDetail.setPrice("15.15"); goodsDetail.setGoodsName("iphone11"); list.add(goodsDetail); list.add(goodsDetail); request.setGoodsDetail(list); } Map<String,Object> map = AliPayUtil.genBatchOptionals(request); System.out.println(map); System.out.println(new ObjectMapper().writeValueAsString(map)); } }
输出数据(转换为json)
{ "royalty_info": { "royalty_type": "ROYALTY", "royalty_detail_infos": [{ "amount": "0.1", "trans_in": "wwwwwww", "serial_no": 1 }, { "amount": "0.1", "trans_in": "wwwwwww", "serial_no": 1 }] }, "invoice_info": { "key_info": { "tax_num": "10", "is_support_invoice": true, "invoice_merchant_name": "merchantName" }, "details": "invoiceInfo" }, "time_expire": "2016-12-31 10:05", "extend_params": { "sys_service_provider_id": "2088511833207847", "hb_fq_seller_percent": "100", "hb_fq_num": "3", "card_type": "S0JP0000" }, "settle_info": { "settle_period_time": "7d", "settle_detail_info": [{ "amount": "0.1", "trans_in": "A0001", "settle_entity_id": "2088****;st_001", "trans_in_type": "cardAliasNo" }] }, "goods_detail": [{ "goods_name": "iphone11", "price": "15.15" }, { "goods_name": "iphone11", "price": "15.15" }], "merchant_order_no": "20161008001" }
如果嫌使用对象麻烦,可以直接使用封装好的Map
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。