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);@Beanpublic 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;@Autowiredpublic 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;@Autowiredpublic 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   缓存fieldField[] 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)){                       //基本数据类型或者Stringlist.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

沙箱支付宝alipay-easysdk java 支付能力对接相关推荐

  1. laravel5集成支付宝alipay扫码支付流程(Laravel 支付解决方案)

    laravel5集成支付宝alipay扫码支付流程(Laravel 支付解决方案) 参考文章: (1)laravel5集成支付宝alipay扫码支付流程(Laravel 支付解决方案) (2)http ...

  2. Java对接支付宝网站扫码支付

    一.对接流程概述 申请支付宝商户号 > 开通支付能力 >申请应用>开发设置>签约开通支付能力>集成SDK 二.流程详解 2.1 申请支付宝账号 2.2开通网站支付功能

  3. 支付宝支付(2) 电脑网站支付(SpringBoot+沙箱环境+Alipay Easy SDK)

    一.前言 支付宝支付(1) 电脑网站支付(SpringBoot+沙箱环境) Alipay Easy SDK 文档 Alipay Easy -> https://github.com/alipay ...

  4. Java支付宝支付接口对接(app端)

    前言:大致说一下流程,其实支付宝官方文档写的很清楚了,还有就是下面我写的一些描述可能转载了其他博客的内容. 用户在app端提交订单--->选择支付方式即支付宝付款(调用了商家端的付款接口,调用之 ...

  5. 【Java Web】支付宝 AliPay 功能

    本文涉及"并行开发"思想: 假设实际开发工作中:支付&订单 两个模块,分别由两位同事并行开发: 一位同事在开发支付模块时,可能需要依赖订单模块的的类.方法.工具类,但负责订 ...

  6. 沙箱支付宝------简单实现支付

    简介: 蚂蚁金服开放平台基于支付宝的海量用户,将强大的支付.营销.数据能力,通过接口等形式开放给第三方合作伙伴,帮助第三方合作伙伴创建更具竞争力的应用. 通过接入蚂蚁金服开放平台,第三方合作伙伴可以获 ...

  7. 支付宝 当面付(扫描支付) 对接逻辑

    支付宝 当面付(扫描支付) 对接逻辑 这两天给网站 博客下方添加了 打赏功能 使用的是 支付宝的 当面付功能 特此记录一下,觉得不错的可以在下方打赏 嘿嘿 ,下面先来看一下效果图. 1.当面付产品介绍 ...

  8. pay-spring-boot 开箱即用的Java支付模块,整合支付宝支付、微信支付

    关于 使用本模块,可轻松实现支付宝支付.微信支付对接,从而专注于业务,无需关心第三方逻辑. 模块完全独立,无支付宝.微信SDK依赖. 基于Spring Boot. 依赖Redis. 我能做什么 支付宝 ...

  9. 支付宝接口的在线支付(https://openhome.alipay.com/platform/appDaily.htm?tab=info)

    项目中需要用到在线支付,实现了调用支付宝接口的在线支付,记录下来以便以后使用. 一.进入蚂蚁金服开放平台登录 网址:https://openhome.alipay.com/developmentDoc ...

最新文章

  1. [kuangbin带你飞]专题五 并查集 E - 食物链 (带权并查集)
  2. 数据结构【图】—024最小生成树
  3. 3.IT-解决方案-3-Backup-Sql
  4. 浏览器如何渲染页面?
  5. python opencv cv2.resize()函数
  6. Linux 移除python Error: Trying to remove “yum”, which is protected
  7. 获奖名单出炉,快来看看有没有你!
  8. linux 创建用户和修改新增用户默认的家目录
  9. CF#303A Lucky Permutation Triple 数论
  10. Linux 文件类型
  11. Go-闭包和匿名函数讲解
  12. Redis 单机使用以及部署
  13. 几个你可能不了解的CSS单位
  14. 1m照片的宽和高是多少_照片常见标准尺寸大全
  15. 三极管:NPN和PNP
  16. python发送soap报文_使用Python将带附件的XML发送到SOAP ws
  17. python根据excel生成报表_python生成Excel图表(通过xlsxwriter)
  18. @PostMapping和@GetMapping使用详解
  19. 安卓开发之简单的弹出单选菜单Dialog
  20. Pywinauto 中文文档

热门文章

  1. python3 中__dict__的用法
  2. PYTHON 语言笔记
  3. java如何做标签云
  4. smartlook.tasktray.exe无法找到入口
  5. 【线上研讨会】多位重磅嘉宾莅临RT-Thread 嵌入式人工智能教学研讨会
  6. adobe reader 打开原理图很慢怎么办
  7. 非线性最小二乘法之Gauss Newton、L-M、Dog-Leg
  8. VR技术成为国家新基建项目主力军
  9. 毕业一年的计科人,聊一下毕业一年的前端开发心酸历程(很学zha的那种,不喜就走)
  10. ArcGIS教程:克里金法的工作原理(二)