In this tutorial, we will show you how to perform payment integration using PayPal.
We will create a Spring boot application and perform payment integration using PayPal.
We will use Spring boot at the backend and Thymeleaf as frontend.
Let's start by creating a Spring boot application. Check out this video for more details.
To work with PayPal, you need to create an account in PayPal.
Go to PayPal develop sandbox and create a new app to get clientId, secret and add to Spring boot application properties file.
1. Create Spring Boot Project
There are many ways to create a Spring Boot application. You can refer to the below articles to create a Spring Boot application.
2. Maven Dependencies
Make you add PayPal SDK dependency and the complete pom.xml file:
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.javatechie</groupId> <artifactId>spring-paypal-example</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-paypal-example</name> <description>payment integration with paypal</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.paypal.sdk</groupId> <artifactId>rest-api-sdk</artifactId> <version>1.4.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
3. PayPalConfig
Create PapPalConfig class and add the following content to it:
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.paypal.api.payments.PaymentHistory;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.OAuthTokenCredential;
import com.paypal.base.rest.PayPalRESTException;
@Configuration
public class PaypalConfig {
@Value("${paypal.client.id}")
private String clientId;
@Value("${paypal.client.secret}")
private String clientSecret;
@Value("${paypal.mode}")
private String mode;
@Bean
public Map paypalSdkConfig() {
Map configMap = new HashMap<>();
configMap.put("mode", mode);
return configMap;
}
@Bean
public OAuthTokenCredential oAuthTokenCredential() {
return new OAuthTokenCredential(clientId, clientSecret, paypalSdkConfig());
}
@Bean
public APIContext apiContext() throws PayPalRESTException {
APIContext context = new APIContext(oAuthTokenCredential().getAccessToken());
context.setConfigurationMap(paypalSdkConfig());
return context;
}
}
4. The application.properties File
server.port: 9090
paypal.mode=sandbox
paypal.client.id=AYSq3RDGsmBLJE-otTkBtM-jBRd1TCQwFf9RGfwddNXWz0uFU9ztymylOhRS
paypal.client.secret=EGnHDxD_qRPdaLdZz8iCr8N7_MzF-YHPTkjs6NKYQvQSBngp4PTTVWkPZRbL
5. Order JPA Entity
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Order {
private double price;
private String currency;
private String method;
private String intent;
private String description;
}
6. PayPal Service
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.paypal.api.payments.Amount;
import com.paypal.api.payments.Payer;
import com.paypal.api.payments.Payment;
import com.paypal.api.payments.PaymentExecution;
import com.paypal.api.payments.RedirectUrls;
import com.paypal.api.payments.Transaction;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;
@Service
public class PaypalService {
@Autowired
private APIContext apiContext;
public Payment createPayment(
Double total,
String currency,
String method,
String intent,
String description,
String cancelUrl,
String successUrl) throws PayPalRESTException{
Amount amount = new Amount();
amount.setCurrency(currency);
total = new BigDecimal(total).setScale(2, RoundingMode.HALF_UP).doubleValue();
amount.setTotal(String.format("%.2f", total));
Transaction transaction = new Transaction();
transaction.setDescription(description);
transaction.setAmount(amount);
List transactions = new ArrayList<>();
transactions.add(transaction);
Payer payer = new Payer();
payer.setPaymentMethod(method.toString());
Payment payment = new Payment();
payment.setIntent(intent.toString());
payment.setPayer(payer);
payment.setTransactions(transactions);
RedirectUrls redirectUrls = new RedirectUrls();
redirectUrls.setCancelUrl(cancelUrl);
redirectUrls.setReturnUrl(successUrl);
payment.setRedirectUrls(redirectUrls);
return payment.create(apiContext);
}
public Payment executePayment(String paymentId, String payerId) throws PayPalRESTException{
Payment payment = new Payment();
payment.setId(paymentId);
PaymentExecution paymentExecute = new PaymentExecution();
paymentExecute.setPayerId(payerId);
return payment.execute(apiContext, paymentExecute);
}
}
7. PayPal Controller
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import com.paypal.api.payments.Links; import com.paypal.api.payments.Payment; import com.paypal.base.rest.PayPalRESTException; @Controller public class PaypalController { @Autowired PaypalService service; public static final String SUCCESS_URL = "pay/success"; public static final String CANCEL_URL = "pay/cancel"; @GetMapping("/") public String home() { return "home"; } @PostMapping("/pay") public String payment(@ModelAttribute("order") Order order) { try { Payment payment = service.createPayment(order.getPrice(), order.getCurrency(), order.getMethod(), order.getIntent(), order.getDescription(), "http://localhost:9090/" + CANCEL_URL, "http://localhost:9090/" + SUCCESS_URL); for(Links link:payment.getLinks()) { if(link.getRel().equals("approval_url")) { return "redirect:"+link.getHref(); } } } catch (PayPalRESTException e) { e.printStackTrace(); } return "redirect:/"; } @GetMapping(value = CANCEL_URL) public String cancelPay() { return "cancel"; } @GetMapping(value = SUCCESS_URL) public String successPay(@RequestParam("paymentId") String paymentId, @RequestParam("PayerID") String payerId) { try { Payment payment = service.executePayment(paymentId, payerId); System.out.println(payment.toJSON()); if (payment.getState().equals("approved")) { return "success"; } } catch (PayPalRESTException e) { System.out.println(e.getMessage()); } return "redirect:/"; } }
Home Thymeleaf Template
Let's create a home.html file and add the following content to it:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <style> body { font-family: Arial; font-size: 17px; padding: 8px; } * { box-sizing: border-box; } .row { display: -ms-flexbox; /* IE10 */ display: flex; -ms-flex-wrap: wrap; /* IE10 */ flex-wrap: wrap; margin: 0 -16px; } .col-25 { -ms-flex: 25%; /* IE10 */ flex: 25%; } .col-50 { -ms-flex: 50%; /* IE10 */ flex: 50%; } .col-75 { -ms-flex: 75%; /* IE10 */ flex: 75%; } .col-25, .col-50, .col-75 { padding: 0 16px; } .container { background-color: #f2f2f2; padding: 5px 20px 15px 20px; border: 1px solid lightgrey; border-radius: 3px; } input[type=text] { width: 100%; margin-bottom: 20px; padding: 12px; border: 1px solid #ccc; border-radius: 3px; } label { margin-bottom: 10px; display: block; } .icon-container { margin-bottom: 20px; padding: 7px 0; font-size: 24px; } .btn { background-color: #4CAF50; color: white; padding: 12px; margin: 10px 0; border: none; width: 100%; border-radius: 3px; cursor: pointer; font-size: 17px; } .btn:hover { background-color: #45a049; } a { color: #2196F3; } hr { border: 1px solid lightgrey; } span.price { float: right; color: grey; } /* Responsive layout - when the screen is less than 800px wide, make the two columns stack on top of each other instead of next to each other (also change the direction - make the "cart" column go on top) */ @media (max-width: 800px) { .row { flex-direction: column-reverse; } .col-25 { margin-bottom: 20px; } } </style> </head> <body> <div class="row"> <div class="col-75"> <div class="container"> <form method="post" action="/pay"> <div class="col-50"> <h3>Payment</h3> <label>Accepted Cards</label> <div class="icon-container"> <i class="fa fa-cc-visa" style="color:navy;"></i> <i class="fa fa-cc-amex" style="color:blue;"></i> <i class="fa fa-cc-mastercard" style="color:red;"></i> <i class="fa fa-cc-discover" style="color:orange;"></i> </div> <label for="price">Total</label> <input type="text" id="price" name="price" value="10"> <label for="currency">Currency</label> <input type="text" id="currency" name="currency" placeholder="Enter Currency"> <label for="method">Payment Method</label> <input type="text" id="method" name="method" placeholder="Payment Method"> <label for="intent">Intent</label> <input type="text" id="intent" name="intent" value="sale"> <label for="description">Payment Description</label> <input type="text" id="description" name="description" placeholder="Payment Description"> </div> <input type="submit" value="Continue to checkout" class="btn"> </form> </div> </div> <div class="col-25"> <div class="container"> <h4>Cart <span class="price" style="color:black"><i class="fa fa-shopping-cart"></i> <b>4</b></span></h4> <p><a href="#">Product 1</a> <span class="price">$1</span></p> <p><a href="#">Product 2</a> <span class="price">$4</span></p> <p><a href="#">Product 3</a> <span class="price">$3</span></p> <p><a href="#">Product 4</a> <span class="price">$2</span></p> <hr> <p>Total <span class="price" style="color:black"><b>$10</b></span></p> </div> </div> </div> </body> </html>
Success Thymeleaf Template
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Insert title here</title> </head> <body> <h1>Payment Success</h1> </body> </html>
Cancel Thymeleaf Template
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Insert title here</title> </head> <body> <h1>Payment Failure</h1> </body> </html>
Run Spring Boot application
Let's run this spring boot application from IDE -> Right-click -> Run As -> Java Application:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringPaypalExampleApplication { public static void main(String[] args) { SpringApplication.run(SpringPaypalExampleApplication.class, args); } }
Demo
The below YouTube video has a complete demo of this example:
Comments
Post a Comment