Braintree не генерирует клиентский токен на эластичном бобовом стебле AWS
Я столкнулся с этой проблемой в приложении Spring Boot, где я получаю исключение нулевого указателя для генерации клиентского токена для Braintree на AWS Elastic Beanstalk, где он отлично работает в localhost. Если кто-нибудь может помочь мне указать на проблему, которая будет высоко оценена.
KolystyleApplication.java
package com.kolystyle;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class KolystyleApplication extends SpringBootServletInitializer {
public static String DEFAULT_CONFIG_FILENAME = "config.properties";
public static BraintreeGateway gateway;
public static void main(String[] args) throws Exception {
File configFile = new File(DEFAULT_CONFIG_FILENAME);
try {
if(configFile.exists() && !configFile.isDirectory()) {
gateway = BraintreeGatewayFactory.fromConfigFile(configFile);
System.out.println("Braintree API use From Config File");
} else {
gateway = BraintreeGatewayFactory.fromConfigMapping(System.getenv());
System.out.println("Braintree configuration from SYSTEM ENVIRONMENT loaded");
}
} catch (NullPointerException e) {
System.err.println("Could not load Braintree configuration from config file or system environment.");
System.exit(1);
}
SpringApplication.run(KolystyleApplication.class, args);
}
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(KolystyleApplication.class);
}
}
BraintreeGatewayFactory.java
package com.kolystyle;
import com.braintreegateway.BraintreeGateway;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
public class BraintreeGatewayFactory {
public static BraintreeGateway fromConfigMapping(Map<String, String> mapping) {
return new BraintreeGateway(
mapping.get("BT_ENVIRONMENT"),
mapping.get("BT_MERCHANT_ID"),
mapping.get("BT_PUBLIC_KEY"),
mapping.get("BT_PRIVATE_KEY")
);
}
public static BraintreeGateway fromConfigFile(File configFile) {
InputStream inputStream = null;
Properties properties = new Properties();
try {
inputStream = new FileInputStream(configFile);
properties.load(inputStream);
} catch (Exception e) {
System.err.println("Exception: " + e);
} finally {
try { inputStream.close(); }
catch (IOException e) { System.err.println("Exception: " + e); }
}
return new BraintreeGateway(
properties.getProperty("BT_ENVIRONMENT"),
properties.getProperty("BT_MERCHANT_ID"),
properties.getProperty("BT_PUBLIC_KEY"),
properties.getProperty("BT_PRIVATE_KEY")
);
}
}
config.properties
BT_ENVIRONMENT=sandbox
BT_MERCHANT_ID=some_merchant_id
BT_PUBLIC_KEY=some_public_key
BT_PRIVATE_KEY=some_private_id
CheckoutController.java
package com.kolystyle.controller;
<removed imports to meet 30000 characters limit>
import com.braintreegateway.BraintreeGateway;
import com.braintreegateway.Result;
import com.braintreegateway.Transaction;
import com.braintreegateway.TransactionRequest;
import com.braintreegateway.ValidationError;
import com.braintreegateway.Transaction.Status;
import com.kolystyle.KolystyleApplication;
import com.kolystyle.domain.BillingAddress;
import com.kolystyle.service.PaymentService;
import com.kolystyle.utility.MailConstructor;
import com.kolystyle.utility.USConstants;
@Controller
public class CheckoutController {
private static final Logger LOG = LoggerFactory.getLogger(CheckoutController.class);
private BraintreeGateway gateway = KolystyleApplication.gateway;
private Status[] TRANSACTION_SUCCESS_STATUSES = new Status[] {
Transaction.Status.AUTHORIZED,
Transaction.Status.AUTHORIZING,
Transaction.Status.SETTLED,
Transaction.Status.SETTLEMENT_CONFIRMED,
Transaction.Status.SETTLEMENT_PENDING,
Transaction.Status.SETTLING,
Transaction.Status.SUBMITTED_FOR_SETTLEMENT
};
private ShippingAddress shippingAddress = new ShippingAddress();
private BillingAddress billingAddress = new BillingAddress();
private Payment payment = new Payment();
@Autowired
private UserService userService;
@Autowired
private OrderRepository orderRepository;
@Autowired
private OrderLogRepository orderLogRepository;
@Autowired
private ShoppingCartService shoppingCartService;
@Autowired
private CartItemService cartItemService;
@Autowired
private ShippingAddressService shippingAddressService;
@Autowired
private BillingAddressService billingAddressService;
@Autowired
private PaymentService paymentService;
@Autowired
private UserShippingService userShippingService;
@Autowired
private SiteSettingService siteSettingService;
@Autowired
private UserPaymentService userPaymentService;
@Autowired
private OrderService orderService;
@Autowired
private OrderLogService orderLogService;
@Autowired
private PromoCodesService promoCodesService;
@Autowired
private PromoCodesRepository promoCodesRepository;
@RequestMapping("/cart/guestcheckout")
public String guestcheckout(HttpServletRequest request,HttpServletResponse response,Model model ) {
SiteSetting siteSettings = siteSettingService.findOne(new Long(1));
model.addAttribute("siteSettings",siteSettings);
ShoppingCart shoppingCart;
shoppingCart = shoppingCartService.findCartByCookie(request);
System.out.println("SUCCESSFUL WITH COOKIE LOGIC");
if(shoppingCart == null) {
return "redirect:/shoppingCart/cart";
}
List<CartItem> cartItemList = cartItemService.findByShoppingCart(shoppingCart);
SiteSetting siteSetting= siteSettingService.findOne((long) 1);
ShippingAddress shippingAddress = new ShippingAddress();
BillingAddress billingAddress = new BillingAddress();
Payment payment = new Payment();
if(shoppingCart.getShippingMethod().equalsIgnoreCase("premiumShipping")) {
model.addAttribute("premiumShipping",true);
}else {
model.addAttribute("groundShipping",true);
}
String clientToken;
try {
clientToken = gateway.clientToken().generate();
LOG.info("Client token {} for paypal generated",clientToken);
} catch (Exception e) {
System.out.println("Exception: " + e);
return "badRequestPage";
}
System.out.println("ClientToken: "+clientToken);
model.addAttribute("siteSetting", siteSetting);
model.addAttribute("clientToken", clientToken);
model.addAttribute("shippingAddress",shippingAddress);
model.addAttribute("payment",payment);
model.addAttribute("billingAddress",billingAddress);
model.addAttribute("cartItemList",cartItemList);
model.addAttribute("shoppingCart",shoppingCart);
List<String> stateList = USConstants.listOfUSStatesCode;
Collections.sort(stateList);
model.addAttribute("stateList", stateList);
model.addAttribute("noCartExist",true);
return "guestcheckout";
}
guestcheckout.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head th:replace="common/head :: common-head" />
<body>
<!-- Load the required components. -->
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
<script src="https://js.braintreegateway.com/web/3.25.0/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.25.0/js/paypal-checkout.min.js"></script>
<div class="spinnerspin">
<div class="wrapper-box">
<div class="main-wrapper">
<div th:replace="common/head :: navbar" />
<div id="container">
<div id="content">
<section class="" ng-app="checkoutApp">
<div ng-controller = "checkoutCtrl" th:attr="ng-init='initCartId('+${shoppingCart.id}+')'">
<div class="row" style="margin-top: 10px;">
<form th:action="@{/chargeguest}" method="post" id="payment-form">
<!--form th:action="@{/checkouts}" method="post" id="payment-form"-->
<!-- Checkout Info -->
<div class="col-md-12">
<div th:if="${missingRequiredField}">
<h5 class="alert alert-warning">There are some fields
missing. Field with * is required</h5>
</div>
</div>
<div class="col-md-6">
<div class="panel-group" id="accordion">
<div class="col-md-12">
<!-- 1. Shipping Address -->
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion"
href="#shippingInfo">Shipping Address</a>
</h4>
</div>
<div id="shippingInfo" class="panel-collapse collapse in"
th:classappend="${classActiveShipping}? 'in'">
<div class="panel-body">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="firstName">* First Name</label> <input type="text"
class="form-control" id="firstName"
placeholder="First Name" th:name="firstName"
required="required"
th:value="${shippingAddress.firstName}" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="lastName">* Last Name</label> <input type="text"
class="form-control" id="lastName"
placeholder="Last Name" th:name="lastName"
required="required"
th:value="${shippingAddress.lastName}" />
</div>
</div>
</div>
<div class="form-group">
<label for="shippingStreet">* Street Address</label> <input
type="text" class="form-control" id="shippingAddressStreet1"
placeholder="Street Address 1"
th:name="shippingAddressStreet1" required="required"
th:value="${shippingAddress.shippingAddressStreet1}" />
</div>
<div class="form-group">
<input type="text" class="form-control"
placeholder="Street Address 2"
th:name="shippingAddressStreet2"
th:value="${shippingAddress.shippingAddressStreet2}" />
</div>
<div class="form-group">
<label for="shippingCity">* City</label> <input type="text"
class="form-control" id="shippingAddressCity"
placeholder="Shipping City" th:name="shippingAddressCity"
required="required"
th:value="${shippingAddress.shippingAddressCity}" />
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
<label for="shippingState">* State</label> <select
id="shippingAddressState" class="form-control"
th:name="shippingAddressState"
th:value="${shippingAddress.shippingAddressState}"
required="required">
<option value="" disabled="disabled">Please select
an option</option>
<option th:each="state : ${stateList}" th:text="${state}"
th:selected="(${shippingAddress.shippingAddressState}==${state})"></option>
</select>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label for="shippingZipcode">* Zipcode</label> <input
type="text" class="form-control" id="shippingAddressZipcode"
placeholder="Shipping Zipcode"
th:name="shippingAddressZipcode" required="required"
th:value="${shippingAddress.shippingAddressZipcode}" />
</div>
</div>
</div>
<!-- a data-toggle="collapse" data-parent="#accordion"
class="btn btn-warning pull-right" href="#paymentInfo">Next</a-->
</div>
</div>
</div>
</div>
<div class="col-md-12">
<!-- Shipping Method -->
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion"
href="#shipMethod">Shipping Method</a>
</h4>
</div>
<div id="shipMethod" class="panel-collapse collapse in"
th:classappend="${classActiveCustomer}? 'in'">
<div class="panel-body">
<h4>Choose your shipping method:</h4>
<div class="radio">
<label>
<input type="radio" th:name="shippingMethod" value="groundShipping" ng-click="changeShippingMethod('groundShipping')" th:checked="${groundShipping}"/>Ground Shipping<br/>
Transit time: 3-6 business days
</label>
</div>
<div class="radio">
<label>
<input type="radio" th:name="shippingMethod" value="premiumShipping" ng-click="changeShippingMethod('premiumShipping')" th:checked="${premiumShipping}"/>Premium Shipping
<span class="text-right"><strong> $<span th:text="${siteSetting.premiumShippingCost}"></span></strong></span><br/>Transit time: 2-3 business days
</label>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-12">
<!--2. Payment Information -->
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#paymentInfo">Payment Information</a>
</h4>
</div>
<div id="paymentInfo" class="panel-collapse collapse in" th:classappend="${classActivePayment}? 'in'">
<div class="panel-body">
<div class="col-md-12">
<div id="sample"></div>
<div id="payPal" class="">
<br/>
<!-- Paypal Amount -->
<label for="amount">
<span class="input-label">Amount</span>
<div class="input-wrapper amount-wrapper">
<input id="amount" name="amount" type="hidden" min="1" placeholder="Amount" value="{{checkOut.orderTotal}}" />
</div>
</label>
<div class="bt-drop-in-wrapper">
<div id="bt-dropin"></div>
</div>
<input type="hidden" id="nonce" name="payment_method_nonce" />
<script src="https://js.braintreegateway.com/web/dropin/1.9.2/js/dropin.min.js"></script>
<script th:inline="javascript">
/*<![CDATA[*/
var form = document.querySelector('#payment-form');
var client_token = [[${clientToken}]];
braintree.dropin.create({
authorization: client_token,
// container: '#dropin-container',
container: '#bt-dropin',
card: {
cardholderName: {required: true},
postalCode: {
minlength: 5 // Set the minimum length of the postal code field
},
cvv:true,
avs:true
},
paypal: {
flow: 'vault'
}
}, function (createErr, instance) {
form.addEventListener('submit', function (event) {
event.preventDefault();
instance.requestPaymentMethod(function (err, payload) {
if (err) {
console.log('Error', err);
return;
}
// Add the nonce to the form and submit
document.querySelector('#nonce').value = payload.nonce;
form.submit();
});
});
});
// var checkout = new Demo({
// formID: 'payment-form'
// });
/*]]>*/
</script>
</div>
</div>
<!--a data-toggle="collapse" data-parent="#accordion" class="btn btn-warning pull-right" href="#reviewItems">Next</a-->
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 3. Review Items and Shipping -->
<div class="col-md-6">
<div class="panel-group" id="accordion">
<div class="col-md-12">
<!-- Contact Information -->
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion"
href="#customerInfo">Contact Information</a>
</h4>
</div>
<div id="customerInfo" class="panel-collapse collapse in"
th:classappend="${classActiveCustomer}? 'in'">
<div class="panel-body">
<div class="form-group">
<label for="phoneNumber">* Phone number</label> <input type="text"
class="form-control" id="phoneNumber"
placeholder="Phone number" th:name="phoneNumber"
required="required"
th:value="${shippingAddress.shippingAddressName}" />
</div>
<div class="form-group">
<label for="email">* Email address</label> <input
type="text" class="form-control" id="email"
placeholder="Email Address"
th:name="email" required="required"
th:value="${shippingAddress.shippingAddressStreet1}" />
</div>
</div>
</div>
</div>
</div>
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion" href="#reviewItems">Review Items and Shipping</a>
</h4>
</div>
<div id="reviewItems" class="panel-collapse collapse in">
<div class="panel-body">
<div class="row">
<div class="col-xs-6"><h4>Products</h4></div>
<div class="col-xs-2"><h4>Price</h4></div>
<div class="col-xs-2"><h4>Qty</h4></div>
<div class="col-xs-2 text-right"><h4>Amount</h4></div>
</div>
<!-- Display products in cart -->
<div class="row" th:attr="ng-repeat = 'cartItem in checkOut.cartItemList'">
<hr/>
<div class="col-xs-2">
<a th:href="@{/productDetail?id={{cartItem.product.id}}}">
<img class="img-responsive shelf-product" th:src="#{adminPath}+@{/image/product/{{cartItem.product.id}}/{{cartItem.product.coverImageName}}}" style="width:70px;" />
</a>
</div>
<div class="col-xs-4">
<div style="margin-left:50px;">
<a th:href="@{/productDetail?id={{cartItem.product.id}}}"><h4>{{cartItem.product.title}}</h4></a>
<span>Size: </span><span>{{cartItem.productSize}}</span> | <span>Web ID: </span><span>{{cartItem.product.sku}}</span>
</div>
</div>
<div class="col-xs-2">
<h5 style="color: #db3208; font-size: large;">
$<span>{{cartItem.product.ourPrice}}</span>
</h5>
</div>
<div class="col-xs-2">
<h5 style="font-size:large">{{cartItem.qty}}</h5>
</div>
<div class="col-xs-2">
<h5 class="text-primary text-right" style="font-size: large;">
$<span>{{(cartItem.product.ourPrice * cartItem.qty).toFixed(2)}}</span>
</h5>
</div>
</div>
<hr/>
<div class="row">
<div class="col-xs-7 text-left">Subtotal :</div>
<div class="col-xs-5 text-right">
$<span>{{checkOut.grandTotal.toFixed(2)}}</span>
</div>
</div>
<div class="row">
<div class="col-xs-7 text-left">Discount :</div>
<div class="col-xs-5 text-right text-danger">
-$<span>{{checkOut.discountedAmount.toFixed(2)}}</span>
</div>
</div>
<div class="row">
<div class="col-xs-7 text-left">Shipping : </div>
<div class="col-xs-5 text-right text-success">
<span>{{checkOut.shippingCost}}</span>
</div>
</div>
<div class="row">
<div class="col-xs-7 text-left">
<h3 style="color: darkred;">
<strong>Order Total : </strong>
</h3>
</div>
<div class="col-xs-5 text-right">
<h3>
<strong style="color: darkred;">$<span>{{checkOut.orderTotal.toFixed(2)}}</span></strong>
</h3>
</div>
</div>
<div class="row">
<div class="col-xs-7 text-left">You saved:</div>
<div class="col-xs-5 text-right">
$<span class="text-alert">{{checkOut.errors.toFixed(2)}}</span>
</div>
</div>
<div class="panel-footer">Shipping and handling haven't
applied.</div>
<br/><br/>
<button type="submit" class="btn btn-warning btn-block" id="submitorder">Place
your order</button>
<p style="font-size: smaller;">
By placing your order, you agree to Koly Style <a href="#">privacy</a>
notice and <a href="#">conditions</a> of use.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</section>
<div class="clear"></div>
</div>
<script th:src="@{/js/controller.js}"></script>
<!-- end of container -->
<div th:replace="common/head :: footer" />
<div th:replace="common/head :: body-bottom-scripts" />
</div>
</div>
</div>
</div>
<script src="/js/demo.js"></script>
</body>
</html>
demo.js
'use strict';
(function () {
var amount = document.querySelector('#amount');
var amountLabel = document.querySelector('label[for="amount"]');
amount.addEventListener('focus', function () {
amountLabel.className = 'has-focus';
}, false);
amount.addEventListener('blur', function () {
amountLabel.className = '';
}, false);
})();
pom.xml
<?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.kolystyle</groupId>
<artifactId>kolystyle</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>Kolystyle</name>
<description>frontend of kolystyle</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.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-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- marked the embedded servlet container as provided -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.braintreepayments.gateway</groupId>
<artifactId>braintree-java</artifactId>
<version>2.73.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>