Olá, recentemente eu venho estudando esse assunto - integrar paypal com java - e obtive alguns resultados, agora quero compartilhar com vocês algumas dicas.
Existem várias maneiras de permitir o usuário comprar algo em seu site, a mais simples é colocando um botão no seu site desta maneira:
[code]
![](https://www.paypal.com/en_US/i/scr/pixel.gif)
Esse botão direciona o comprador para o site do paypal, note que o form está direcionando para sandbox (caixa de areia), este é um servidor de testes do paypal que funciona semelhante ao paypal real. Nos testes, obviamente, você não vai gastar dinheiro, então entre no site:
Cadastre-se e depois crie duas contas, uma busines e outra buyer ou personal. Existe a opção de criar uma conta pré-configurada, porém ela não vem com o username/password/assinatura da API (mais sobre isso depois), nesse caso é interessante criar uma conta busines do zero. Porém, eles pedem um zipcode real para um estado real e só pode ser dos EUA, o phone number tem que ser correspondente ao zipcode, procure na net números de telefone para o zipcode escolhido. Criando a conta para o buyer e o seller (comprador e vendedor) você já pode usar o botão acima e fazer as compras, e checar na sua conta do sandbox as transações feitas.
Mas esse botão só funciona quando tu não quer saber em tempo real se o usuário pagou, serve só pra quando tu checa seu email do paypal. E quando tu deseja ter o resultado da compra imediatamente!? Uma das soluções é usar IPN (Instant Payment Notification) configurando mais três campos no botão e também configurando na sua conta do paypal o endereço de retorno do IPN (sandbox vocÊ configura o endereço em Test Tools e vai em Simulate IPN). Agora o botão fica assim:
[code]
Veja que está retornando para a página retorno.jsp. Essa jsp deve tratar do retorno do IPN, e deve ser semlhante a esta página:
[code]<%@ page import=“java.util." %>
<%@ page import="java.net.” %>
<%@ page import=“java.io.*” %>
<%
System.out.println(“Entrou!!!”);
// read post from PayPal system and add ‘cmd’
Enumeration en = request.getParameterNames();
String str = “cmd=_notify-validate”;
while(en.hasMoreElements()) {
String paramName = (String)en.nextElement();
String paramValue = request.getParameter(paramName);
str = str + "&" + paramName + "=" + URLEncoder.encode(paramValue);
}
// post back to PayPal system to validate
// NOTE: change http: to https: in the following URL to verify using SSL (for increased security).
// using HTTPS requires either Java 1.4 or greater, or Java Secure Socket Extension (JSSE)
// and configured for older versions.
URL u = new URL("https://www.sandbox.paypal.com/cgi-bin/webscr");
URLConnection uc = u.openConnection();
uc.setDoOutput(true);
uc.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
PrintWriter pw = new PrintWriter(uc.getOutputStream());
pw.println(str);
pw.close();
BufferedReader in = new BufferedReader(
new InputStreamReader(uc.getInputStream()));
String res = in.readLine();
in.close();
// assign posted variables to local variables
String itemName = request.getParameter("item_name");
String itemNumber = request.getParameter("item_number");
String paymentStatus = request.getParameter("payment_status");
String paymentAmount = request.getParameter("mc_gross");
String paymentCurrency = request.getParameter("mc_currency");
String txnId = request.getParameter("txn_id");
String receiverEmail = request.getParameter("receiver_email");
String payerEmail = request.getParameter("payer_email");
//check notification validation
if(res.equals("VERIFIED")) {
// check that paymentStatus=Completed
// check that txnId has not been previously processed
// check that receiverEmail is your Primary PayPal email
// check that paymentAmount/paymentCurrency are correct
// process payment
System.out.println(paymentStatus);
}
else if(res.equals("INVALID")) {
// log for investigation
}
else {
// error
}
%>[/code]
A primeira parte tu pega os parâmetros do request e envia pra eles de volta adicionando no fim: “cmd=_notify-validate”. Depois você testa a resposta e ve se foi verificado, caso for você checa o status da transação, em especial paymentStatus.
Porém, volte no botão de novo, veja que o usuário está vendo tudo, até o email do vendedor e a quantia. Para evitar isso tu deve encriptar o botão, que é meio complicado, uma soluçao seria criar esse botão e fazer o submit programaticamente em java, assim:
[code]
StringBuilder builder = new StringBuilder();
builder.append("");
builder.append("");
builder.append("<meta http-equiv=“content-type” content=“text/html; charset=”+resp.getCharacterEncoding()+" “>”
/response.ContentEncoding.BodyName/ );
builder.append("</head>");
builder.append("<body onLoad=\"document.forms[0].submit()\">");
builder.append("<form name=\"formPaypal\" target=\"" + "_self" + "\"" + "action=\""+ "https://www.sandbox.paypal.com/cgi-bin/webscr" + "\" method=\"post\">");
builder.append("<input type=\"hidden\" name=\"encoding\" value=\""+resp.getCharacterEncoding()+"\">"/*response.ContentEncoding.BodyName*/);
builder.append("<input type=\"hidden\" name=\""+ "cmd" +"\" value=\"_xclick"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "business" +"\" value=\"email_do_vendedor@com"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "item_name" +"\" value=\"Nome produto"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "item_number" +"\" value=\"701"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "amount" +"\" value=\"20.00"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "no_shipping" +"\" value=\"2"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "no_note" +"\" value=\"1"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "currency_code" +"\" value=\"USD"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "return" +"\" value=\"http://host/retorno.jsp"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "cancel_return" +"\" value=\"http://host/retorno.jsp"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "notify_url" +"\" value=\"http://host/retorno.jsp"+ "" +"\">");
builder.append("<input type=\"hidden\" name=\""+ "bn" +"\" value=\"PP-BuyNowBF"+ "" +"\">");
builder.append("</form>");
builder.append("</body>");
builder.append("</html>");
resp.getWriter().write(builder.toString());
resp.getWriter().flush();
resp.getWriter().close();[/code]
Isso deve ficar numa servlet. Veja que quando chamamos essa servlet ela mesma faz o POST simulando o click do botão.
Com isso já podemos vender algo, mas apesar disso tudo ser muito bonito, temos uma solução melhor ainda: usar SOAP. Eles disponibilizam 3 APIs Java NVP SOAP e WPS. Usando SOAP podemos pedir os dados da compra em nosso site e em background fazemos uma chamada as APIs do paypal SOAP para comunicar com o site deles e fazer o pagamento, sem botão e sem risco.
Para isso funcionar você precisa de um username/password/assinatura da api, só pode usar a API quem tem esses dados (senão qualquer progrmaador poderia acessar - através da API - a conta de qualquer um). Vamos ver um exemplo de SOAP.
[code]CallerServices caller = new CallerServices();
APIProfile profile = ProfileFactory.createSignatureAPIProfile();
/*
* WARNING: Do not embed plaintext credentials in your application
* code. Doing so is insecure and against best practices. Your API
* credentials must be handled securely. Please consider encrypting
* them for use in any production environment, and ensure that only
* authorized individuals may view or modify them.
*/
// Set up your API credentials, PayPal end point, and API version.
profile.setAPIUsername("username da API");
profile.setAPIPassword("password da API");
profile.setSignature("assinatura da api");
profile.setEnvironment("sandbox");
caller.setAPIProfile(profile);
SetExpressCheckoutRequestType setRequest = new SetExpressCheckoutRequestType();
SetExpressCheckoutRequestDetailsType setDetails = new
SetExpressCheckoutRequestDetailsType();
// DEFINE SOME BASIC CHECKOUT PARAMETERS
setDetails.setReturnURL("url de retorno, na verdade uma ação ou servlet");
setDetails.setCancelURL("cancel url");
setDetails.setPaymentAction(PaymentActionCodeType.Sale);
setDetails.setOrderDescription("description");
// SET THE ORDER AMOUNT
BasicAmountType amount = new BasicAmountType();
amount.setCurrencyID(CurrencyCodeType.USD);
amount.set_value("99.99");
setDetails.setOrderTotal(amount);
setRequest.setSetExpressCheckoutRequestDetails(setDetails);
SetExpressCheckoutResponseType setResponse =
(SetExpressCheckoutResponseType)caller.call("SetExpressCheckout", setRequest);
// REDIRECT THE CUSTOMER TO PAYPAL?S WEBSITE FOR AUTHENTICATION
String token = setResponse.getToken();
response.sendRedirect("https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=" + token);[/code]
Pronto, isso redireciona o usuário pro site do paypal para ele confirmar o pagamento com sua conta no paypal.
O retorno que será também um servlet, servirá para terminar a compra e checar o status da transação. Veja abaixo.
[code]
try {
CallerServices caller = new CallerServices();
APIProfile profile = ProfileFactory.createSignatureAPIProfile();
/*
* WARNING: Do not embed plaintext credentials in your application
* code. Doing so is insecure and against best practices. Your API
* credentials must be handled securely. Please consider encrypting
* them for use in any production environment, and ensure that only
* authorized individuals may view or modify them.
*/
// Set up your API credentials, PayPal end point, and API version.
profile.setAPIUsername("...");
profile.setAPIPassword("...");
profile.setSignature("...");
profile.setEnvironment("sandbox");
caller.setAPIProfile(profile);
GetExpressCheckoutDetailsRequestType getRequest = new
GetExpressCheckoutDetailsRequestType();
// GET THE SESSION TOKEN FROM THE HTTP REQUEST
String token = request.getParameter("token");
getRequest.setToken(token);
// MAKE THE API CALL TO GET BUYER DETAILS
GetExpressCheckoutDetailsResponseType getResponse =
(GetExpressCheckoutDetailsResponseType)caller.call("GetExpressCheckoutDetails",
getRequest);
// EXTRACT SOME DATA ABOUT THE BUYER
GetExpressCheckoutDetailsResponseDetailsType details =
getResponse.getGetExpressCheckoutDetailsResponseDetails();
String total = details.getCustom();
PayerInfoType payer = details.getPayerInfo();
String payerID = payer.getPayerID();
PersonNameType name = payer.getPayerName();
AddressType address = payer.getAddress();
DoExpressCheckoutPaymentRequestType doRequest = new
DoExpressCheckoutPaymentRequestType();
DoExpressCheckoutPaymentRequestDetailsType doDetails = new
DoExpressCheckoutPaymentRequestDetailsType();
// SET DETAILS ABOUT THE FINAL TRANSACTION AMOUNT
doDetails.setPayerID(request.getParameter("PayerID"));
doDetails.setPaymentAction(PaymentActionCodeType.Sale);
doDetails.setToken(token);
PaymentDetailsType paymentDetails = new PaymentDetailsType();
BasicAmountType amount = new BasicAmountType();
amount.setCurrencyID(CurrencyCodeType.USD);
amount.set_value("10.00");
paymentDetails.setOrderTotal(amount);
doDetails.setPaymentDetails(paymentDetails);
doRequest.setDoExpressCheckoutPaymentRequestDetails(doDetails);
DoExpressCheckoutPaymentResponseType doResponse =
(DoExpressCheckoutPaymentResponseType)caller.call("DoExpressCheckoutPayment", doRequest);
DoExpressCheckoutPaymentResponseDetailsType details2 =
doResponse.getDoExpressCheckoutPaymentResponseDetails();
if (doResponse.getAck() == AckCodeType.Success) {
System.out.println(
"Status" +
doResponse.getDoExpressCheckoutPaymentResponseDetails().
getPaymentInfo().
getPaymentStatus());
Check.transactionId = doResponse.getDoExpressCheckoutPaymentResponseDetails().getPaymentInfo().getTransactionID();
Check check = new Check();
check.start();
System.out.println("Sucesso na transacao");
}
} catch(PayPalException e) {
e.printStackTrace();
}[/code]
Isso vai mostrar pra você o status da transação, falta ainda criar a classe Check que será uma thread, ela fica verificando o status da transação, quando for “Completed” você libera oque tá vendendo! A classe check é mostrada a seguir:
[code]public class Check extends Thread {
static public String transactionId;
public Check() {
}
public void run() {
while(true) {
System.out.println(getTransactionDetailsCode(transactionId));
try {
sleep(20000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public String getTransactionDetailsCode(String transactionId)
{
CallerServices caller = new CallerServices();
String responseValue = null;
try {
APIProfile profile = ProfileFactory.createSignatureAPIProfile();
/*
WARNING: Do not embed plaintext credentials in your application code.
Doing so is insecure and against best practices.
Your API credentials must be handled securely. Please consider
encrypting them for use in any production environment, and ensure
that only authorized individuals may view or modify them.
*/
// Set up your API credentials, PayPal end point, and API version.
profile.setAPIUsername("...");
profile.setAPIPassword("..");
profile.setSignature("...");
profile.setEnvironment("sandbox");
caller.setAPIProfile(profile);
GetTransactionDetailsRequestType pprequest = new GetTransactionDetailsRequestType();
pprequest.setVersion("58.0");
// Add request-specific fields to the request.
pprequest.setTransactionID(transactionId);
// Execute the API operation and obtain the response.
GetTransactionDetailsResponseType ppresponse =
(GetTransactionDetailsResponseType) caller.call("GetTransactionDetails", pprequest);
System.out.println(ppresponse.getPaymentTransactionDetails().getPaymentInfo().getPaymentStatus());
responseValue = ppresponse.getAck().toString();
}catch(Exception ex)
{
ex.printStackTrace();
}
return responseValue;
}
}[/code]
Bom, isso é o que tenho a dizer sobre o paypal…