Skip to content

8. Versão 4 – cliente/servidor em uma arquitetura de serviço web

Nesta nova versão, o aplicativo [Pam] será executado no modo cliente/servidor em uma arquitetura de serviço web. Voltemos à arquitetura do aplicativo anterior:

Acima, uma camada de comunicação [C, RMI, S] permitia uma comunicação transparente entre o cliente [ui] e a camada remota [metier]. Vamos utilizar uma arquitetura semelhante, na qual a camada de comunicação [C, RMI, S] será substituída por uma camada [C, HTTP / SOAP, S]:

O protocolo HTTP / SOAP tem a vantagem, em relação ao protocolo anterior RMI / EJB, de ser multiplataforma. Assim, o serviço web pode ser escrito em Java e implantado no servidor Glassfish, enquanto o cliente pode ser um cliente .NET ou PHP.

Vamos desenvolver essa arquitetura de acordo com três modos diferentes:

  1. o serviço web será fornecido pelo EJB [Metier]
  2. o serviço web será fornecido por um aplicativo web que utiliza o EJB e o [Metier]
  3. o serviço web será fornecido por uma aplicação web que utiliza o Spring

Um serviço web pode ser implementado de diversas maneiras em um servidor Java EE:

  • por meio de uma classe anotada com @WebService que é executada em um contêiner web
  • por meio de um EJB anotado com @WebService que é executado em um contêiner EJB

Começaremos por esta última arquitetura.

8.1. Serviço web implementado por um EJB

8.1.1. A parte do servidor

8.1.1.1. O projeto NetBeans

Vamos começar criando um novo projeto Maven, cópia do projeto EJB [mv-pam-ejb-metier-dao-jpa-eclipselink]:

  

Com a seguinte arquitetura:

a camada [metier] será o serviço web acionado pela camada [ui]. Essa classe não precisa implementar uma interface. São as anotações que transformam um POJO (Plain Ordinary Java Object) em um serviço web. A classe [Metier], que implementa a camada [metier] acima, é transformada da seguinte maneira:


package metier;

...
@WebService
@Stateless()
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class Metier implements IMetierLocal,IMetierRemote {
  
  // referências sobre as camadas [DAO]
  @EJB
  private ICotisationDaoLocal cotisationDao = null;
  @EJB
  private IEmployeDaoLocal employeDao=null;
  @EJB
  private IIndemniteDaoLocal indemniteDao=null;
  
  
  // obter a folha de pagamento
@WebMethod
  public FeuilleSalaire calculerFeuilleSalaire(String SS,
...
  }
  
  // lista de funcionários
@WebMethod
   public List<Employe> findAllEmployes() {
...
  }
// importante — sem getters e setters para os EJB
 }
  • na linha 4, a anotação @WebService transforma a classe [Metier] em um serviço web. Um serviço web expõe métodos aos seus clientes. Esses métodos devem ser anotados com o atributo @WebMethod.
  • linhas 19 e 25: os dois métodos da classe [Metier] tornam-se métodos do serviço web.
  • linha 29: é importante que os getters e setters sejam removidos; caso contrário, eles serão expostos no serviço web, o que causará erros de segurança.

A adição dessas anotações é detectada pelo NetBeans, que então altera a natureza do projeto:

Em [1], surgiu uma árvore de diretórios [Web Services] no projeto. Nela, encontram-se o serviço web Metier e seus dois métodos. A aplicação de servidor pode ser implantada em [2]. O servidor MySQL deve estar em execução e seu banco de dados [dbpam_eclipselink] deve existir e estar preenchido. Pode ser necessário, antes disso, excluir os arquivos [3] e EJB do projeto cliente/servidor EJB analisado anteriormente, para evitar conflitos de nomes. De fato, nosso novo projeto traz consigo os mesmos EJB do projeto anterior.

