Tomcat Java Servlet实现Apple Pay商户验证及HTTPClient证书传输方法
Absolutely! You can use a Tomcat Java Servlet to handle Apple Pay merchant verification—this is fully feasible, and we can adapt your PHP cURL logic to Java's HttpClient ecosystem with just a few key steps.
The core requirement is sending a signed POST request to Apple’s validation endpoint, which requires authenticating with your SSL certificate and private key. Here’s how to do it in a Java Servlet:
1. Prepare Your PEM Files for Java
Java typically works with keystores (PKCS12 or JKS) instead of raw PEM files. The easiest way is to convert your certificate and private key into a PKCS12 keystore using OpenSSL:
openssl pkcs12 -export -in your-production-cert.pem -inkey your-production-key.pem -out apple-pay-keystore.p12 -name "apple-pay-identity"
You’ll be prompted to set a password for the keystore—save this, as you’ll need it in your code.
Alternatively, if you want to load raw PEM files directly, you can use the BouncyCastle library, but the keystore approach is simpler for standard Java HttpClient usage.
2. Modern Java HttpClient (Java 11+)
If you’re using Java 11 or newer, the built-in java.net.http.HttpClient is the way to go. Here’s a complete Servlet example:
import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.security.KeyStore; import java.security.SecureRandom; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/apple-pay/verify-merchant") public class ApplePayMerchantVerificationServlet extends HttpServlet { // Apple's production validation URL (use sandbox URL for testing) private static final String APPLE_VALIDATION_URL = "https://apple-pay-gateway.apple.com/paymentservices/startSession"; // Path to your PKCS12 keystore (place this in WEB-INF for security) private static final String KEYSTORE_PATH = "/WEB-INF/apple-pay-keystore.p12"; private static final String KEYSTORE_PASSWORD = "your-keystore-password"; private static final String KEY_PASSWORD = "your-keystore-password"; // Same as keystore unless you set a separate one @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { // Load the PKCS12 keystore from the web app's resources KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(getServletContext().getResourceAsStream(KEYSTORE_PATH), KEYSTORE_PASSWORD.toCharArray()); // Initialize KeyManagerFactory to use our keystore KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, KEY_PASSWORD.toCharArray()); // Create a custom SSL context with our identity SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), null, new SecureRandom()); // Build HttpClient with the custom SSL context HttpClient httpClient = HttpClient.newBuilder() .sslContext(sslContext) .build(); // Prepare the request body (matches your PHP payload) String requestBody = "{\"merchantIdentifier\":\"merchant.com.blah.shop\", \"domainName\":\"shop.blah.com\", \"displayName\":\"Blah Shop\"}"; // Build and send the POST request HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(APPLE_VALIDATION_URL)) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); // Forward Apple's response back to the client resp.setContentType("application/json"); resp.setStatus(response.statusCode()); resp.getWriter().write(response.body()); } catch (Exception e) { throw new ServletException("Failed to process Apple Pay merchant verification", e); } } }
3. Apache HttpClient (For Java 8 or Older)
If you’re stuck on an older Java version, use Apache HttpClient. First add these Maven dependencies:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.14</version> </dependency>
Then the Servlet code:
import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLContexts; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import javax.net.ssl.SSLContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.security.KeyStore; @WebServlet("/apple-pay/verify-merchant") public class ApplePayMerchantVerificationServlet extends HttpServlet { private static final String APPLE_VALIDATION_URL = "https://apple-pay-gateway.apple.com/paymentservices/startSession"; private static final String KEYSTORE_PATH = "/WEB-INF/apple-pay-keystore.p12"; private static final String KEYSTORE_PASSWORD = "your-keystore-password"; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { // Load PKCS12 keystore KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(getServletContext().getResourceAsStream(KEYSTORE_PATH), KEYSTORE_PASSWORD.toCharArray()); // Create SSL context with our keystore SSLContext sslContext = SSLContexts.custom() .loadKeyMaterial(keyStore, KEYSTORE_PASSWORD.toCharArray()) .build(); // Create SSL socket factory for HttpClient SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext); // Build HttpClient HttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(sslSocketFactory) .build(); // Prepare POST request HttpPost postRequest = new HttpPost(APPLE_VALIDATION_URL); postRequest.setHeader("Content-Type", "application/json"); String requestBody = "{\"merchantIdentifier\":\"merchant.com.blah.shop\", \"domainName\":\"shop.blah.com\", \"displayName\":\"Blah Shop\"}"; postRequest.setEntity(new StringEntity(requestBody)); // Execute request and get response HttpResponse httpResponse = httpClient.execute(postRequest); HttpEntity responseEntity = httpResponse.getEntity(); String responseBody = EntityUtils.toString(responseEntity); // Send response back to client resp.setContentType("application/json"); resp.setStatus(httpResponse.getStatusLine().getStatusCode()); resp.getWriter().write(responseBody); } catch (Exception e) { throw new ServletException("Apple Pay merchant verification failed", e); } } }
- Security: Always store your keystore in the
WEB-INFdirectory (not accessible via public URLs) and avoid hardcoding passwords in production—use environment variables or a secure configuration system instead. - Sandbox vs Production: Use Apple’s sandbox validation URL (
https://apple-pay-gateway-sandbox.apple.com/paymentservices/startSession) for testing. - Error Handling: Add checks for HTTP status codes (Apple returns 200 for success) and parse error responses from Apple to handle cases like invalid merchant identifiers.
内容的提问来源于stack exchange,提问作者Joe Smith

