How to accept Stripe payments in Java (Tomcat + https) for Beginners πŸ’΅

1. Overview

Accepting credit card payments via Stripe has become one of the most prevalents billing payments online. Certainly, the simplicity of setting up a payment channel is a success factor of Stripe.com.

In this post we show how to set up a fully functioning payment channel via credit cards using Java and HTTPs.

We assume a configuration like this:

  • Java Server (Tomcat, JSP)
  • HTTPs (SSL/TLS) encryption available on our server
  • A legal entity to conduct business operations and accept payments (for sign up with Stripe)

2. Sign up and starting with Stripe development API

It’s easy to get start with Stripe. Just sign up for a new account with your email follow the instructions.

Next we can login in our dashboard and obtain our developer API keys.

We copy the public key and insert in the next step on our public payment form rendered by Stripe’s checkout.js library. This key will be visible to everyone. The private key will after that on the server side to send a billing request back to stripe servers.

3. Checkout.js

As a simple proof-of-concept we set up a Java Web Application that hosts a pay.html – a minimalistic form that accepts users credit card credentials and is based on Stripe’s checkout.js.

Since we require the checkout.js from a stripe server it is best practice to serve our pay.html via https to prevent Man-In-The-Middle attacks.

<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <form action="/StripeTestApp/acceptpaymentrequest" method="POST">
            <script
                src="https://checkout.stripe.com/checkout.js" class="stripe-button"
                data-key="pk_test_XXXXXXXXXXXXXXXXXXXXXXXXXx"
                data-amount="999"
                data-name="TestBiz"
                data-description="Example charge"
                data-image="https://stripe.com/img/documentation/checkout/marketplace.png"
                data-locale="auto"
                data-currency="eur">
            </script>


        </form>
    </body>
</html>

The end result will look like this:

Note how the setting data-locale=”auto” affects the displayed language and data-currency=”eur” changes the charge currency.

4. Making a test payment

Before we can start our test payment we set up a servlet to accept a request from the POST form.

First we use maven to add the required Stripe Java library for API request. This is done by adding a dependency in the pom.xml.

 <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.example</groupId>
<!-- ... -->

    <dependencies>
   <!-- ... -->
        <dependency>
            <groupId>com.stripe</groupId>
            <artifactId>stripe-java</artifactId>
            <version>5.31.0</version>
        </dependency>
  <!-- ... -->
    </dependencies>

   <!-- ... -->

</project>

Next we set up the servlet for the payment request.

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.mycompany.stripetestapp;

import com.stripe.Stripe;
import com.stripe.exception.APIConnectionException;
import com.stripe.exception.APIException;
import com.stripe.exception.AuthenticationException;
import com.stripe.exception.CardException;
import com.stripe.exception.InvalidRequestException;
import com.stripe.model.Charge;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author pushcommit
 */
public class acceptpaymentrequest extends HttpServlet {

    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
     * methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        response.setContentType("text/html");// Set response content type
        String title = "Stripe payment";
        String docType = "<!doctype html public \"-//w3c//dtd html 4.0 " + "transitional//en\">\n";

        try {

            Stripe.apiKey = getServletContext().getInitParameter("stripeSecretKey");
            Map<String, String[]> httpParameters = request.getParameterMap();

            //esctract request parameters
            Map<String, Object> userBillingData = new HashMap<>();
            String userEmail = httpParameters.get("stripeEmail")[0];
            userBillingData.put("email", userEmail);
            userBillingData.put("stripeToken", httpParameters.get("stripeToken")[0]);

            Map<String, Object> params = new HashMap<>();
            params.put("amount", "999"); // or get from request
            params.put("currency", "eur");  // or get from request
            params.put("source", userBillingData.get("stripeToken"));// or get from request
            params.put("receipt_email", userEmail);

            Charge charge;

            charge = Charge.create(params);

            String chargeID = charge.getId();

            out.println(docType
                    + "<html>\n"
                    + "<head><title>" + title + "</title></head>\n"
                    + "<body bgcolor = \"#f0f0f0\">\n"
                    + "<h1 align = \"center\">" + title + "</h1>\n"
                    + "- PAYMENT OK. chargeID " + chargeID + " -"
                    + "</body></html>"
            );

        } catch (Exception ex) {
            out.println(docType
                    + "<html>\n"
                    + "<head><title>" + title + "</title></head>\n"
                    + "<body bgcolor = \"#f0f0f0\">\n"
                    + "<h1 align = \"center\">" + title + "</h1>\n"
                    + "- ERROR - "
                    + "</body></html>"
            );
            out.close();
        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

}

After that we set up the required binding in our deployment descriptor web.xml so that the request will get redirect to our servlet. Also we enter our public and secret key – whether live or testing.

    <servlet>
        <servlet-name>acceptpaymentrequest</servlet-name>
        <servlet-class>com.example.acceptpaymentrequest</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>acceptpaymentrequest</servlet-name>
        <url-pattern>/acceptpaymentrequest</url-pattern>
    </servlet-mapping>	

     <context-param>
        <param-name>stripePublicKey</param-name>
        <param-value>pk_live_XXXXXXXXXXXXXXXXXXXXXXXX</param-value>
    </context-param>
    <context-param>
        <param-name>stripeSecretKey</param-name>
        <param-value>sk_live_XXXXXXXXXXXXXXXXXXXXXXXX</param-value>
    </context-param>

Also we set our custom context path in context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/StripeTestApp"/>

Our app is now able to accept payments. To test this we use one of the test credit card informations (see here).

In the Stripe dashboard we should be able to witness the payment in the log. Of course no one has been charged really yet. To go live and “arm” our payment form we take the steps described next.

The payment form is now online available under https://YOURDOMAIN.COM/StripeTetApp/pay.html and our servlet is accepting post request at https://YOURDOMAIN.COM/StripeTetApp/acceptpaymentrequest .

Our app will display the successful charge id.

5. Switching to production configuration

Stripe has to verify that we are an eligible business so we fill the required application form and wait for approval.

After that we have access to the live public keys. We replace the test keys in our web.xml with the live version and from there one we can accept real payments.

6. Conclusion

Even though the entire process is easy to understand there are several places where some debugging might be necessary.

If this proof-of-concept is working, we can create a more sophisticated and customized payment page and even log charges to be later displayed on a customer account page for example.

Leave a Reply

Your email address will not be published. Required fields are marked *