No [1], vemos nosso aplicativo serveur implantado no servidor Glassfish. Uma vez implantado o serviço web, ele pode ser testado:

  • no [1], no projeto atual, testamos o serviço web [Metier]
  • o serviço web está acessível por meio de diferentes URL. O URL e o [2] permitem testar o serviço web
  • em [3], um link no arquivo XML que define o serviço web. Os clientes do serviço web precisam conhecer o URL desse arquivo. É a partir dele que é gerada a camada cliente (stubs) do serviço web.
  • no [4,5], um formulário que permite testar os métodos expostos pelo serviço web. Esses métodos são apresentados com seus parâmetros, que o usuário pode definir.

Por exemplo, vamos testar o método [findAllEmployes], que não requer nenhum parâmetro:

 

Acima, testamos o método. Recebemos então a resposta abaixo (visualização parcial). Nela, encontramos os dois funcionários com suas indenizações. O leitor é convidado a testar da mesma forma o método [4], passando-lhe os três parâmetros que ele espera.

Image

8.1.2. A parte do cliente

8.1.2.1. O projeto NetBeans do cliente console

Agora criamos um projeto Java do tipo [Java Application] para a parte client do aplicativo. Não foi possível (junho de 2012) criar um projeto Maven para esse cliente. Ocorre um erro, que parece ser conhecido na internet, mas continua sem solução.

 

Após a criação do projeto, indicamos que ele será cliente do serviço web que acabamos de implantar no servidor Glassfish:

  • em [2], selecionamos o novo projeto e clicamos no botão [New File]
  • em [3], indicamos que queremos criar um cliente de serviço web
  • com [4], vamos designar o projeto NetBeans do serviço web
  • na janela [5], estão listados todos os projetos com um branch [Web Services], aqui apenas o projeto [mv-pam-ws-metier-dao-eclipselink].
  • Um projeto pode implantar vários serviços web. Em [6], selecionamos o serviço web ao qual queremos nos conectar.
  • No [7], é exibida a definição do serviço web URL. Essa definição URL é utilizada pelas ferramentas de software que geram a camada cliente que fará a interface com o serviço web.
  • A camada cliente [C] [1] que será gerada é constituída por um conjunto de classes Java que serão colocadas em um mesmo pacote. O nome deste pacote é definido como [8].
  • Assim que o assistente de criação do cliente do serviço web for concluído com o botão [Finish], a camada [C] acima é criada.

Isso se reflete em algumas alterações no projeto:

  • No [10] acima, aparece uma árvore de classes [Generated Sources] que contém as classes da camada [C], as quais permitem que o cliente [3] se comunique com o serviço web. Essa camada permite que o cliente [3] se comunique com a camada [metier] e [4] como se ela fosse local e não remota.
  • Em [11], aparece uma árvore [Web Service References] que lista os serviços web para os quais foi gerada uma camada de cliente.

Observe-se que, na camada [C] [10] gerada, encontramos classes que foram implantadas no lado do servidor: Indemnite, Cotisation, Employe, FeuilleSalaire, ElementsSalaire, Metier. Metier é o serviço web e as demais classes são necessárias para esse serviço. Podemos ter a curiosidade de consultar o código delas. Veremos que a definição das classes que, quando instanciadas, representam objetos manipulados pelo serviço, consiste na definição dos campos da classe e de seus acessadores, bem como na adição de anotações que permitem a serialização da classe no fluxo XML. A classe Metier tornou-se uma interface contendo os dois métodos que foram anotados com @WebMethod. Cada um desses métodos gera duas classes, por exemplo, [CalculerFeuilleSalaire.java] e [CalculerFeuilleSalaireResponse.java], em que uma encapsula a chamada ao método e a outra, seu resultado. Por fim, a classe MetierService é a classe que permite ao cliente obter uma referência ao serviço web de negócio remoto:

1
2
3
4
    @WebEndpoint(name = "MetierPort")
    public Metier getMetierPort() {
        return super.getPort(new QName("http://metier/", "MetierPort"), Metier.class);
}

O método getMetierPort da linha 2 permite obter uma referência ao serviço web Metier remoto.

8.1.2.2. O cliente de console do serviço web Metier

