Neste tutorial pretendo mostrar de forma simples como criar um Web Service em Java utilizando o NetBeans e uma aplicação cliente para consumir o serviço no Android. O Web Service vai implementar uma operação que deverá retornar um array de objetos. Na aplicação Android esse array será recebido e utilizado para preencher uma lista de itens (ListView).
Ferramentas utilizadas:
- NetBeans 7.1 + Tomcat 7 (servidor)
- Eclipse + ADT - Android Developer Tools v21.0.1-543035 (cliente)
Criando o Web Service
Não vou entrar em detalhes sobre a criação da aplicação no NetBeans porque já existe um bom tutorial disponível aqui. Após criar o projeto, crie também uma classe para o objeto que será retornado. Para fins de exemplo vou utilizar a seguinte classe:
public class Fornecedor { int codigo; String razaoSocial; String cpfCnpj; public Fornecedor() { } public Fornecedor(int codigo, String razaoSocial, String cpfCnpj) { this.codigo = codigo; this.razaoSocial = razaoSocial; this.cpfCnpj = cpfCnpj; } public int getCodigo() { return codigo; } public void setCodigo(int codigo) { this.codigo = codigo; } public String getCpfCnpj() { return cpfCnpj; } public void setCpfCnpj(String cpfCnpj) { this.cpfCnpj = cpfCnpj; } public String getRazaoSocial() { return razaoSocial; } public void setRazaoSocial(String razaoSocial) { this.razaoSocial = razaoSocial; } @Override public String toString() { return getCodigo() + ". " + getRazaoSocial(); } }
É importante que sua classe tenha um construtor padrão, sem argumentos. Pode parecer inútil mas o Tomcat não vai implantar o projeto sem ele. O método toString deverá ser sobrescrito na classe, mas isto será útil apenas na aplicação cliente ao preencher a lista, pois será utilizada a mesma classe.
Seguindo o tutorial que foi sugerido, você deve criar uma operação que não receberá parâmetros e que a saída será do tipo List<Fornecedor>. Para o exemplo vou chamar esta operação de getFornecedores. O código deverá ser parecido com este:
Seguindo o tutorial que foi sugerido, você deve criar uma operação que não receberá parâmetros e que a saída será do tipo List<Fornecedor>. Para o exemplo vou chamar esta operação de getFornecedores. O código deverá ser parecido com este:
@WebService(serviceName = "GetFornecedores") public class GetFornecedores { @WebMethod(operationName = "getFornecedores") public List<Fornecedor> getFornecedores() { List<Fornecedor> listFornecedores = new ArrayList<Fornecedor>(); listFornecedores.add(new Fornecedor(1, "Fornecedor 1", "0123456789")); listFornecedores.add(new Fornecedor(2, "Fornecedor 2", "0123456789")); listFornecedores.add(new Fornecedor(3, "Fornecedor 3", "0123456789")); return listFornecedores; } }
Após implantar e executar o projeto, o arquivo wsdl pode ser acessado através do browser, de acordo com suas configurações:
http://localhost:8080/TestWSApp/GetFornecedores?wsdl
Com o projeto rodando vamos para a segunda parte.
Criando o cliente Android
Crie um projeto no Eclipse com uma Activity principal e adicione a lib ksoap2 no Build Path. Copie a classe Fornecedor citada anteriormente e cole no pacote do projeto. Então crie uma classe chamada ConexaoWS com o seguinte código:
import org.ksoap2.SoapEnvelope; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransportSE; public class ConexaoWS { private static final String NAMESPACE = "http://testws.me.org/"; private static final String METHOD_NAME = "getFornecedores"; private static final String SOAP_ACTION = "http://testws.me.org/getFornecedores"; private static final String URL = "http://10.1.0.116:8080/TestWSApp/GetFornecedores?wsdl"; public Fornecedor[] getFornecedores() throws Exception { SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME); SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.dotNet = true; envelope.setOutputSoapObject(request); HttpTransportSE ht = new HttpTransportSE(URL); ht.call(SOAP_ACTION, envelope); SoapObject response = (SoapObject) envelope.bodyIn; Fornecedor[] fornecedores = new Fornecedor[response.getPropertyCount()]; for (int c = 0; c < fornecedores.length; c++) { SoapObject soapObject = (SoapObject) response.getProperty(c); Fornecedor f = new Fornecedor(); f.codigo = Integer.parseInt(soapObject.getProperty(0).toString()); f.cpfCnpj = soapObject.getProperty(1).toString(); f.razaoSocial = soapObject.getProperty(2).toString(); fornecedores[c] = f; } return fornecedores; } }
As principais alterações a serem feitas são nas constantes:
- NAMESPACE: Pode ser encontrado no arquivo wsdl, mas normalmente é "http://" + pacote + "/"
- METHOD_NAME: Mesmo nome dado a operação
- SOAP_ACTION: NAMESPACE + METHOD_NAME
- URL: Endereço do arquivo wsdl (nos meus testes a conexão foi recusada quando utilizei localhost ou 127.0.0.1, portanto use o IP real da sua máquina)
Com isto fica faltando o layout da aplicação e a chamada do método. Para o layout utilize a seguinte definição:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" > </ListView> </RelativeLayout>
E para a classe principal utilize o seguinte código:
public class MainActivity extends ListActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Operações de rede não podem ser realizadas na thread principal new MyAsyncTask().execute(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } private class MyAsyncTask extends AsyncTask<Void, Void, Fornecedor[]> { boolean erro = false; private final ProgressDialog dialog = new ProgressDialog( MainActivity.this); @Override protected void onProgressUpdate(Void... values) { this.dialog.setMessage("Aguarde..."); this.dialog.show(); } @Override protected Fornecedor[] doInBackground(Void... params) { Fornecedor[] retorno = null; try { ConexaoWS conexao = new ConexaoWS(); retorno = conexao.getFornecedores(); } catch (Exception e) { erro = true; e.printStackTrace(); } return retorno; } @Override protected void onPostExecute(Fornecedor[] result) { if (this.dialog.isShowing()) { this.dialog.dismiss(); } if (erro == false) { List<Fornecedor> listaFornecedores = Arrays.asList(result); ArrayAdapter<Fornecedor> adapter = new ArrayAdapter<Fornecedor>( MainActivity.this, android.R.layout.simple_list_item_1, listaFornecedores); setListAdapter(adapter); } else { Toast.makeText(MainActivity.this, "Ocorreu um erro ao acessar o Web Service.", Toast.LENGTH_LONG).show(); } } } }
Se você é leigo em programação para Android, recomendo que procure entender como funcionam as classes ListActivity e AsyncTask para melhor compreensão do exemplo. O resultado da aplicação será este: