Integrating Alipay Sandbox Payment in Spring Boot: Configuration, SDK Setup, and Callback Handling
This article provides a step‑by‑step guide for integrating Alipay sandbox payment into a Spring Boot backend, covering sandbox configuration, network tunneling, Maven SDK dependency, application properties, payment request creation, callback processing, and common troubleshooting.
The guide begins with the prerequisite setup, requiring an Alipay sandbox account and a network tunneling tool to expose the local service to the public internet, enabling Alipay to send asynchronous callbacks.
It then shows how to configure the Alipay sandbox by visiting the sandbox portal and obtaining the public key, private key, gateway URL, APPID, and SDK information.
Next, the article explains the network tunneling process, recommending a free tunneling service, showing how to download the client, start a tunnel, and map the local 9090 port to a public address for testing.
For the actual development, the required Maven dependency is added:
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.9.28.ALL</version>
</dependency>The application.yml (or equivalent) is configured with the Alipay credentials:
server:
port: 9090
alipay:
appId: 9021000135634074
appPrivateKey: <your_private_key>
alipayPublicKey: <alipay_public_key>
notifyUrl: http://your-public-domain/notifyA Spring component reads these properties:
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
private String appId;
private String appPrivateKey;
private String alipayPublicKey;
private String notifyUrl;
@PostConstruct
public void init() {
Config config = new Config();
config.protocol = "https";
config.gatewayHost = "openapi-sandbox.dl.alipaydev.com";
config.signType = "RSA2";
config.appId = this.appId;
config.merchantPrivateKey = this.appPrivateKey;
config.alipayPublicKey = this.alipayPublicKey;
config.notifyUrl = this.notifyUrl;
Factory.setOptions(config);
System.out.println("=======支付宝SDK初始化成功=======");
}
}The payment request object is defined:
@Data
public class PayVO {
private String out_trade_no; // required
private String subject; // required
private BigDecimal total_amount; // required
private String body; // optional
}The controller creates an AlipayClient , builds a AlipayTradePagePayRequest , sets the business parameters as JSON, and returns the generated HTML form to the browser:
@RestController
@RequestMapping("/alipay")
public class AliPayController {
@Resource AliPayConfig aliPayConfig;
private static final String GATEWAY_URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
// ... other constants ...
@GetMapping("/pay")
public void pay(PayVO aliPay, HttpServletResponse httpResponse) throws Exception {
AlipayClient alipayClient = new DefaultAlipayClient(
GATEWAY_URL, aliPayConfig.getAppId(), aliPayConfig.getAppPrivateKey(),
"JSON", "utf-8", aliPayConfig.getAlipayPublicKey(), "RSA2");
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setNotifyUrl(aliPayConfig.getNotifyUrl());
aliPay.setOut_trade_no(UUID.randomUUID().toString());
request.setBizContent("{\"out_trade_no\":\"" + aliPay.getOut_trade_no() + "\",\"total_amount\":\"" + aliPay.getTotal_amount() + "\",\"subject\":\"" + aliPay.getSubject() + "\",\"body\":\"" + aliPay.getBody() + "\",\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
request.setReturnUrl("http://localhost:9090/hello/pay");
String form = alipayClient.pageExecute(request).getBody();
httpResponse.setContentType("text/html;charset=utf-8");
httpResponse.getWriter().write(form);
}
}The callback endpoint receives Alipay's asynchronous notification, verifies the signature, logs the transaction details, and updates the order status in the database:
@PostMapping("/notify")
public String payNotify(HttpServletRequest request) throws Exception {
if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
Map
params = new HashMap<>();
for (String name : request.getParameterMap().keySet()) {
params.put(name, request.getParameter(name));
}
if (Factory.Payment.Common().verifyNotify(params)) {
// log details and update order
ShopOrder order = new ShopOrder();
order.setId(params.get("out_trade_no"));
order.setStatus("1");
order.setZhhifuTime(params.get("gmt_payment"));
shopOrderMapper.save(order);
}
}
return "success";
}Common pitfalls such as a null Context during SDK initialization are addressed, with a solution that initializes the SDK in a @PostConstruct method of the configuration bean.
Finally, the article shows the expected result: a successful payment page in the Alipay sandbox, followed by the callback data and a confirmation that the order status has been updated.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.