Resta-nos apenas escrever o cliente do serviço web Metier. Copiamos a classe [MainRemote] do projeto [mv-pam-client-metier-dao-jpa-eclipselink] — que era um cliente de um servidor EJB — para o novo projeto.

  • em [1], a classe do cliente do serviço web. A classe [MainRemote] apresenta erros. Para corrigi-los, começaremos removendo todas as instruções [import] existentes na classe e as regeneraremos usando a opção [Fix Imports]. De fato, algumas das classes utilizadas pela classe [MainRemote] agora fazem parte do pacote [client] gerado.
  • No [3], o trecho de código onde a camada [metier] é instanciada é o [3]. Isso é feito com o código JNDI para obter uma referência a um EJB remoto.

Fazemos a evolução do código da seguinte maneira:

  • o código JNDI é removido
  • como a classe [PamException] não existe no lado do cliente, excluímos o catch associado para manter apenas o catch na classe pai [Exception].
  • no [4], resta-nos obter uma referência ao serviço web remoto [Metier] para podermos chamar seu método [calculerFeuilleSalaire].
  • em [5], com o mouse, arrastamos (drag) o método [calculerFeuilleSalaire] do serviço web [Metier] para soltá-lo (drop) em [4]. É gerado o código [6]. Esse código genérico pode ser posteriormente adaptado pelo desenvolvedor.
  • na linha 112, vemos que [calculerFeuilleSalaire] é um método da classe [client.Metier] (linha 111). Agora que sabemos como obter a camada [metier], o código anterior pode ser reescrito da seguinte forma:
...    
// Tudo certo — já é possível solicitar a folha de pagamento
    FeuilleSalaire feuilleSalaire = null;
    Metier metier = null;
    try {
       // instanciação da camada [metier]
      metier = new MetierService().getMetierPort();
       // cálculo da folha de pagamento
      feuilleSalaire = metier.calculerFeuilleSalaire(args[0], nbHeuresTravaillées, nbJoursTravaillés);
    } catch (Throwable th) {
       // cadeia de exceções
      System.out.println("Chaîne des exceptions --------------------------------------");
      System.out.println(th.getClass().getName() + ":" + th.getMessage());
      while (th.getCause() != null) {
        th = th.getCause();
        System.out.println(th.getClass().getName() + ":" + th.getMessage());
      }
      System.exit(1);
    }
     // exibição rápida
...

A linha 7 obtém uma referência ao serviço web Metier. Feito isso, o código da classe não se altera, exceto que, na linha 10, não é a exceção do tipo [Exception] que é tratada, mas sim o tipo mais geral Throwable, a classe pai da classe Exception. Se ocorrer uma exceção, exibimos todas as causas aninhadas até a causa original.

Estamos prontos para os testes:

  • verificar se o SGBD MySQL5 foi iniciado, se a base de dados dbpam_eclipselink foi criada e inicializada
  • verificar se o serviço web está implantado no servidor Glassfish
  • compilar o cliente (Clean and Build)
  • configurar a execução do cliente
  
  • Executar o cliente

Os resultados no console são os seguintes:

...
Valeurs saisies :
N° de sécurité sociale de l'employé : 254104940426058
Nombre d'heures travaillées : 150
Nombre de jours travaillés : 20

Informations Employé : 
Nom : Jouveinal
Prénom : Marie
Adresse : 5 rue des oiseaux
...

Com a seguinte configuração:

Image

obtêm-se os seguintes resultados:

1
2
3
4
Chaîne des exceptions --------------------------------------
javax.xml.ws.soap.SOAPFaultException:L'employé de n°[xx] est introuvable
com.sun.xml.internal.ws.developer.ServerSideException:L'employé de n°[xx] est introuvable
Java Result: 1

Observe-se que, embora o serviço web [Metier] envie uma exceção do tipo [PamException], a exceção recebida pelo cliente é do tipo [SOAPFaultException]. Mesmo na cadeia de exceções, o tipo [PamException] não aparece.

8.1.3. O cliente Swing do serviço web Metier


Tarefa a ser realizada: portar o cliente Swing do projeto [mv-pam-client-ejb-metier-dao-jpa-eclipselink] para o novo projeto, de modo que ele também seja um cliente do serviço web implantado no servidor Glassfish.


8.2. Serviço web implementado por uma aplicação web

Agora, situamo-nos no contexto da seguinte arquitetura:

