Charge a credit card with Stripe (#1556)
* Charge a credit card with Stripe Spring Boot project that includes Stripe Java library and does a charge to a credit card. BAEL-742 * Use ExceptionHandler for Stripe exceptions BAEL-742 * Show more detail at result page BAEL-742 * Show more detail at result page BAEL-742
This commit is contained in:
parent
e37ab29a42
commit
4b19cb6bcc
|
@ -0,0 +1,27 @@
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
nbproject/private/
|
||||||
|
build/
|
||||||
|
nbbuild/
|
||||||
|
dist/
|
||||||
|
nbdist/
|
||||||
|
.nb-gradle/
|
||||||
|
|
||||||
|
###
|
||||||
|
desktop.ini
|
|
@ -0,0 +1,66 @@
|
||||||
|
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.baeldung.stripe</groupId>
|
||||||
|
<artifactId>stripe</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>Stripe</name>
|
||||||
|
<description>Demo project for Stripe API</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>1.5.2.RELEASE</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.16.16</version>
|
||||||
|
<!-- version is explicit here because the one provided with the
|
||||||
|
current spring-boot-starter-parent has a bug in NetBeans;
|
||||||
|
can be removed if spring-boot-starter-parent is upgraded -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.stripe</groupId>
|
||||||
|
<artifactId>stripe-java</artifactId>
|
||||||
|
<version>4.2.0</version>
|
||||||
|
</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>
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.baeldung.stripe;
|
||||||
|
|
||||||
|
import com.baeldung.stripe.ChargeRequest.Currency;
|
||||||
|
import com.stripe.exception.StripeException;
|
||||||
|
import com.stripe.model.Charge;
|
||||||
|
import lombok.extern.java.Log;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||||
|
|
||||||
|
@Log
|
||||||
|
@Controller
|
||||||
|
public class ChargeController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
StripeService paymentsService;
|
||||||
|
|
||||||
|
@RequestMapping(value = "/charge", method = POST)
|
||||||
|
public String charge(ChargeRequest chargeRequest, Model model) throws StripeException {
|
||||||
|
chargeRequest.setDescription("Example charge");
|
||||||
|
chargeRequest.setCurrency(Currency.EUR);
|
||||||
|
Charge charge = paymentsService.charge(chargeRequest);
|
||||||
|
model.addAttribute("id", charge.getId());
|
||||||
|
model.addAttribute("status", charge.getStatus());
|
||||||
|
model.addAttribute("chargeId", charge.getId());
|
||||||
|
model.addAttribute("balance_transaction", charge.getBalanceTransaction());
|
||||||
|
return "result";
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(StripeException.class)
|
||||||
|
public String handleError(Model model, StripeException ex) {
|
||||||
|
model.addAttribute("error", ex.getMessage());
|
||||||
|
return "result";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.baeldung.stripe;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString(includeFieldNames = false)
|
||||||
|
public class ChargeRequest {
|
||||||
|
|
||||||
|
public enum Currency {
|
||||||
|
EUR, USD;
|
||||||
|
}
|
||||||
|
private String description;
|
||||||
|
private int amount; // cents
|
||||||
|
private Currency currency;
|
||||||
|
private String stripeEmail;
|
||||||
|
private String stripeToken;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.baeldung.stripe;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class CheckoutController {
|
||||||
|
|
||||||
|
@Value("${STRIPE_PUBLIC_KEY}")
|
||||||
|
private String stripePublicKey;
|
||||||
|
|
||||||
|
@RequestMapping("/checkout")
|
||||||
|
public String checkout(Model model) {
|
||||||
|
model.addAttribute("amount", 50 * 100); // in cents
|
||||||
|
model.addAttribute("stripePublicKey", stripePublicKey);
|
||||||
|
model.addAttribute("currency", ChargeRequest.Currency.EUR);
|
||||||
|
return "checkout";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.baeldung.stripe;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class StripeApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(StripeApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.baeldung.stripe;
|
||||||
|
|
||||||
|
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.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class StripeService {
|
||||||
|
|
||||||
|
@Value("${STRIPE_SECRET_KEY}")
|
||||||
|
String secretKey;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
Stripe.apiKey = secretKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Charge charge(ChargeRequest chargeRequest)
|
||||||
|
throws AuthenticationException, InvalidRequestException, APIConnectionException, CardException, APIException {
|
||||||
|
Map<String, Object> chargeParams = new HashMap<>();
|
||||||
|
chargeParams.put("amount", chargeRequest.getAmount());
|
||||||
|
chargeParams.put("currency", chargeRequest.getCurrency());
|
||||||
|
chargeParams.put("description", chargeRequest.getDescription());
|
||||||
|
chargeParams.put("source", chargeRequest.getStripeToken());
|
||||||
|
return Charge.create(chargeParams);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="refresh" content="0; url=/checkout.html" />
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
|
@ -0,0 +1,35 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:th='http://www.thymeleaf.org'>
|
||||||
|
<head>
|
||||||
|
<title>Checkout</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'arial';
|
||||||
|
}
|
||||||
|
#checkout-form input,
|
||||||
|
#checkout-form button {
|
||||||
|
display: block;
|
||||||
|
margin: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form action='/charge' method='POST' id='checkout-form'>
|
||||||
|
<input type='hidden' th:value='${amount}' name='amount' />
|
||||||
|
<label>Price:<span th:text='${amount/100}' /></label>
|
||||||
|
<!-- NOTE: data-key/data-amount/data-currency will be rendered by Thymeleaf -->
|
||||||
|
<script
|
||||||
|
src='https://checkout.stripe.com/checkout.js'
|
||||||
|
class='stripe-button'
|
||||||
|
th:attr='data-key=${stripePublicKey},
|
||||||
|
data-amount=${amount},
|
||||||
|
data-currency=${currency}'
|
||||||
|
data-name='Baeldung'
|
||||||
|
data-description='Spring course checkout'
|
||||||
|
data-image='http://www.baeldung.com/wp-content/themes/baeldung/favicon/android-chrome-192x192.png'
|
||||||
|
data-locale='auto'
|
||||||
|
data-zip-code='false'>
|
||||||
|
</script>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,17 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:th='http://www.thymeleaf.org'>
|
||||||
|
<head>
|
||||||
|
<title>Result</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h3 th:if='${error}' th:text='${error}' style='color: red;'></h3>
|
||||||
|
<div th:unless='${error}'>
|
||||||
|
<h3 style='color: green;'>Success!</h3>
|
||||||
|
<div>Id.: <span th:text='${id}' /></div>
|
||||||
|
<div>Status: <span th:text='${status}' /></div>
|
||||||
|
<div>Charge id.: <span th:text='${chargeId}' /></div>
|
||||||
|
<div>Balance transaction id.: <span th:text='${balance_transaction}' /></div>
|
||||||
|
</div>
|
||||||
|
<a href='/checkout.html'>Checkout again</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue