RESTful Web Services - Guia rápido
O que é arquitetura REST?
REST significa Transferência de Estado Representacional. REST é uma arquitetura baseada em padrões da web e usa protocolo HTTP. Ele gira em torno de recursos em que cada componente é um recurso e um recurso é acessado por uma interface comum usando métodos padrão HTTP. O REST foi introduzido pela primeira vez por Roy Fielding em 2000.
Na arquitetura REST, um servidor REST simplesmente fornece acesso aos recursos e o cliente REST acessa e modifica os recursos. Aqui, cada recurso é identificado por URIs / IDs globais. REST usa várias representações para representar um recurso como texto, JSON, XML. JSON é o mais popular.
Métodos HTTP
Os quatro métodos HTTP a seguir são comumente usados na arquitetura baseada em REST.
GET - Fornece acesso somente leitura a um recurso.
POST - Usado para criar um novo recurso.
DELETE - Usado para remover um recurso.
PUT - Usado para atualizar um recurso existente ou criar um novo recurso.
Introdução aos serviços da web RESTFul
Um serviço da web é uma coleção de protocolos e padrões abertos usados para trocar dados entre aplicativos ou sistemas. Os aplicativos de software escritos em várias linguagens de programação e em execução em várias plataformas podem usar serviços da web para trocar dados em redes de computadores como a Internet de maneira semelhante à comunicação entre processos em um único computador. Essa interoperabilidade (por exemplo, entre aplicativos Java e Python ou Windows e Linux) se deve ao uso de padrões abertos.
Os serviços da Web baseados na arquitetura REST são conhecidos como serviços da Web RESTful. Esses serviços da web usam métodos HTTP para implementar o conceito de arquitetura REST. Um serviço da web RESTful geralmente define um URI, Uniform Resource Identifier um serviço, fornece representação de recursos como JSON e um conjunto de métodos HTTP.
Criação de serviço da Web RESTFul
Nos próximos capítulos, criaremos um serviço da web, digamos, gerenciamento de usuários com as seguintes funcionalidades -
Sr. Não. | URI | Método HTTP | POST body | Resultado |
---|---|---|---|---|
1 | / UserService / users | PEGUE | vazio | Mostra a lista de todos os usuários. |
2 | / UserService / addUser | POSTAR | String JSON | Adicione detalhes do novo usuário. |
3 | / UserService / getUser /: id | PEGUE | vazio | Mostra os detalhes de um usuário. |
Este tutorial irá guiá-lo sobre como preparar um ambiente de desenvolvimento para começar seu trabalho com Jersey Frameworkpara criar serviços da Web RESTful. Implementos de estrutura de JerseyJAX-RS 2.0API, que é uma especificação padrão para criar serviços da Web RESTful. Este tutorial também lhe ensinará como configurarJDK, Tomcat e Eclipse em sua máquina antes de configurar o Jersey Framework.
Configure o Java Development Kit (JDK)
Você pode baixar a versão mais recente do SDK no site Java da Oracle - Java SE Downloads . Você encontrará as instruções para instalar o JDK nos arquivos baixados. Siga as instruções fornecidas para instalar e configurar a configuração. Finalmente defina oPATH e JAVA_HOME variáveis de ambiente para se referir ao diretório que contém Java e Javac, normalmente java_install_dir / bin e java_install_dir respectivamente.
Se você estiver executando o Windows e instalou o JDK em C: \ jdk1.7.0_75, deverá inserir a seguinte linha em seu arquivo C: \ autoexec.bat.
set PATH = C:\jdk1.7.0_75\bin;%PATH%
set JAVA_HOME = C:\jdk1.7.0_75
Como alternativa, no Windows NT / 2000 / XP, você também pode clicar com o botão direito do mouse em Meu Computador → selecionar Propriedades → Avançado → Variáveis de Ambiente. Em seguida, você atualizaria o valor de PATH e pressionaria o botão OK.
No Unix (Solaris, Linux, etc.), se o SDK estiver instalado em /usr/local/jdk1.7.0_75 e você usar o C Shell, você deve colocar o seguinte em seu arquivo .cshrc.
setenv PATH /usr/local/jdk1.7.0_75/bin:$PATH
setenv JAVA_HOME /usr/local/jdk1.7.0_75
Alternativamente, se você usar um Ambiente de Desenvolvimento Integrado (IDE) como Borland JBuilder, Eclipse, IntelliJ IDEA ou Sun ONE Studio, compile e execute um programa simples para confirmar que o IDE sabe onde você instalou o Java, caso contrário, faça a configuração adequada conforme o documento fornecido do IDE.
Configurar IDE Eclipse
Todos os exemplos neste tutorial foram escritos usando o IDE Eclipse. Portanto, sugiro que você tenha a versão mais recente do Eclipse instalada em sua máquina.
Para instalar o Eclipse IDE, baixe os binários mais recentes do Eclipse em https://www.eclipse.org/downloads/. Depois de fazer o download da instalação, descompacte a distribuição binária em um local conveniente. Por exemplo, em C: \ eclipse no windows, ou / usr / local / eclipse no Linux / Unix e finalmente defina a variável PATH apropriadamente.
O Eclipse pode ser iniciado executando os seguintes comandos em uma máquina Windows ou você pode simplesmente clicar duas vezes em eclipse.exe.
%C:\eclipse\eclipse.exe
O Eclipse pode ser iniciado executando os seguintes comandos na máquina Unix (Solaris, Linux, etc.) -
$/usr/local/eclipse/eclipse
Após uma inicialização bem-sucedida, se tudo estiver bem, sua tela deverá exibir o seguinte resultado -
Configurar bibliotecas do Jersey Framework
Agora, se tudo estiver bem, você pode prosseguir com a configuração da estrutura Jersey. A seguir estão algumas etapas simples para baixar e instalar a estrutura em sua máquina.
Escolha se deseja instalar o Jersey no Windows ou Unix e prossiga para a próxima etapa para baixar o arquivo .zip para Windows e, em seguida, o arquivo .tz para Unix.
Baixe a versão mais recente dos binários do framework Jersey a partir do seguinte link - https://jersey.java.net/download.html.
No momento em que escrevi este tutorial, eu baixei jaxrs-ri-2.17.zip na minha máquina Windows e quando você descompacta o arquivo baixado, ele mostra a estrutura de diretórios dentro de E: \ jaxrs-ri-2.17 \ jaxrs-ri como mostrado na imagem a seguir.
Você encontrará todas as bibliotecas de Jersey nos diretórios C:\jaxrs-ri-2.17\jaxrs-ri\lib e dependências em C:\jaxrs-ri-2.17\jaxrs-ri\ext. Certifique-se de definir sua variável CLASSPATH neste diretório corretamente, caso contrário, você terá problemas ao executar seu aplicativo. Se você estiver usando o Eclipse, não é necessário definir o CLASSPATH porque todas as configurações serão feitas por meio do Eclipse.
Configurar Apache Tomcat
Você pode baixar a última versão do Tomcat em https://tomcat.apache.org/. Depois de baixar a instalação, descompacte a distribuição binária em um local conveniente. Por exemplo, em C: \ apache-tomcat-7.0.59 no Windows ou /usr/local/apache-tomcat-7.0.59 no Linux / Unix e defina a variável de ambiente CATALINA_HOME apontando para os locais de instalação.
O Tomcat pode ser iniciado executando os seguintes comandos em uma máquina Windows, ou você pode simplesmente clicar duas vezes em startup.bat.
%CATALINA_HOME%\bin\startup.bat
ou
C:\apache-tomcat-7.0.59\bin\startup.bat
O Tomcat pode ser iniciado executando os seguintes comandos em uma máquina Unix (Solaris, Linux, etc.) -
$CATALINA_HOME/bin/startup.sh
ou
/usr/local/apache-tomcat-7.0.59/bin/startup.sh
Após uma inicialização bem-sucedida, os aplicativos da web padrão incluídos no Tomcat estarão disponíveis visitando http://localhost:8080/. Se tudo estiver bem, ele deve exibir o seguinte resultado -
Mais informações sobre como configurar e executar o Tomcat podem ser encontradas na documentação incluída nesta página. Essas informações também podem ser encontradas no site do Tomcat -https://tomcat.apache.org.
O Tomcat pode ser interrompido executando os seguintes comandos em uma máquina Windows -
%CATALINA_HOME%\bin\shutdown
ou
C:\apache-tomcat-7.0.59\bin\shutdown
O Tomcat pode ser interrompido executando os seguintes comandos na máquina Unix (Solaris, Linux, etc.) -
$CATALINA_HOME/bin/shutdown.sh
ou
/usr/local/apache-tomcat-7.0.59/bin/shutdown.sh
Depois de concluir esta última etapa, você está pronto para prosseguir para seu primeiro exemplo de Jersey, que verá no próximo capítulo.
Vamos começar a escrever os serviços da web RESTful reais com o Jersey Framework. Antes de começar a escrever seu primeiro exemplo usando o Jersey Framework, você deve certificar-se de que configurou seu ambiente Jersey corretamente, conforme explicado no capítulo RESTful Web Services - Configuração do ambiente . Aqui, também estou assumindo que você tem algum conhecimento prático do Eclipse IDE.
Portanto, vamos continuar a escrever um aplicativo Jersey simples que exporá um método de serviço da web para exibir a lista de usuários.
Criando um Projeto Java
A primeira etapa é criar um Projeto da Web Dinâmico usando Eclipse IDE. Siga a opçãoFile → New → Project e finalmente selecione o Dynamic Web Projectassistente da lista de assistentes. Agora nomeie seu projeto comoUserManagement usando a janela do assistente, conforme mostrado na imagem a seguir -
Assim que seu projeto for criado com sucesso, você terá o seguinte conteúdo em seu Project Explorer -
Adicionando as Bibliotecas Necessárias
Como uma segunda etapa, vamos adicionar Jersey Framework e suas dependências (bibliotecas) em nosso projeto. Copie todos os jars dos seguintes diretórios da pasta zip de download do jersey no diretório WEB-INF / lib do projeto.
- \jaxrs-ri-2.17\jaxrs-ri\api
- \jaxrs-ri-2.17\jaxrs-ri\ext
- \jaxrs-ri-2.17\jaxrs-ri\lib
Agora, clique com o botão direito no nome do seu projeto UserManagement e depois siga a opção disponível no menu de contexto - Build Path → Configure Build Path para exibir a janela Java Build Path.
Agora usa Add JARs botão disponível em Libraries para adicionar os JARs presentes no diretório WEBINF / lib.
Criando os arquivos de origem
Agora vamos criar os arquivos de origem reais sob o UserManagementprojeto. Primeiro, precisamos criar um pacote chamadocom.tutorialspoint. Para fazer isso, clique com o botão direito em src na seção Package Explorer e siga a opção -New → Package.
Em seguida, vamos criar UserService.java, User.java,UserDao.java arquivos no pacote com.tutorialspoint.
User.java
package com.tutorialspoint;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private String profession;
public User(){}
public User(int id, String name, String profession){
this.id = id;
this.name = name;
this.profession = profession;
}
public int getId() {
return id;
}
@XmlElement
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
@XmlElement
public void setName(String name) {
this.name = name;
}
public String getProfession() {
return profession;
}
@XmlElement
public void setProfession(String profession) {
this.profession = profession;
}
}
UserDao.java
package com.tutorialspoint;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
public class UserDao {
public List<User> getAllUsers(){
List<User> userList = null;
try {
File file = new File("Users.dat");
if (!file.exists()) {
User user = new User(1, "Mahesh", "Teacher");
userList = new ArrayList<User>();
userList.add(user);
saveUserList(userList);
}
else{
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
userList = (List<User>) ois.readObject();
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return userList;
}
private void saveUserList(List<User> userList){
try {
File file = new File("Users.dat");
FileOutputStream fos;
fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(userList);
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
UserService.java
package com.tutorialspoint;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/UserService")
public class UserService {
UserDao userDao = new UserDao();
@GET
@Path("/users")
@Produces(MediaType.APPLICATION_XML)
public List<User> getUsers(){
return userDao.getAllUsers();
}
}
Existem dois pontos importantes a serem observados sobre o programa principal,
UserService.java
A primeira etapa é especificar um caminho para o serviço da web usando a anotação @Path para o UserService.
A segunda etapa é especificar um caminho para o método de serviço da web específico usando a anotação @Path para o método de UserService.
Criação do arquivo de configuração Web.xml
Você precisa criar um arquivo de configuração xml da Web que é um arquivo XML e é usado para especificar o servlet da estrutura Jersey para nosso aplicativo.
web.xml
<?xml version = "1.0" encoding = "UTF-8"?>
<web-app xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id = "WebApp_ID" version = "3.0">
<display-name>User Management</display-name>
<servlet>
<servlet-name>Jersey RESTful Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.tutorialspoint</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Jersey RESTful Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
Implementando o Programa
Quando terminar de criar os arquivos de origem e de configuração da web, você estará pronto para esta etapa que consiste em compilar e executar seu programa. Para fazer isso, usando o Eclipse, exporte seu aplicativo como um arquivo war e implante o mesmo no tomcat.
Para criar um arquivo WAR usando eclipse, siga a opção File → export → Web → War Filee, por fim, selecione o gerenciamento do usuário do projeto e a pasta de destino. Para implantar um arquivo war no Tomcat, coloque o UserManagement.war noTomcat Installation Directory → webapps directory e inicie o Tomcat.
Executando o Programa
Estamos usando Postman , uma extensão do Chrome, para testar nossos serviços da web.
Faça uma solicitação ao UserManagement para obter a lista de todos os usuários. Coloque http: // localhost: 8080 / UserManagement / rest / UserService / users no POSTMAN com solicitação GET e veja o seguinte resultado.
Parabéns, você criou seu primeiro aplicativo RESTful com sucesso.
O que é um recurso?
A arquitetura REST trata cada conteúdo como um recurso. Esses recursos podem ser arquivos de texto, páginas html, imagens, vídeos ou dados dinâmicos de negócios. O REST Server simplesmente fornece acesso aos recursos e o cliente REST acessa e modifica os recursos. Aqui, cada recurso é identificado por URIs / IDs globais. REST usa várias representações para representar um recurso onde Texto, JSON, XML. As representações de recursos mais populares são XML e JSON.
Representação de Recursos
Um recurso em REST é um Objeto semelhante em Programação Orientada a Objetos ou é como uma Entidade em um Banco de Dados. Uma vez identificado um recurso, então sua representação deve ser decidida utilizando um formato padrão para que o servidor possa enviar o recurso no formato acima mencionado e o cliente possa entender o mesmo formato.
Por exemplo, no capítulo RESTful Web Services - Primeiro aplicativo , um usuário é um recurso representado usando o seguinte formato XML -
<user>
<id>1</id>
<name>Mahesh</name>
<profession>Teacher</profession>
</user>
O mesmo recurso pode ser representado no formato JSON da seguinte forma -
{
"id":1,
"name":"Mahesh",
"profession":"Teacher"
}
Boa Representação de Recursos
O REST não impõe nenhuma restrição ao formato de uma representação de recurso. Um cliente pode solicitar representação JSON, enquanto outro cliente pode solicitar representação XML do mesmo recurso para o servidor e assim por diante. É responsabilidade do servidor REST passar ao cliente o recurso no formato que o cliente entende.
A seguir estão alguns pontos importantes a serem considerados ao projetar um formato de representação de um recurso em RESTful Web Services.
Understandability - Tanto o servidor quanto o cliente devem ser capazes de entender e utilizar o formato de representação do recurso.
Completeness- O formato deve ser capaz de representar um recurso completamente. Por exemplo, um recurso pode conter outro recurso. O formato deve ser capaz de representar estruturas de recursos simples e complexas.
Linkablity - Um recurso pode ter uma ligação a outro recurso, um formato deve ser capaz de lidar com tais situações.
No entanto, no momento, a maioria dos serviços da web está representando recursos usando o formato XML ou JSON. Existem muitas bibliotecas e ferramentas disponíveis para entender, analisar e modificar dados XML e JSON.
Os RESTful Web Services usam protocolos HTTP como meio de comunicação entre o cliente e o servidor. Um cliente envia uma mensagem na forma de uma solicitação HTTP e o servidor responde na forma de uma resposta HTTP. Esta técnica é denominada Messaging. Essas mensagens contêm dados e metadados da mensagem, ou seja, informações sobre a própria mensagem. Vamos dar uma olhada nas mensagens de solicitação HTTP e resposta HTTP para HTTP 1.1.
Pedido HTTP
Uma solicitação HTTP tem cinco partes principais -
Verb - indica os métodos HTTP como GET, POST, DELETE, PUT, etc.
URI - Uniform Resource Identifier (URI) para identificar o recurso no servidor.
HTTP Version- indica a versão HTTP. Por exemplo, HTTP v1.1.
Request Header- Contém metadados para a mensagem de solicitação HTTP como pares chave-valor. Por exemplo, tipo de cliente (ou navegador), formato suportado pelo cliente, formato do corpo da mensagem, configurações de cache, etc.
Request Body - Conteúdo da mensagem ou representação de recursos.
Resposta HTTP
Uma resposta HTTP tem quatro partes principais -
Status/Response Code- indica o status do servidor para o recurso solicitado. Por exemplo, 404 significa recurso não encontrado e 200 significa que a resposta está ok.
HTTP Version- indica a versão HTTP. Por exemplo, HTTP v1.1.
Response Header- Contém metadados para a mensagem de resposta HTTP como pares chave-valor. Por exemplo, comprimento do conteúdo, tipo de conteúdo, data de resposta, tipo de servidor, etc.
Response Body - Conteúdo da mensagem de resposta ou representação de recursos.
Exemplo
Conforme explicado no capítulo RESTful Web Services - Primeiro aplicativo , vamos colocar http: // localhost: 8080 / UserManagement / rest / UserService / users no POSTMAN com uma solicitação GET. Se você clicar no botão Visualizar, próximo ao botão enviar do Postman, e clicar no botão Enviar, poderá ver o seguinte resultado.
Aqui você pode ver que o navegador enviou uma solicitação GET e recebeu um corpo de resposta como XML.
O endereçamento refere-se à localização de um recurso ou vários recursos no servidor. É análogo localizar o endereço postal de uma pessoa.
Cada recurso na arquitetura REST é identificado por seu URI (Uniform Resource Identifier). Um URI tem o seguinte formato -
<protocol>://<service-name>/<ResourceType>/<ResourceID>
O objetivo de um URI é localizar um ou mais recursos no servidor que hospeda o serviço da web. Outro atributo importante de uma solicitação é VERB que identifica a operação a ser executada no recurso. Por exemplo, no capítulo RESTful Web Services - Primeiro aplicativo , o URI éhttp://localhost:8080/UserManagement/rest/UserService/users e o VERBO é GET.
Construindo um URI padrão
A seguir estão os pontos importantes a serem considerados ao projetar um URI -
Use Plural Noun- Use o substantivo plural para definir recursos. Por exemplo, usamos usuários para identificar usuários como um recurso.
Avoid using spaces- Use sublinhado (_) ou hífen (-) ao usar um nome de recurso longo. Por exemplo, use authorized_users em vez de% 20users autorizados.
Use lowercase letters - Embora o URI não faça distinção entre maiúsculas e minúsculas, é uma boa prática manter o url apenas em letras minúsculas.
Maintain Backward Compatibility- Como o Web Service é um serviço público, um URI, uma vez tornado público, deve estar sempre disponível. Caso o URI seja atualizado, redirecione o URI mais antigo para um novo URI usando o código de status HTTP, 300.
Use HTTP Verb- Sempre use HTTP Verb como GET, PUT e DELETE para fazer as operações no recurso. Não é bom usar o nome de operações no URI.
Exemplo
A seguir está um exemplo de um URI ruim para buscar um usuário.
http://localhost:8080/UserManagement/rest/UserService/getUser/1
A seguir está um exemplo de um bom URI para buscar um usuário.
http://localhost:8080/UserManagement/rest/UserService/users/1
Como discutimos nos capítulos anteriores, o serviço da Web RESTful usa muitos verbos HTTP para determinar a operação a ser realizada no (s) recurso (s) especificado (s). A tabela a seguir apresenta os exemplos dos verbos HTTP mais comumente usados.
Sr. Não. | Método HTTP, URI e operação |
---|---|
1 | GET http: // localhost: 8080 / UserManagement / rest / UserService / users Obtém a lista de usuários. (Somente leitura) |
2 |
GET http: // localhost: 8080 / UserManagement / rest / UserService / users / 1 Obtém o usuário de Id 1 (Somente leitura) |
3 |
PUT http: // localhost: 8080 / UserManagement / rest / UserService / users / 2 Insere usuário com Id 2 (Idempotente) |
4 |
POST http: // localhost: 8080 / UserManagement / rest / UserService / users / 2 Atualiza o usuário com Id 2 (N / D) |
5 |
DELETE http: // localhost: 8080 / UserManagement / rest / UserService / users / 1 Exclui o usuário com ID 1 (Idempotente) |
6 |
OPTIONS http: // localhost: 8080 / UserManagement / rest / UserService / users Lista as operações com suporte em um serviço da web. (Somente leitura) |
7 |
HEAD http: // localhost: 8080 / UserManagement / rest / UserService / users Retorna apenas o cabeçalho HTTP, sem corpo. (Somente leitura) |
Os seguintes pontos devem ser considerados.
As operações GET são somente leitura e são seguras.
As operações PUT e DELETE são idempotentes, o que significa que seu resultado sempre será o mesmo, não importa quantas vezes essas operações sejam chamadas.
As operações PUT e POST são quase iguais, com a diferença apenas no resultado em que a operação PUT é idempotente e a operação POST pode causar um resultado diferente.
Exemplo
Vamos atualizar um exemplo criado no capítulo RESTful Web Services - Primeiro aplicativo para criar um serviço da Web que pode executar operações CRUD (Criar, Ler, Atualizar, Excluir). Para simplificar, usamos um arquivo de E / S para substituir as operações do banco de dados.
Deixe-nos atualizar o User.java, UserDao.java e UserService.java arquivos no pacote com.tutorialspoint.
User.java
package com.tutorialspoint;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private String profession;
public User(){}
public User(int id, String name, String profession){
this.id = id;
this.name = name;
this.profession = profession;
}
public int getId() {
return id;
}
@XmlElement
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
@XmlElement
public void setName(String name) {
this.name = name;
}
public String getProfession() {
return profession;
}
@XmlElement
public void setProfession(String profession) {
this.profession = profession;
}
@Override
public boolean equals(Object object){
if(object == null){
return false;
}else if(!(object instanceof User)){
return false;
}else {
User user = (User)object;
if(id == user.getId()
&& name.equals(user.getName())
&& profession.equals(user.getProfession())){
return true;
}
}
return false;
}
}
UserDao.java
package com.tutorialspoint;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
public class UserDao {
public List<User> getAllUsers(){
List<User> userList = null;
try {
File file = new File("Users.dat");
if (!file.exists()) {
User user = new User(1, "Mahesh", "Teacher");
userList = new ArrayList<User>();
userList.add(user);
saveUserList(userList);
}
else{
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
userList = (List<User>) ois.readObject();
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return userList;
}
public User getUser(int id){
List<User> users = getAllUsers();
for(User user: users){
if(user.getId() == id){
return user;
}
}
return null;
}
public int addUser(User pUser){
List<User> userList = getAllUsers();
boolean userExists = false;
for(User user: userList){
if(user.getId() == pUser.getId()){
userExists = true;
break;
}
}
if(!userExists){
userList.add(pUser);
saveUserList(userList);
return 1;
}
return 0;
}
public int updateUser(User pUser){
List<User> userList = getAllUsers();
for(User user: userList){
if(user.getId() == pUser.getId()){
int index = userList.indexOf(user);
userList.set(index, pUser);
saveUserList(userList);
return 1;
}
}
return 0;
}
public int deleteUser(int id){
List<User> userList = getAllUsers();
for(User user: userList){
if(user.getId() == id){
int index = userList.indexOf(user);
userList.remove(index);
saveUserList(userList);
return 1;
}
}
return 0;
}
private void saveUserList(List<User> userList){
try {
File file = new File("Users.dat");
FileOutputStream fos;
fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(userList);
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
UserService.java
package com.tutorialspoint;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
@Path("/UserService")
public class UserService {
UserDao userDao = new UserDao();
private static final String SUCCESS_RESULT = "<result>success</result>";
private static final String FAILURE_RESULT = "<result>failure</result>";
@GET
@Path("/users")
@Produces(MediaType.APPLICATION_XML)
public List<User> getUsers(){
return userDao.getAllUsers();
}
@GET
@Path("/users/{userid}")
@Produces(MediaType.APPLICATION_XML)
public User getUser(@PathParam("userid") int userid){
return userDao.getUser(userid);
}
@PUT
@Path("/users")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String createUser(@FormParam("id") int id,
@FormParam("name") String name,
@FormParam("profession") String profession,
@Context HttpServletResponse servletResponse) throws IOException{
User user = new User(id, name, profession);
int result = userDao.addUser(user);
if(result == 1){
return SUCCESS_RESULT;
}
return FAILURE_RESULT;
}
@POST
@Path("/users")
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String updateUser(@FormParam("id") int id,
@FormParam("name") String name,
@FormParam("profession") String profession,
@Context HttpServletResponse servletResponse) throws IOException{
User user = new User(id, name, profession);
int result = userDao.updateUser(user);
if(result == 1){
return SUCCESS_RESULT;
}
return FAILURE_RESULT;
}
@DELETE
@Path("/users/{userid}")
@Produces(MediaType.APPLICATION_XML)
public String deleteUser(@PathParam("userid") int userid){
int result = userDao.deleteUser(userid);
if(result == 1){
return SUCCESS_RESULT;
}
return FAILURE_RESULT;
}
@OPTIONS
@Path("/users")
@Produces(MediaType.APPLICATION_XML)
public String getSupportedOperations(){
return "<operations>GET, PUT, POST, DELETE</operations>";
}
}
Agora usando o Eclipse, exporte seu aplicativo como um WAR Filee implantar o mesmo no Tomcat. Para criar um arquivo WAR usando eclipse, siga este caminho -File → export → Web → War Filee, finalmente, selecione o projeto UserManagement e a pasta de destino. Para implementar um arquivo WAR no Tomcat, coloque o UserManagement.war noTomcat Installation Directory → webapps diretório e o Tomcat inicial.
Testando o serviço da Web
Jersey fornece APIs para criar um cliente de serviço da web para testar serviços da web. Nós criamos uma amostra de classe de testeWebServiceTester.java sob o pacote com.tutorialspoint no mesmo projeto.
WebServiceTester.java
package com.tutorialspoint;
import java.util.List;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
public class WebServiceTester {
private Client client;
private String REST_SERVICE_URL = "
http://localhost:8080/UserManagement/rest/UserService/users";
private static final String SUCCESS_RESULT = "<result>success</result>";
private static final String PASS = "pass";
private static final String FAIL = "fail";
private void init(){
this.client = ClientBuilder.newClient();
}
public static void main(String[] args){
WebServiceTester tester = new WebServiceTester();
//initialize the tester
tester.init();
//test get all users Web Service Method
tester.testGetAllUsers();
//test get user Web Service Method
tester.testGetUser();
//test update user Web Service Method
tester.testUpdateUser();
//test add user Web Service Method
tester.testAddUser();
//test delete user Web Service Method
tester.testDeleteUser();
}
//Test: Get list of all users
//Test: Check if list is not empty
private void testGetAllUsers(){
GenericType<List<User>> list = new GenericType<List<User>>() {};
List<User> users = client
.target(REST_SERVICE_URL)
.request(MediaType.APPLICATION_XML)
.get(list);
String result = PASS;
if(users.isEmpty()){
result = FAIL;
}
System.out.println("Test case name: testGetAllUsers, Result: " + result );
}
//Test: Get User of id 1
//Test: Check if user is same as sample user
private void testGetUser(){
User sampleUser = new User();
sampleUser.setId(1);
User user = client
.target(REST_SERVICE_URL)
.path("/{userid}")
.resolveTemplate("userid", 1)
.request(MediaType.APPLICATION_XML)
.get(User.class);
String result = FAIL;
if(sampleUser != null && sampleUser.getId() == user.getId()){
result = PASS;
}
System.out.println("Test case name: testGetUser, Result: " + result );
}
//Test: Update User of id 1
//Test: Check if result is success XML.
private void testUpdateUser(){
Form form = new Form();
form.param("id", "1");
form.param("name", "suresh");
form.param("profession", "clerk");
String callResult = client
.target(REST_SERVICE_URL)
.request(MediaType.APPLICATION_XML)
.post(Entity.entity(form,
MediaType.APPLICATION_FORM_URLENCODED_TYPE),
String.class);
String result = PASS;
if(!SUCCESS_RESULT.equals(callResult)){
result = FAIL;
}
System.out.println("Test case name: testUpdateUser, Result: " + result);
}
//Test: Add User of id 2
//Test: Check if result is success XML.
private void testAddUser(){
Form form = new Form();
form.param("id", "2");
form.param("name", "naresh");
form.param("profession", "clerk");
String callResult = client
.target(REST_SERVICE_URL)
.request(MediaType.APPLICATION_XML)
.put(Entity.entity(form,
MediaType.APPLICATION_FORM_URLENCODED_TYPE),
String.class);
String result = PASS;
if(!SUCCESS_RESULT.equals(callResult)){
result = FAIL;
}
System.out.println("Test case name: testAddUser, Result: " + result );
}
//Test: Delete User of id 2
//Test: Check if result is success XML.
private void testDeleteUser(){
String callResult = client
.target(REST_SERVICE_URL)
.path("/{userid}")
.resolveTemplate("userid", 2)
.request(MediaType.APPLICATION_XML)
.delete(String.class);
String result = PASS;
if(!SUCCESS_RESULT.equals(callResult)){
result = FAIL;
}
System.out.println("Test case name: testDeleteUser, Result: " + result);
}
}
Agora execute o testador usando Eclipse. Clique com o botão direito no arquivo e siga a opçãoRun as → Java Application. Você verá o seguinte resultado no console do Eclipse -
Test case name: testGetAllUsers, Result: pass
Test case name: testGetUser, Result: pass
Test case name: testUpdateUser, Result: pass
Test case name: testAddUser, Result: pass
Test case name: testDeleteUser, Result: pass
De acordo com a arquitetura REST, um serviço da Web RESTful não deve manter um estado de cliente no servidor. Essa restrição é chamada de apatridia. É responsabilidade do cliente passar seu contexto para o servidor e, em seguida, o servidor pode armazenar esse contexto para processar a solicitação posterior do cliente. Por exemplo, a sessão mantida pelo servidor é identificada pelo identificador de sessão passado pelo cliente.
Os serviços da Web RESTful devem aderir a essa restrição. Vimos isso no capítulo Serviços da Web RESTful - Métodos , que os métodos de serviço da Web não armazenam nenhuma informação do cliente a partir do qual são chamados.
Consider the following URL −
https: // localhost: 8080 / UserManagement / rest / UserService / users / 1
Se você acessar a url acima usando seu navegador ou um cliente baseado em java ou usando Postman, o resultado será sempre o XML do usuário cujo Id é 1 porque o servidor não armazena nenhuma informação sobre o cliente.
<user>
<id>1</id>
<name>mahesh</name>
<profession>1</profession>
</user>
Vantagens da apatridia
A seguir estão os benefícios da apatridia em RESTful Web Services -
Os serviços da Web podem tratar cada solicitação de método independentemente.
Os serviços da Web não precisam manter as interações anteriores do cliente. Isso simplifica o design do aplicativo.
Como o HTTP é um protocolo sem estado, os serviços da Web RESTful funcionam perfeitamente com os protocolos HTTP.
Desvantagens da apatridia
A seguir estão as desvantagens da ausência de estado em RESTful Web Services -
Os serviços da Web precisam obter informações extras em cada solicitação e, em seguida, interpretar para obter o estado do cliente, caso as interações com o cliente precisem ser cuidadas.
O armazenamento em cache refere-se ao armazenamento da resposta do servidor no próprio cliente, para que o cliente não precise fazer uma solicitação do servidor para o mesmo recurso repetidamente. Uma resposta do servidor deve ter informações sobre como o armazenamento em cache deve ser feito, para que um cliente armazene em cache a resposta por um período de tempo ou nunca armazene em cache a resposta do servidor.
A seguir estão os cabeçalhos que uma resposta do servidor pode ter para configurar o cache de um cliente -
Sr. Não. | Cabeçalho e Descrição |
---|---|
1 |
Date Data e hora do recurso quando foi criado. |
2 |
Last Modified Data e hora do recurso quando foi modificado pela última vez. |
3 |
Cache-Control Cabeçalho primário para controlar o cache. |
4 |
Expires Data de expiração e hora do armazenamento em cache. |
5 |
Age Duração em segundos a partir de quando o recurso foi buscado no servidor. |
Cabeçalho Cache-Control
A seguir estão os detalhes de um cabeçalho Cache-Control -
Sr. Não. | Diretriz e descrição |
---|---|
1 |
Public Indica que o recurso pode ser armazenado em cache por qualquer componente. |
2 |
Private Indica que o recurso pode ser armazenado em cache apenas pelo cliente e pelo servidor, nenhum intermediário pode armazenar o recurso em cache. |
3 |
no-cache/no-store Indica que um recurso não pode ser armazenado em cache. |
4 |
max-age Indica que o armazenamento em cache é válido até a idade máxima em segundos. Depois disso, o cliente deve fazer outro pedido. |
5 |
must-revalidate Indicação ao servidor para revalidar o recurso se max-age tiver passado. |
Melhores Práticas
Sempre mantenha conteúdos estáticos como imagens, CSS, JavaScript armazenáveis em cache, com data de validade de 2 a 3 dias.
Nunca mantenha a data de validade muito alta.
O conteúdo dinâmico deve ser armazenado em cache por apenas algumas horas.
Como os serviços da Web RESTful funcionam com caminhos de URL HTTP, é muito importante proteger um serviço da Web RESTful da mesma maneira que um site é protegido.
A seguir estão as melhores práticas a serem seguidas ao projetar um serviço da Web RESTful -
Validation- Valide todas as entradas no servidor. Proteja seu servidor contra ataques de injeção de SQL ou NoSQL.
Session Based Authentication - Use a autenticação baseada em sessão para autenticar um usuário sempre que uma solicitação for feita a um método de serviço da web.
No Sensitive Data in the URL - Nunca use nome de usuário, senha ou token de sessão em uma URL, esses valores devem ser passados para o serviço da Web através do método POST.
Restriction on Method Execution- Permitir o uso restrito de métodos como métodos GET, POST e DELETE. O método GET não deve ser capaz de excluir dados.
Validate Malformed XML/JSON - Verifique a entrada bem formada passada para um método de serviço da web.
Throw generic Error Messages - Um método de serviço da web deve usar mensagens de erro HTTP como 403 para mostrar o acesso proibido, etc.
Código HTTP
Sr. Não. | Código HTTP e descrição |
---|---|
1 |
200 OK - mostra sucesso. |
2 |
201 CREATED- quando um recurso é criado com sucesso usando a solicitação POST ou PUT. Retorna o link para o recurso recém-criado usando o cabeçalho do local. |
3 |
204 NO CONTENT- quando o corpo de resposta está vazio. Por exemplo, uma solicitação DELETE. |
4 |
304 NOT MODIFIED- usado para reduzir o uso da largura de banda da rede no caso de solicitações GET condicionais. O corpo da resposta deve estar vazio. Os cabeçalhos devem ter data, localização, etc. |
5 |
400 BAD REQUEST- afirma que uma entrada inválida foi fornecida. Por exemplo, erro de validação, dados ausentes. |
6 |
401 UNAUTHORIZED - afirma que o usuário está usando um token de autenticação inválido ou incorreto. |
7 |
403 FORBIDDEN- informa que o usuário não está tendo acesso ao método que está sendo usado. Por exemplo, Excluir acesso sem direitos de administrador. |
8 |
404 NOT FOUND - afirma que o método não está disponível. |
9 |
409 CONFLICT- indica a situação de conflito durante a execução do método. Por exemplo, adicionar uma entrada duplicada. |
10 |
500 INTERNAL SERVER ERROR - afirma que o servidor lançou alguma exceção ao executar o método. |
JAX-RSsignifica JAVA API para RESTful Web Services. JAX-RS é uma API e especificação de linguagem de programação baseada em JAVA para fornecer suporte para serviços da Web RESTful criados. Sua versão 2.0 foi lançada em 24 de maio de 2013. JAX-RS usa anotações disponíveis no Java SE 5 para simplificar o desenvolvimento da criação e implantação de serviços da web baseados em JAVA. Ele também fornece suporte para a criação de clientes para RESTful Web Services.
Especificações
A seguir estão as anotações mais comumente usadas para mapear um recurso como um recurso de serviço da web.
Sr. Não. | Anotação e descrição |
---|---|
1 |
@Path Caminho relativo da classe / método de recurso. |
2 |
@GET Solicitação HTTP Get, usada para buscar recursos. |
3 |
@PUT Solicitação HTTP PUT, usada para atualizar o recurso. |
4 |
@POST Solicitação HTTP POST, usada para criar um novo recurso. |
5 |
@DELETE Solicitação HTTP DELETE, usada para excluir o recurso. |
6 |
@HEAD Solicitação HTTP HEAD, usada para obter o status de disponibilidade do método. |
7 |
@Produces Afirma a resposta HTTP gerada pelo serviço da web. Por exemplo, APPLICATION / XML, TEXT / HTML, APPLICATION / JSON etc. |
8 |
@Consumes Indica o tipo de solicitação HTTP. Por exemplo, application / x-www-formurlencoded para aceitar dados de formulário no corpo HTTP durante a solicitação POST. |
9 |
@PathParam Vincula o parâmetro passado ao método a um valor no caminho. |
10 |
@QueryParam Vincula o parâmetro passado ao método a um parâmetro de consulta no caminho. |
11 |
@MatrixParam Vincula o parâmetro passado ao método a um parâmetro de matriz HTTP no caminho. |
12 |
@HeaderParam Vincula o parâmetro passado ao método a um cabeçalho HTTP. |
13 |
@CookieParam Vincula o parâmetro passado ao método a um Cookie. |
14 |
@FormParam Vincula o parâmetro passado ao método a um valor de formulário. |
15 |
@DefaultValue Atribui um valor padrão a um parâmetro passado ao método. |
16 |
@Context Contexto do recurso. Por exemplo, HTTPRequest como um contexto. |
Note- Usamos Jersey, uma implementação de referência de JAX-RS 2.0 da Oracle, nos capítulos RESTful Web Services - First Application e RESTful Web Services - Methods .