O serviço web é fornecido por um aplicativo web executado no contêiner web do servidor Glassfish. Esse serviço web utilizará o EJB e o [Metier], que, por sua vez, estão implantados no contêiner EJB3.

8.2.1. A parte do servidor

Criamos uma aplicação web:

  • no [1], criamos um novo projeto
  • em [2]; esse projeto é do tipo [Web Application]
  • em [3], nomeamos o projeto como [mv-pam-ws-ejb-metier-dao-eclipselink]
  • em [4], escolhemos a versão Java EE 6
  • em [6], o projeto criado

No esquema abaixo, o aplicativo web criado será executado no contêiner web. Ele utilizará o EJB [Metier], que, por sua vez, será implantado no contêiner EJB do servidor.

Para que a aplicação web criada tenha acesso às classes associadas ao EJB [Metier], adicionamos às bibliotecas da aplicação web [mv-pam-ws-ejb-metier-dao-eclipselink], a dependência do servidor EJB [mv-pam-ejb-metier-dao-eclipselink], já analisado.

  • no [1], adicionamos um projeto às dependências do projeto web,
  • em [2], seleciona-se o projeto [mv-pam-ejb-metier-dao-eclipselink],
  • em [3], o tipo da dependência é ejb,
  • em [4], o escopo da dependência é provided, ou seja, ela será fornecida pelo ambiente de execução,
  • em [5], a dependência foi adicionada.

Para criar o mesmo serviço web de antes, precisamos:

  • criar uma classe com a tag @Webservice
  • com dois métodos calculerFeuilleSalaire e findAllEmployes marcados com @WebMethod

Criamos uma classe [PamWsEjbMetier] no pacote [pam.ws]:

  

A classe [PamWsEjbMetier] é a seguinte:

package pam.ws;

import java.util.List;
import javax.ejb.EJB;
import javax.jws.WebMethod;
import javax.jws.WebService;
import jpa.Employe;
import metier.FeuilleSalaire;
import metier.IMetier;
import metier.IMetierLocal;

@WebService
public class PamWsEjbMetier implements IMetier{

  @EJB
  private IMetierLocal metier;

  @WebMethod
  public FeuilleSalaire calculerFeuilleSalaire(String SS, double nbHeuresTravaillées, int nbJoursTravaillés) {
    return metier.calculerFeuilleSalaire(SS, nbHeuresTravaillées, nbJoursTravaillés);
  }

  @WebMethod
  public List<Employe> findAllEmployes() {
    return metier.findAllEmployes();
  }

}
  • linhas 7-10: a classe importa classes dos módulos EJB e [pam-serveurws-metier-dao-jpa-eclipselink], cujo projeto Maven foi adicionado às dependências do projeto.
  • linha 12: a classe é um serviço web
  • linha 13: ela implementa a interface IMetier definida no módulo EJB
  • linhas 18-19: o método calculerFeuilleSalaire é exposto como método do serviço web
  • linhas 23-24: o método findAllEmployes é exposto como método do serviço web
  • linhas 15-16: a interface local do EJB [Metier] é inserida no campo da linha 16. Utilizamos a interface local porque a aplicação web e o módulo EJB são executados no mesmo JVM.
  • linhas 20 e 25: os métodos calculerFeuilleSalaire e findAllEmployes delegam seu processamento aos métodos de mesmo nome do EJB [Metier]. Portanto, a classe serve apenas para expor aos clientes remotos os métodos de EJB e [Metier] como métodos de um serviço web.

No NetBeans, a aplicação web é reconhecida como expondo um serviço web:

Para implantar o serviço web no servidor GlassFish, precisamos implantar:

  • o módulo web no contêiner web do servidor
  • o módulo EJB no contêiner EJB do servidor

Para isso, precisamos criar uma aplicação do tipo [Enterprise Application] que irá implantar os dois módulos ao mesmo tempo. Para tal, é necessário que os dois projetos estejam carregados no NetBeans [2].

Feito isso, criamos um novo projeto [3].

  • no [4], escolhemos um projeto do tipo [Enterprise Application].
  • em [5], nomeamos o projeto
  • em [6], configuramos o projeto. A versão do Java EE será Java EE 6. Um projeto empresarial pode ser criado com dois módulos: um módulo EJB e um módulo Web. Aqui, o projeto corporativo irá encapsular o módulo Web e o módulo EJB já criados e carregados no NetBeans. Portanto, não solicitamos a criação de novos módulos.
  • No [7], o projeto empresarial [mv-pam-webapp-ear] assim criado. Outro projeto Maven foi criado ao mesmo tempo: [mv-pam-webapp]. Não vamos nos preocupar com ele.
  • No [8], adicionamos dependências ao projeto corporativo
  • no [9], adicionamos o projeto web do tipo WAR,
  • no [10], adicionamos o projeto EJB do tipo EJB,
  • em [11], o projeto corporativo com suas duas dependências.

Compilamos o projeto corporativo com um “Clean and Build”. Estamos quase prontos para implantá-lo no servidor GlassFish. Antes disso, pode ser necessário descarregar as aplicações já carregadas no servidor para evitar possíveis conflitos de nomes entre EJB e [11]:

O servidor MySQL deve estar em execução e o banco de dados [dbpam_eclipselink] disponível e preenchido. Feito isso, a aplicação corporativa [12] pode ser implantada. No [13], é possível verificar que ela foi efetivamente implantada no servidor Glassfish.

Podemos testar o serviço web que acaba de ser implantado:

  • em [1], solicitamos o teste do serviço web [PamWsEjbMetier]
  • em [2], a página de teste. Deixamos a cargo do leitor a realização dos testes.

8.2.2. A parte do cliente


Tarefa a ser realizada: seguindo a abordagem descrita no parágrafo 8.1.2.1, construir um cliente de console para o serviço web anterior.


8.3. Serviço web implementado com Spring e Tomcat

Passamos agora a considerar a seguinte arquitetura:

O serviço web é fornecido por uma aplicação web executada no contêiner web do servidor Tomcat. A arquitetura da aplicação será a seguinte:

Vamos nos basear no projeto [mv-pam-spring-hibernate] desenvolvido no parágrafo 5.11:

  

8.3.1. A parte do servidor

Criamos um aplicativo Maven do tipo web chamado [mv-pam-ws-spring-tomcat] [1]:

Modificamos o arquivo [pom.xml] para incluir as seguintes dependências [2]:


  <dependencies>
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>mv-pam-spring-hibernate</artifactId>
      <version>${project.version}</version>
    </dependency>
    <!-- Dependências do Apache CXF -->
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxws</artifactId>
      <version>2.2.12</version>
    </dependency>
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-transports-http</artifactId>
      <version>2.2.12</version>
    </dependency>
</dependencies>
  • linhas 3-7: a dependência do projeto [spring-pam-jpa-hibernate],
  • linhas 8-17: as dependências do framework Apache CXF e [http://cxf.apache.org/]. Esse framework facilita a criação de serviços web.

Este arquivo [pom.xml] traz várias dependências [2].

Voltemos à arquitetura do aplicativo:

As chamadas ao serviço web que vamos construir são gerenciadas por um servlet do framework CXF. Isso se traduz no arquivo [WEB-INF / web.xml] da seguinte maneira:


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <display-name>mv-pam-ws-spring-tomcat</display-name>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
<!--  Configuração do CXF -->
  <servlet>
    <servlet-name>CXFServlet</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>CXFServlet</servlet-name>
    <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>
  <session-config>
    <session-timeout>
      30
    </session-timeout>
  </session-config>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  • O framework CXF depende do Spring. Linhas 4-6: é declarado um listener. A classe correspondente será carregada junto com a aplicação web. Ela utilizará o arquivo de configuração do Spring [WEB-INF / applicationContext.xml]:
  • linhas 8-12: o servlet CXF, que irá gerenciar as chamadas ao serviço web que iremos criar,
  • linhas 13-16: as chamadas URL processadas pelo servlet CXF serão do tipo /ws/*. As demais não serão processadas pelo CXF.

Para definir o serviço web, definimos uma interface e sua implementação:

A interface [IWsMetier] será a seguinte:


package pam.ws;

import javax.jws.WebService;
import metier.IMetier;

@WebService
public interface IWsMetier extends IMetier{
  
}
  • linha 7: a interface [IWsMetier] deriva da interface [IMetier] da camada [métier] do projeto [mv-pam-spring-hibernate],
  • linha 6: a interface [IWsMetier] é a de um serviço web.

A classe de implementação dessa interface é a seguinte:


package pam.ws;

import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebService;
import jpa.Employe;
import metier.FeuilleSalaire;
import metier.IMetier;

@WebService
public class PamWsMetier implements IWsMetier {

  // camada de negócios
  private IMetier metier;
  
  // Construtor
  public PamWsMetier(){
    
  }
  
  @WebMethod
  public FeuilleSalaire calculerFeuilleSalaire(String SS, double nbHeuresTravaillees, int nbJoursTravailles) {
    return metier.calculerFeuilleSalaire(SS, nbHeuresTravaillees, nbJoursTravailles);
  }

  @WebMethod
  public List<Employe> findAllEmployes() {
    return metier.findAllEmployes();
  }
  
  // getters e setters

  public void setMetier(IMetier metier) {
    this.metier = metier;
  }
  
}
  • linha 11: a classe [PamWsMetier] implementa a interface definida anteriormente,
  • linha 10: define a classe como um serviço web,
  • linha 14: a camada [métier] será injetada pelo Spring,
  • linhas 21 e 26: a anotação @WebMethod transforma um método em um método exposto pelo serviço web,
  • linhas 23 e 28: os métodos são implementados por meio da camada [métier].

Resta-nos definir o conteúdo do arquivo de configuração do Spring [applicationContext.xml]:

Seu conteúdo é o seguinte:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-2.0.xsd 
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
       http://cxf.apache.org/jaxws
       http://cxf.apache.org/schemas/jaxws.xsd">
  
  <!-- Apache CXF -->
  <import resource="classpath:META-INF/cxf/cxf.xml" />
  <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
  <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />  

  <!-- camadas inferiores -->
  <import resource="classpath:spring-config-metier-dao.xml" />  
  
  <!-- serviço web -->
  <bean id="wsMetier" class="pam.ws.PamWsMetier">
    <property name="metier" ref="metier"/>
  </bean>
  <jaxws:endpoint id="wsmetier"
                  implementor="#wsMetier"
                  address="/metier">
  </jaxws:endpoint>  

</beans>
  • linhas 13-15: importam-se arquivos de configuração do Apache CXF. Estes são buscados no Classpath do projeto (atributo classpath:),
  • linhas 4, 9, 10: são declarados namespaces específicos do Apache CXF,
  • linha 18: importa-se o arquivo de configuração do Spring do projeto [mv-pam-spring-hibernate],
  • linhas 21-23: definem o bean do serviço web com sua dependência da camada [métier] (linha 22),
  • linhas 24-27: definem o próprio serviço web,
    • linha 25: o bean Spring que implementa o serviço web é aquele definido na linha 21;
    • linha 26: define o URL no qual o serviço web estará disponível, neste caso /metier. Combinada com o formato que as URL processadas pelo Apache CXF devem ter (consulte o arquivo web.xml), essa URL passa a ser /ws/metier.

Nosso projeto está pronto para ser executado. Nós o executamos (Run) e acessamos o URL [http://localhost:8080/mv-pam-ws-spring-tomcat/ws] em um navegador:

Image

A página lista todos os serviços web implantados. Aqui, há apenas um. Seguimos o link WSDL:

O texto exibido [1] corresponde a um arquivo XML que define as funcionalidades do serviço web, como chamá-lo e quais respostas ele envia. Observe que o URL e o [2] estão contidos neste arquivo WSDL. Todos os clientes do serviço web precisam conhecê-lo.

8.3.2. A parte do cliente


Tarefa a ser realizada: seguindo a abordagem descrita no parágrafo 8.1.2.1, criar um cliente de console para o serviço web anterior.


Observação: para indicar o URL do arquivo WSDL do serviço web, proceda da seguinte forma:

Colocaremos em [3] o URL anotado anteriormente em [2].