Looking for a payment solution for your Spring Boot app? If so, then you should check out Braintree Direct.
Why? For starters, Braintree is a division of PayPal. So if you’re looking for PayPal integration, then you’re all set.
Beyond that, though, you can use Braintree to accept Most major credit cards, Apple Pay, Google Pay, and Venmo.
What’s not to love?
In this article, we’ll go over how you can implement a Braintree Direct solution within your Spring Boot application.
Feel free to review the entire source for this project on GitHub.
The Use Case
As usual, we’ll start with the use case because we’re business-focused around these parts.
Your boss, Smithers, just showed up in your office and told you that the company needed a payment solution for a new e-commerce website.
Smithers is clearly frustrated because he’s never rolled out a payment solution before. “I’ve always done admin screens!” he says in exasperation.
No problem, you reply. You assure him that you can integrate a Braintree solution into the app.
Smithers leave your office smiling.
To get the most out of this demo, you’ll need a working knowledge of Java, Spring Boot, and Thymeleaf. There are plenty of tutorials online that will help you understand that tech stack if you’re unfamiliar with any of it.
You should also have a basic understanding of Braintree. That doesn’t mean you need to be an expert in the integration technology (that’s why you’re reading this article, after all). But you should know how to set up an account and configure it to accept various payments.
For the purposes of this demo, the application is only accepting credit card payments. It’s not accepting PayPal, Apple Pay, Google Pay, or Venmo.
Playing in the Sandbox
Fortunately, Braintree offers a sandbox environment where you can play to your heart’s content with fake credit card transactions. That way, you can make sure that your code works without having to max out your card.
You’ll need to set up a sandbox in Braintree if you want to use the demo code locally.
Once you have that set up, you’ll get a Merchant ID. You can find it by viewing your Merchant Account info located under the Account menu at the top of the screen.
You’ll also need a private key and public key. You can access those by selecting API Keys under the Settings menu.
The POM File
You need to update your POM file to include the Braintree Java client library. Add the following dependency:
That’s the only addition you need to make for this project.
The Config Class
Next, you need to create a config class. Here’s what that will look like:
There are two annotations at the top of the code. They’re very important.
@Configuration annotation tells Spring that the class is a configuration class. That means it can be used to define beans that will ultimately be injected into other objects. We’ll see how that works later.
@ComponentScan annotation is necessary because the code will create a bean from an external library. In this case, it’s instantiating a
BraintreeGateway object from the Braintree Java client library.
Note that the code is scanning the
com.braintreegateway package. That’s the base package of the library.
At the top, the first line of code is a constant that defines the name and location of the configuration file. That file will include important info that Braintree needs, such as the public and private key.
In this case, the config file is named
config.properties and located in the root of the
Here’s the structure of the file:
The only public method in the class is annotated with
@Bean. That’s because it’s used to create an object that can be managed by the Spring container and injected into other objects.
As you can see,
getBraintreeGateway() is intuitively named and returns a
BraintreeGateway object. It does that by calling the factory that we’ll look at in just a bit.
Before it can call
BraintreeGatewayFactory, though, it needs to create a map. The code does that by reading the config file mentioned above and translating the name/value pairs in the file to key/value pairs in a Java Map object.
The second method, called
getMap(), does most of the heavy lifting to make that happen.
Next, let’s look at the class that creates the
There are two public, static methods. The first one creates the object from a
Obviously, that’s the one used in this project.
The second method creates the object directly from the config file. That’s not used here.
If you’re wondering why the code uses the first method instead of the second one, it’s because the config file is embedded in the Spring JAR file. Spring has trouble reading
File objects from its own JAR.
That’s why it’s best to read those kinds of files as
Streams. Then, the code can process the
Streams with a
The Checkout Page
To keep things simple, there’s only one Controller class in this demo. Here’s the method that handles the main checkout page:
There’s nothing too fancy in that. The most important part is that the code invokes the
Keep in mind the
BraintreeGateway object was injected into the controller class:
The method closes by serving up newTransaction.html.
Checkout Page HTML Code
Next, let’s look at the important parts of the HTML on the main checkout page. Here’s some of that code towards the top:
Both of those
div tags are designed to hold error messages. The top one holds server-side error messages and the bottom one holds client-side error messages.
Below that, there’s a table that looks like a shopping cart. Most of the info is hard-coded. Here’s the default output:
As you can see, the only field that users can change is the price.
Here’s what the code for that table looks like:
Note that the table is encapsulated in a
<form> tag. That’s because of the single element that accepts input.
After the table code, there’s a placeholder for the Braintree drop-in.
Here’s what the placeholder code looks like:
The code is blocked off with
The next line creates the client token. As you can see, it sets the
client_token variable to the value of the
clientToken string put in the model by the controller class. Check out the controller code above to see how that happens.
Next, the code invokes the create() method from the
Two important things to note here. First, the
create() method is the workhorse method that plugs the payment widget into the page. As you might have guessed, it puts it in that placeholder element that you saw above.
create() method accepts two parameters: an array object and a callback function.
The array object contains a series of name/value pairs that are fairly intuitive. For example, the “container” name is assigned to the element ID of the div where the drop-in will appear. In this case, it’s set to “#bt-dropin” because “bt-dropin” is the ID of the placeholder div tag.
As you can see from above, the code interrupts the submit function on the form. Then, it hides the two error
After that, the code calls the
That function sets the nonce and submits the form.
If you’re unfamiliar with the word “nonce,” it’s a secure, single reference to payment info.
instance.requestPaymentMethod() block just above, you’ll see that the callback function checks for the existence of err. If that exists, then it contains error info that the user needs to see. That’s why that block of code invokes the
Now, let’s look at what happens when that form gets submitted.
POSTing the Checkout Form
Here’s the method that handles form submission on the checkout page: