Uma das funcionalidades mais importantes da maioria dos apps mobile de hoje em dia é a possibilidade de se integrar com plataformas de pagamento online, tais como PagSeguro, MercadoPago ou a mais famosa de todas (a nível internacional): PayPal.
Na maioria dos apps de eCommerce, que se caracterizam principalmente por compras e vendas online, não basta somente ter uma boa interface e lógica de negócio implementadas, é também preciso gerenciar tudo isso de forma segura, e para isso precisamos fazer uso de Web Services, bancos de dados, aplicações e outros tipos de recursos e operações no lado do servidor.
Com o objetivo de cobrir uma implementação pouco vista em português, esse artigo, dividido em duas partes, visa ensinar como construir uma aplicação básica em Android, usando a biblioteca SDK do PayPal, uma integração server side com um projeto em Java Web, que fará uso de requisições HTTP via Web Services Restful (implementação Jersey) e salvará os dados em um schema MySQL.
Você poderá efetuar o download do código fonte diretamente do meu GitHub, no botão abaixo:
DOWNLOAD CÓDIGO
Na Figura 1 abaixo você pode visualizar como ficarão nossas telas ao final da implementação:
Veja no vídeo abaixo como se dará o fluxo de execução da nossa implementação:
Acesse a página, logue ou crie uma nova conta se não for registrado ainda, e em seguida acesse a página de Apps.
Após isso, crie uma nova aplicação, dê um nome, selecione a sua conta de desenvolvedor e finaliza, tal como exibido na Figura 2.
Uma vez criada, a app será redirecionada para a página com os dados da mesma, dentre os quais se destacam as informações de Client ID (Identificador do cliente) e Secret (Senha) que deverão ser guardadas para uso nas chamadas futuras que faremos com a API (Figura 3).
Para fazer uso real desse ambiente, basta ir na opção "Sandbox > Accounts" na mesma página exibida na Figura 2 e selecionar o email com o sufixo "-buyer" (que corresponde ao email da conta de teste). Clique no link "Profile" e modifique a senha na aba "Profile" (já selecionada). A Figura 4 mostra a opção na mesma aba e uma representação da aba Funding, onde podemos ver o saldo disponível para testes na conta em questão.
Já em relação às tecnologias usadas, temos a seguinte relação:
Para implementar o nosso projeto, precisaremos ainda efetuar o download de dois pacotes do PayPal:
O SQL de geração do modelo apresentado pode ser encontrado na listagem abaixo. Rode o mesmo script no seu banco MySQL.
O código sku é um código usado pelo PayPal para gerenciar os produtos. Você pode criar os seus próprios, porém no padrão mostrado.
Após isso, adicione as libs baixadas do Jersey, Gson e MySQL Connector J na pasta WEB-INF/lib do projeto igual às da Figura 7 na pasta src.
Após isso, a primeira configuração importante é a do Servlet do Jersey no web.xml. Adicione o conteúdo da listagem abaixo a esse arquivo, de modo a termos os Web Services rest prontos para serem usados:
Em seguida precisamos criar as entidades que conterão os dados como POJOS Java comuns para serem usados depois. Veja na listagem abaixo toda as quatro entidades que devem ser criados dentro do pacote br.edu.ecommerce.entidades:
Agora é hora de configurar as nossas classes DAO para lidar com a persistência das informações relacionadas aos produtos. Veja na listagem abaixo todos os métodos que usaremos no projeto, portanto, adicione-os à uma nova classe no pacote br.edu.ecommerce.dao.
Agora é hora de criar os métodos do nosso Web Service Restful que irá atuar como fachada de recebimento das requisições provindas do app Android. Veja na listagem abaixo o código que precisaremos criar na nova classe do pacote br.edu.ecommerce.rest:
O primeiro método lista todos os produtos vindos da base de acordo com o parâmetro de filtro enviado. O segundo é o método de verificação do pagamento, para nos assegurar de que o mesmo está correto e aprovado. Perceba que logo no início carregamos o objeto do tipo OAuthTokenCredential a partir de um arquivo "sdk_config.properties" que deve estar na raiz da pasta src do projeto. O conteúdo desse arquivo está listado na próxima listagem abaixo. No final do método, salvamos a informação do pagamento e, se estiver tudo ok, salvamos a venda em seguida através do último método da classe. Nesse momento, o código sku também se faz importante.
-->
Na maioria dos apps de eCommerce, que se caracterizam principalmente por compras e vendas online, não basta somente ter uma boa interface e lógica de negócio implementadas, é também preciso gerenciar tudo isso de forma segura, e para isso precisamos fazer uso de Web Services, bancos de dados, aplicações e outros tipos de recursos e operações no lado do servidor.
Com o objetivo de cobrir uma implementação pouco vista em português, esse artigo, dividido em duas partes, visa ensinar como construir uma aplicação básica em Android, usando a biblioteca SDK do PayPal, uma integração server side com um projeto em Java Web, que fará uso de requisições HTTP via Web Services Restful (implementação Jersey) e salvará os dados em um schema MySQL.
Você poderá efetuar o download do código fonte diretamente do meu GitHub, no botão abaixo:
DOWNLOAD CÓDIGO
Na Figura 1 abaixo você pode visualizar como ficarão nossas telas ao final da implementação:
Resumo
O PayPal disponibiliza três formas distintas para efetuar pagamentos via sua API, a saber:- Single Payment: Recebe o pagamento imediatamente.
- Future Payments: Usado para fazer pagamentos agendados ou recorrentes.
- Profile Sharing: Quando queremos determinados dados sobre o cliente.
Veja no vídeo abaixo como se dará o fluxo de execução da nossa implementação:
Criando App no PayPal
Para fazer uso dos serviços do PayPal mostrados no vídeo, nós precisaremos antes criar uma conta no site developer.paypal.com, em alusão ao que já ocorre com o padrão oAuth em empresas como Google, Facebook, etc.Acesse a página, logue ou crie uma nova conta se não for registrado ainda, e em seguida acesse a página de Apps.
Após isso, crie uma nova aplicação, dê um nome, selecione a sua conta de desenvolvedor e finaliza, tal como exibido na Figura 2.
Uma vez criada, a app será redirecionada para a página com os dados da mesma, dentre os quais se destacam as informações de Client ID (Identificador do cliente) e Secret (Senha) que deverão ser guardadas para uso nas chamadas futuras que faremos com a API (Figura 3).
Conta de Testes: PayPal Sandbox
O PayPal fornece um ambiente de teste integrado chamado sandbox. Ele será muito útil pois vem com contas configuradas automaticamente com quantias em dinheiro para teste, o que nos poupa o trabalho de usar algo real.Para fazer uso real desse ambiente, basta ir na opção "Sandbox > Accounts" na mesma página exibida na Figura 2 e selecionar o email com o sufixo "-buyer" (que corresponde ao email da conta de teste). Clique no link "Profile" e modifique a senha na aba "Profile" (já selecionada). A Figura 4 mostra a opção na mesma aba e uma representação da aba Funding, onde podemos ver o saldo disponível para testes na conta em questão.
Downloads e Configurações
Como estamos usando tecnologias distintas (mobile, server e bd), é interessante que você selecione as IDEs, banco, SGBD e emuladores que se sinta mais confortável. Neste artigo, estarei usando as seguintes ferramentas:- Eclipse IDE for Java EE Developers - Luna
- MySQL Workbench 6.1
- Emulador Genymotion 2.3.1 (plugin do Eclipse)
Já em relação às tecnologias usadas, temos a seguinte relação:
Para implementar o nosso projeto, precisaremos ainda efetuar o download de dois pacotes do PayPal:
- A API do PayPal para Java, que fornece os mesmos recursos do SDK para fazer a comunicação com os serviços PayPal. Essa API também pode ser usada normalmente em um projeto Java Web qualquer que precise dos mesmos serviços.
- E o SDK do PayPal para Android.
- PayPal Rest SDK: http://mvnrepository.com/artifact/com.paypal.sdk/rest-api-sdk/1.2.0
- Dependência do SLF4J: http://mvnrepository.com/artifact/org.slf4j/slf4j-api/1.7.10
- MySQL Connector J: http://dev.mysql.com/downloads/connector/j/
- Libs do Jersey Restful: https://jersey.java.net/nonav/download.html
- Lib do Google Gson (Para conversão de JSON para Java e vice versa): https://code.google.com/p/google-gson/
Criando o Banco de Dados
O nosso modelo de base de dados (Figura 5) será composto por seis tabelas distintas. A tabela tb_usuario salvará os dados básicos do usuário, como login, senha, etc. tb_pagamento se encarregará de guardar um histórico com todos os dados de quaisquer pagamentos que tenham sido feitos, com ou sem sucesso. tb_venda guardará as vendas finalizadas e aprovadas e se comunicará com tb_produto que terá a listagem de todos os produtos disponíveis. Cada produto tem uma ou mais categorias e vice versa, por isso temos uma tabela intermediária para representar o relacionamento muitos-pra-muitos.O SQL de geração do modelo apresentado pode ser encontrado na listagem abaixo. Rode o mesmo script no seu banco MySQL.
CREATE SCHEMA IF NOT EXISTS `ecommerce-teste` DEFAULT CHARACTER SET utf8 ;
USE `ecommerce-teste` ;
-- -----------------------------------------------------
-- Table `ecommerce-teste`.`tb_categoria`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `ecommerce-teste`.`tb_categoria` (
`id_categoria` INT(11) NOT NULL AUTO_INCREMENT,
`descricao` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id_categoria`))
ENGINE = InnoDB
AUTO_INCREMENT = 5
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `ecommerce-teste`.`tb_produto`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `ecommerce-teste`.`tb_produto` (
`id_produto` INT(11) NOT NULL AUTO_INCREMENT,
`titulo` VARCHAR(45) NOT NULL,
`qtde` INT(11) NOT NULL,
`valor` DOUBLE NOT NULL,
`img` VARCHAR(1500) NOT NULL,
`sku` TEXT NOT NULL,
PRIMARY KEY (`id_produto`))
ENGINE = InnoDB
AUTO_INCREMENT = 5
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `ecommerce-teste`.`tb_produto_categoria`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `ecommerce-teste`.`tb_produto_categoria` (
`id_produto` INT(11) NOT NULL,
`id_categoria` INT(11) NOT NULL,
PRIMARY KEY (`id_produto`, `id_categoria`),
INDEX `fk_tb_produto_has_tb_categoria_tb_categoria1_idx` (`id_categoria` ASC),
INDEX `fk_tb_produto_has_tb_categoria_tb_produto_idx` (`id_produto` ASC),
CONSTRAINT `fk_tb_produto_has_tb_categoria_tb_categoria1`
FOREIGN KEY (`id_categoria`)
REFERENCES `ecommerce-teste`.`tb_categoria` (`id_categoria`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_tb_produto_has_tb_categoria_tb_produto`
FOREIGN KEY (`id_produto`)
REFERENCES `ecommerce-teste`.`tb_produto` (`id_produto`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `ecommerce-teste`.`tb_usuario`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `ecommerce-teste`.`tb_usuario` (
`id_usuario` INT(11) NOT NULL AUTO_INCREMENT,
`login` VARCHAR(45) NOT NULL,
`senha` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id_usuario`))
ENGINE = InnoDB
AUTO_INCREMENT = 6
DEFAULT CHARACTER SET = utf8;
-- -----------------------------------------------------
-- Table `ecommerce-teste`.`tb_pagamento`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `ecommerce-teste`.`tb_pagamento` (
`id_pagamento` INT NOT NULL AUTO_INCREMENT,
`pagtoPaypalId` TEXT NOT NULL,
`estado` VARCHAR(15) NOT NULL,
`valor` DECIMAL(6,2) NOT NULL,
`moeda` VARCHAR(3) NOT NULL,
`idUsuario` INT(11) NOT NULL,
PRIMARY KEY (`id_pagamento`),
INDEX `fk_tb_pagamento_tb_usuario1_idx` (`idUsuario` ASC),
CONSTRAINT `fk_tb_pagamento_tb_usuario1`
FOREIGN KEY (`idUsuario`)
REFERENCES `ecommerce-teste`.`tb_usuario` (`id_usuario`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `ecommerce-teste`.`tb_venda`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `ecommerce-teste`.`tb_venda` (
`id_venda` INT NOT NULL AUTO_INCREMENT,
`estado` VARCHAR(45) NOT NULL,
`preco` DECIMAL(6,2) NOT NULL,
`qtde` INT(4) NOT NULL,
`produtoId` INT(11) NOT NULL,
`pagtoId` INT NOT NULL,
PRIMARY KEY (`id_venda`),
INDEX `fk_tb_venda_tb_produto1_idx` (`produtoId` ASC),
INDEX `fk_tb_venda_tb_pagamento1_idx` (`pagtoId` ASC),
CONSTRAINT `fk_tb_venda_tb_produto1`
FOREIGN KEY (`produtoId`)
REFERENCES `ecommerce-teste`.`tb_produto` (`id_produto`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_tb_venda_tb_pagamento1`
FOREIGN KEY (`pagtoId`)
REFERENCES `ecommerce-teste`.`tb_pagamento` (`id_pagamento`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
As tabelas de produtos e usuários são as únicas que você precisará popular diretamente na base. Você pode preencher com seus próprios dados, ou pode utilizar a referência abaixo:O código sku é um código usado pelo PayPal para gerenciar os produtos. Você pode criar os seus próprios, porém no padrão mostrado.
Criando o Projeto Java Web
No Eclipse, com o Tomcat já configurado e funcional, selecione a perspectiva Java EE no canto superior direito, e vá até o menu "File > New > Dynamic Web Project". Clique em "Next" até a tela de "Web Module" e marque a opção de geração do web.xml descrita na Figura 6, e clique em finalizar.Após isso, adicione as libs baixadas do Jersey, Gson e MySQL Connector J na pasta WEB-INF/lib do projeto igual às da Figura 7 na pasta src.
Após isso, a primeira configuração importante é a do Servlet do Jersey no web.xml. Adicione o conteúdo da listagem abaixo a esse arquivo, de modo a termos os Web Services rest prontos para serem usados:
<servlet>
<servlet-name>Jersey Rest</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>br.edu.ecommerce.rest</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Rest</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Após isso, precisamos criar uma classe de comunicação direta com o banco MySQL, para fornecer objetos Connection há cada nova ação de persistência. Para isso, crie a classe da listagem abaixo dentro do pacote br.edu.ecommerce.db:package br.edu.ecommerce.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBUtil {
public static Connection getConnexao() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.jdbc.Driver");
return DriverManager.getConnection("jdbc:mysql://localhost:3306/ecommerce-teste", "root", "root");
}
}
Modifique os valores de usuário e senha de acordo com os configurados para o seu banco em específico.Em seguida precisamos criar as entidades que conterão os dados como POJOS Java comuns para serem usados depois. Veja na listagem abaixo toda as quatro entidades que devem ser criados dentro do pacote br.edu.ecommerce.entidades:
public class Usuario {
private int id;
private String login;
private String senha;
private boolean logado;
// get's e set's
}
public class Pagamento {
private int id;
private String pagtoPaypalId;
private String estado;
private String moeda;
private double valor;
private Usuario usuario;
// get's e set's
}
public class Venda {
private int id;
private String estado;
private double preco;
private int qtde;
private Pagamento pagamento;
private Produto produto;
// get's e set's
}
public class Produto {
private int id;
private String titulo;
@SerializedName("imagem")
private String img;
private int qtde;
private double valor;
private String sku;
private List<String> categoria;
private List<Venda> vendas;
// get's e set's
}
Perceba que a classe Produto tem seu atributo img anotado com a anotação @SerializeName pertencente ao Gson, e que define o nome com o qual esse valor será serializado quando transformado para JSON.Agora é hora de configurar as nossas classes DAO para lidar com a persistência das informações relacionadas aos produtos. Veja na listagem abaixo todos os métodos que usaremos no projeto, portanto, adicione-os à uma nova classe no pacote br.edu.ecommerce.dao.
package br.edu.ecommerce.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import br.edu.ecommerce.db.DBUtil;
import br.edu.ecommerce.entidades.Pagamento;
import br.edu.ecommerce.entidades.Produto;
import br.edu.ecommerce.entidades.Venda;
public class ProdutoDAO {
public List<Produto> listarProdutos() {
List<Produto> resultado = new ArrayList<Produto>();
Connection con = null;
try {
con = DBUtil.getConnexao();
String sql = "SELECT * FROM TB_PRODUTO";
PreparedStatement st = con.prepareStatement(sql);
ResultSet rs = st.executeQuery();
while (rs.next()) {
Produto produto = new Produto();
int idProduto = rs.getInt("id_produto");
produto.setId(idProduto);
produto.setTitulo(rs.getString("titulo"));
produto.setQtde(rs.getInt("qtde"));
produto.setSku(rs.getString("sku"));
produto.setValor(rs.getDouble("valor"));
produto.setImg(rs.getString("img"));
produto.setCategoria(consultarCategoriasPorId(idProduto));
resultado.add(produto);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return resultado;
}
public Produto consultarPorSku(String sku) {
Produto produto = new Produto();
Connection con = null;
try {
con = DBUtil.getConnexao();
String sql = "SELECT * FROM TB_PRODUTO";
if (sku != null) {
sql += " WHERE SKU = ?";
}
PreparedStatement st = con.prepareStatement(sql);
if (sku != null) {
st.setString(1, sku);
}
ResultSet rs = st.executeQuery();
if (rs.next()) {
int idProduto = rs.getInt("id_produto");
produto.setId(idProduto);
produto.setTitulo(rs.getString("titulo"));
produto.setQtde(rs.getInt("qtde"));
produto.setSku(rs.getString("sku"));
produto.setValor(rs.getDouble("valor"));
produto.setImg(rs.getString("img"));
produto.setCategoria(consultarCategoriasPorId(idProduto));
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return produto;
}
public List<String> consultarCategoriasPorId(int idProduto) {
List<String> resultado = new ArrayList<String>();
Connection con = null;
try {
con = DBUtil.getConnexao();
StringBuilder sql = new StringBuilder();
sql.append("SELECT ");
sql.append(" cat.descricao");
sql.append(" FROM");
sql.append(" tb_categoria cat");
sql.append(" INNER JOIN");
sql.append(" tb_produto_categoria pc ON cat.id_categoria = pc.id_categoria");
sql.append(" WHERE");
sql.append(" pc.id_produto = ?");
PreparedStatement st = con.prepareStatement(sql.toString());
st.setInt(1, idProduto);
ResultSet rs = st.executeQuery();
while (rs.next()) {
resultado.add(rs.getString("descricao"));
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return resultado;
}
public int salvarPagto(Pagamento pagamento) {
int chaveGerada = 0;
Connection con = null;
try {
con = DBUtil.getConnexao();
String sql = "INSERT INTO TB_PAGAMENTO(PAGTOPAYPALID, ESTADO, VALOR, MOEDA, IDUSUARIO) VALUES (?, ?, ?, ?, ?)";
PreparedStatement st = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
st.setString(1, pagamento.getPagtoPaypalId());
st.setString(2, pagamento.getEstado());
st.setDouble(3, pagamento.getValor());
st.setString(4, pagamento.getMoeda());
st.setInt(5, pagamento.getUsuario().getId());
st.execute();
ResultSet rs = st.getGeneratedKeys();
if(rs.next()) {
chaveGerada = rs.getInt(1);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return chaveGerada;
}
public List<Produto> salvarVenda(Venda venda) {
List<Produto> resultado = new ArrayList<Produto>();
Connection con = null;
try {
con = DBUtil.getConnexao();
String sql = "INSERT INTO TB_VENDA(ESTADO, PRECO, QTDE, PRODUTOID, PAGTOID) VALUES (?, ?, ?, ?, ?)";
PreparedStatement st = con.prepareStatement(sql);
st.setString(1, venda.getEstado());
st.setDouble(2, venda.getPreco());
st.setInt(3, venda.getQtde());
st.setInt(4, venda.getProduto().getId());
st.setInt(5, venda.getPagamento().getId());
st.execute();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return resultado;
}
}
Na mesma listagem, temos os seguintes métodos e suas funções:- listarProdutos: Faz uma listagem simples dos produtos na base preenchendo os valores e chamando o método consultarCategoriasPorId() para buscar as categorias de cada produto.
- consultarPorSku: Método que busca os valores pelo código sku já falado antes.
- salvarPagto: Método que efetua o salvamento do pagamento. Note que ele deverá ser chamado sempre após qualquer tentativa de fazer um pagamento. Repare também que estamos usando o recurso RETURN_GENERATED_KEYS do Statement JDBC, isso serve para nos retornar o id autogerado de cada produto, uma vez que iremos precisar dele para salvar o relacionamento com a venda.
- salvarVenda: Método que salva a venda final.
package br.edu.ecommerce.util;
public class Util {
public static StringBuilder converterJSONUTF8(List<Produto> produtos) {
Gson gson = new Gson();
StringBuilder produtosJson = new StringBuilder();
String string;
try {
InputStream inputStream = new ByteArrayInputStream(gson.toJson(produtos).getBytes(StandardCharsets.UTF_8));
if (inputStream != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while (null != (string = reader.readLine())) {
produtosJson.append(string);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return produtosJson;
}
}
package br.edu.ecommerce.rest;
public class Response {
private String msg;
private boolean erro;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public boolean isErro() {
return erro;
}
public void setErro(boolean erro) {
this.erro = erro;
}
}
package br.edu.ecommerce.entidades;
import com.google.gson.annotations.SerializedName;
public class PagamentoCliente {
@SerializedName("amount")
private double quantia;
@SerializedName("currency_code")
private String moeda;
public double getQuantia() {
return quantia;
}
public void setQuantia(double quantia) {
this.quantia = quantia;
}
public String getMoeda() {
return moeda;
}
public void setMoeda(String moeda) {
this.moeda = moeda;
}
}
A primeira classe é um utilitário que nos ajudará a fazer a converter todo o nosso conteúdo JSON para UTF-8, uma vez que lidaremos com valores de URLs, acentos e caracteres especiais via HTTP. A segunda classe é um POJO simples para lidar com as respostas que enviaremos ao app Android e a terceira lidará com o salvamento das informações de cada pagamento que virão serializadas também do app Android.Agora é hora de criar os métodos do nosso Web Service Restful que irá atuar como fachada de recebimento das requisições provindas do app Android. Veja na listagem abaixo o código que precisaremos criar na nova classe do pacote br.edu.ecommerce.rest:
package br.edu.ecommerce.rest;
// Imports omitidos. Use Ctrl + Shift + O para organizá-los no Eclipse.
@Path("produto")
public class ProdutosRest {
private ProdutoDAO produtoDAO = new ProdutoDAO();
@Path("produtos")
@GET
@Produces(MediaType.APPLICATION_JSON)
public String getProdutos(@QueryParam("str") String str) {
return Util.converterJSONUTF8(produtoDAO.consultarPorTitulo(str)).toString();
}
@Path("checkPagto")
@POST
@Produces(MediaType.APPLICATION_JSON)
public Response verificarPagto(@FormParam("idPagto") String idPagto, @FormParam("jsonClientePagto") String jsonClientePagto, @FormParam("idUsuario") String idUsuario) {
br.edu.ecommerce.rest.Response r = new br.edu.ecommerce.rest.Response();
try {
OAuthTokenCredential tokenCredential = Payment.initConfig(getClass().getClassLoader().getResourceAsStream("sdk_config.properties"));
String accessToken = tokenCredential.getAccessToken();
APIContext apiContext = new APIContext(accessToken);
Payment pagto = Payment.get(apiContext, idPagto);
if (!pagto.getState().equals("approved")) {
r.setErro(true);
r.setMsg("Pagamento não verificado. Status: ");
return Response.ok(new Gson().toJson(r), MediaType.APPLICATION_JSON).build();
}
Gson gson = new Gson();
PagamentoCliente pagtoParam = gson.fromJson(jsonClientePagto, PagamentoCliente.class);
double valorCliente = pagtoParam.getQuantia();
String moedaCliente = pagtoParam.getMoeda();
Transaction trans = pagto.getTransactions().get(0);
String valorServidor = trans.getAmount().getTotal();
String moedaServidor = trans.getAmount().getCurrency();
String estadoVenda = trans.getRelatedResources().get(0).getSale().getState();
Pagamento pagtoFinal = new Pagamento();
pagtoFinal.setEstado(pagto.getState());
pagtoFinal.setPagtoPaypalId(pagto.getId());
Usuario usuario = new Usuario();
usuario.setId(idUsuario != null ? Integer.parseInt(idUsuario) : 1);
pagtoFinal.setUsuario(usuario);
pagtoFinal.setMoeda(moedaCliente);
pagtoFinal.setValor(Double.parseDouble(valorServidor));
int idPagtoBD = produtoDAO.salvarPagto(pagtoFinal);
pagtoFinal.setId(idPagtoBD);
if (Double.parseDouble(valorServidor) != valorCliente) {
r.setErro(true);
r.setMsg("Quantias de pagamento não conferem!");
return Response.ok(new Gson().toJson(r), MediaType.APPLICATION_JSON).build();
}
if (!moedaServidor.equals(moedaCliente)) {
r.setErro(true);
r.setMsg("Moedas de pagamento não conferem!");
return Response.ok(new Gson().toJson(r), MediaType.APPLICATION_JSON).build();
}
if (!estadoVenda.equals("completed")) {
r.setErro(true);
r.setMsg("Venda não completada!");
return Response.ok(new Gson().toJson(r), MediaType.APPLICATION_JSON).build();
}
inserirItensVendas(pagtoFinal, trans, estadoVenda);
} catch (PayPalRESTException ex) {
ex.printStackTrace();
return Response.serverError().entity("Erro na comunicação com o PayPal. Favor tentar novamente!").build();
}
r.setErro(false);
r.setMsg("Pagamento verificado com sucesso!");
return Response.ok(new Gson().toJson(r), MediaType.APPLICATION_JSON).build();
}
private void inserirItensVendas(Pagamento pagtoFinal, Transaction trans, String estadoVenda) {
ItemList listaItens = trans.getItemList();
for (Item i : listaItens.getItems()) {
Venda venda = new Venda();
venda.setQtde(Integer.parseInt(i.getQuantity()));
venda.setPreco(Double.parseDouble(i.getPrice()));
venda.setPagamento(pagtoFinal);
venda.setEstado(estadoVenda);
Produto produto = produtoDAO.consultarPorSku(i.getSku());
venda.setProduto(produto);
produtoDAO.salvarVenda(venda);
}
}
}
Essa classe usa essencialmente Rest e anotações da API do Jersey. Se não conhece bem como funciona esse tipo de WS e/ou tecnologia, dê uma pesquisada na documentação oficial do projeto.O primeiro método lista todos os produtos vindos da base de acordo com o parâmetro de filtro enviado. O segundo é o método de verificação do pagamento, para nos assegurar de que o mesmo está correto e aprovado. Perceba que logo no início carregamos o objeto do tipo OAuthTokenCredential a partir de um arquivo "sdk_config.properties" que deve estar na raiz da pasta src do projeto. O conteúdo desse arquivo está listado na próxima listagem abaixo. No final do método, salvamos a informação do pagamento e, se estiver tudo ok, salvamos a venda em seguida através do último método da classe. Nesse momento, o código sku também se faz importante.
# Connection Information
http.ConnectionTimeOut=5000
http.Retry=1
http.ReadTimeOut=30000
http.MaxConnection=100
# HTTP Proxy configuration
# If you are using proxy set http.UseProxy to true and replace the following values with your proxy parameters
http.ProxyPort=8080
http.ProxyHost=127.0.0.1
http.UseProxy=false
http.ProxyUserName=null
http.ProxyPassword=null
#Set this property to true if you are using the PayPal SDK within a Google App Engine java app
http.GoogleAppEngine = false
# Service Configuration
service.EndPoint=https://api.sandbox.paypal.com
# Live EndPoint
# service.EndPoint=https://api.paypal.com
# Credentials
clientId=AbkVNdXzruEZ6FEGaJB6TBfB_-4qmlqLPAQj5qin4FI8cS3v0Vs2pjldttP4MgmF487ZyVZ2y34j4xPE
clientSecret=EDYpA14ZmKc8pXqFe9CHWYJkkqu-6z1NxduRpeIHsr_O37QIgZK7vYd3R6ElsKpsPbQ55VbVo8ps3KuE
Esse arquivo pode ser encontrado dentro do pacote de download do projeto PayPal-Java-SDK no Github, bastando simplesmente alterar as informações de clientId e clientSecret para as do seu app.Concluindo
Com isso, nós finalizamos os ajustes na parte web e de bando de dados do nosso projeto. Na segunda parte do artigo, iremos construir o projeto Android, configurar a exibição dos produtos e fazer as requisições para os métodos de serviço que criamos hoje. Até já! :)-->
Cara, parabéns pelo tutorial. Estou finalizando algumas etapas de um projeto e assim que finalizar seguirei seu tutorial. Mas parabéns, muito bem explicado e deu pra ter uma noção boa de como integrar o Android com PayPal. Muito grato pela divulgação deste conteúdo. Abs
ResponderExcluirOpa Luiz,
ExcluirFico feliz que tenha gostado. Avante! :)
Domino programação asp, mas sou iniciante na programação Android. Pode me passar um bom livro para trabalhar com banco de dados externo mysql, listar produtos, cadastro e login? Vejo que o seu é exatamente isso e mais, mas ainda me parece complicado seguir o codigo. Ou você dá alguma ajuda presencial? Grato
ResponderExcluirFala Omar, tudo bem?
ExcluirUm dos melhores livros que conheço sobre Android é o https://novatec.com.br/livros/google-android-5ed/
Nele, você encontra tudo que precisa sobre esse tipo de conteúdo!
Infelizmente estou sem tempo hábil para dar consultorias... :(
Diogo sou seu fã.
ResponderExcluirAcompanho os seus artigos sempre que posso e sempre são demais.
Você já fez alguma integração com o PagSeguro ?
Onde eu poderia encontrar a documentação para integração com o do PagSeguro ?
Fala Ueder, que bom que curte o material.. :)
ExcluirNunca fiz integrações com eles, mas eles têm uma documentação recente atualizada que tá bem legal, vê só: https://dev.pagseguro.uol.com.br/bibliotecas/java