Para incorporar pagos a través de Alipay en una aplicación web Java, es necesario registrarse en la plataforma abierta de Ant Financial y acceder al entorno de pruebas (sandbox). Desde el panel de desarrollo, se genera un par de claves RSA que permitirán firmar las solicitudes y verificar las notificaciones.
Preparación del entorno sandbox
Dentro del apartado de sandbox se debe configurar la clave pública de la aplicación. Para ello se descarga la herramienta oficial de generación de claves (disponible para Windows). Se selecciona una longitud de clave de 2048 bits y se obtienen tanto la clave privada como la pública. La clave pública se copia y se pega en el campo correspondiente de la consola, lo que genera automáticamente la clave pública de Alipay asociada al APPID.
Es fundamental mantener la clave privada en secreto, ya que forma parte de los parámetros de autenticación. Además, se debe descargar la aplicación de monedero sandbox para simular los pagos. En la sección de cuantas de prueba se encuentran los datos de un comprador de prueba con saldo suficiente.
Incorporación en un proyecto Spring Boot
Se asume un proyecto Spring Boot con las dependencias básicas. Para usar el SDK de Alipay se añade la siguiente dependencia en el archivo pom.xml:
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.0.0</version>
</dependency>
Configuración de parámetros
Se crea una clase de configuración que almacena los datos de conexión. En este ejemplo se utiliza una clase con constantes estáticas, aunque en un entorno productivo se recomienda externalizarlas mediante application.properties.
public class ConfiguracionAlipay {
public static final String APP_ID = "2016101400681231";
public static final String CLAVE_PRIVADA = "MIIEvQIBADANBgkqh...";
public static final String CLAVE_PUBLICA_ALIPAY = "MIIBIjANBgkqhkiG...";
public static final String URL_NOTIFICACION = "http://tudominio.com/notify";
public static final String URL_RETORNO = "http://tudominio.com/return";
public static final String TIPO_FIRMA = "RSA2";
public static final String CHARSET = "utf-8";
public static final String URL_GATEWAY = "https://openapi.alipaydev.com/gateway.do";
}
La URL del gateway corresponde al entorno sandbox; en producción se cambia a https://openapi.alipay.com/gateway.do.
Servicio de pago
Se encapsula la lógica de interacción con Alipay en un servicio dedicdao. Este servicio construye el cliente, prepara la solicitud de pago por página y devuelve el formulario HTML que se debe enviar al navegador.
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
public class ServicioPagoAlipay {
private final AlipayClient cliente;
public ServicioPagoAlipay() {
this.cliente = new DefaultAlipayClient(
ConfiguracionAlipay.URL_GATEWAY,
ConfiguracionAlipay.APP_ID,
ConfiguracionAlipay.CLAVE_PRIVADA,
"json",
ConfiguracionAlipay.CHARSET,
ConfiguracionAlipay.CLAVE_PUBLICA_ALIPAY,
ConfiguracionAlipay.TIPO_FIRMA
);
}
public String generarFormularioPago(PedidoDto pedido) throws AlipayApiException {
AlipayTradePagePayRequest solicitud = new AlipayTradePagePayRequest();
solicitud.setReturnUrl(ConfiguracionAlipay.URL_RETORNO);
solicitud.setNotifyUrl(ConfiguracionAlipay.URL_NOTIFICACION);
String contenido = String.format(
"{\"out_trade_no\":\"%s\",\"total_amount\":\"%s\",\"subject\":\"%s\",\"body\":\"%s\",\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}",
pedido.getNumeroOrden(),
pedido.getMontoTotal(),
pedido.getAsunto(),
pedido.getDescripcion()
);
solicitud.setBizContent(contenido);
return cliente.pageExecute(solicitud).getBody();
}
}
La clase PedidoDto es un simple objeto de transferencia con los campos numeroOrden, montoTotal, asunto y descripcion.
Controlador de pago
El controlador recibe la petición del formulario de compra, invoca al servicio y escribe la respuesta HTML directamente en el flujo de salida. Esto provoca que el navegador redirija automáticamente al usuario a la pasarela de pago.
@RestController
public class ControladorPago {
private final ServicioPagoAlipay servicioPago = new ServicioPagoAlipay();
@PostMapping("/pagar")
public void procesarPago(HttpServletRequest request, HttpServletResponse response) throws IOException {
// Lectura de parámetros con codificación correcta
PedidoDto pedido = new PedidoDto();
pedido.setNumeroOrden(new String(request.getParameter("numeroOrden").getBytes("ISO-8859-1"), "UTF-8"));
pedido.setMontoTotal(new String(request.getParameter("monto").getBytes("ISO-8859-1"), "UTF-8"));
pedido.setAsunto(new String(request.getParameter("asunto").getBytes("ISO-8859-1"), "UTF-8"));
pedido.setDescripcion(new String(request.getParameter("descripcion").getBytes("ISO-8859-1"), "UTF-8"));
try {
String formulario = servicioPago.generarFormularioPago(pedido);
response.setContentType("text/html;charset=" + ConfiguracionAlipay.CHARSET);
response.getWriter().write(formulario);
response.getWriter().flush();
} catch (AlipayApiException e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error al generar el pago");
}
}
}
Notificaciones asíncronas
Cuando el pago se completa, Alipay envía una notificación POST a la URL configurada en URL_NOTIFICACION. Es imprescindible verificar la firma de los datos recibidos y, a continuación, actualizar el estado del pedido en el sistema. Un ejemplo simplificado de endpoint de notificación:
@PostMapping("/notify")
public void recibirNotificacion(HttpServletRequest request, HttpServletResponse response) throws IOException {
Map<String,String> params = obtenerParametros(request);
boolean firmaValida = AlipaySignature.rsaCheckV1(params, ConfiguracionAlipay.CLAVE_PUBLICA_ALIPAY, ConfiguracionAlipay.CHARSET, ConfiguracionAlipay.TIPO_FIRMA);
if (firmaValida) {
String estado = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
String numeroOrden = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
// Actualizar pedido en base de datos
response.getWriter().write("success");
} else {
response.getWriter().write("fail");
}
}
Operaciones de reembolso y consulta
El SDK también permite realizar reembolsos, consultar el estado de un pago o cerrar transacciones. A continuación se muestra un servicio de reembolso que recibe un objeto con los datos necesarios:
public String ejecutarReembolso(ReembolsoDto reembolso) throws AlipayApiException {
AlipayTradeRefundRequest solicitud = new AlipayTradeRefundRequest();
String contenido = String.format(
"{\"out_trade_no\":\"%s\",\"trade_no\":\"%s\",\"refund_amount\":\"%s\",\"refund_reason\":\"%s\",\"out_request_no\":\"%s\"}",
reembolso.getNumeroOrden(),
reembolso.getNumeroTransaccion(),
reembolso.getMontoReembolso(),
reembolso.getMotivo(),
reembolso.getSolicitudId()
);
solicitud.setBizContent(contenido);
return cliente.execute(solicitud).getBody();
}
Las consultas de estado de pago (AlipayTradeQueryRequest) y el cierre de transacciones (AlipayTradeCloseRequest) siguen un patrón similar, adaptando los parámetros de negocio según la documentación oficial.
Con esta base es posible integrar completamente Alipay en una aplicación Spring Boot, manejando tanto pagos en el entorno de pruebas como en producción, y cubriendo las operaciones más habituales del ciclo de vida de una transacción.