Servizi Web RESTful - Guida rapida
Cos'è l'architettura REST?
REST sta per REpresentational State Transfer. REST è un'architettura basata su standard web e utilizza il protocollo HTTP. Ruota intorno a una risorsa in cui ogni componente è una risorsa e una risorsa è accessibile da un'interfaccia comune utilizzando metodi standard HTTP. REST è stato introdotto per la prima volta da Roy Fielding nel 2000.
Nell'architettura REST, un server REST fornisce semplicemente l'accesso alle risorse e il client REST accede e modifica le risorse. Qui ogni risorsa è identificata da URI / ID globali. REST utilizza varie rappresentazioni per rappresentare una risorsa come testo, JSON, XML. JSON è il più popolare.
Metodi HTTP
I seguenti quattro metodi HTTP sono comunemente usati nell'architettura basata su REST.
GET - Fornisce un accesso di sola lettura a una risorsa.
POST - Usato per creare una nuova risorsa.
DELETE - Usato per rimuovere una risorsa.
PUT - Utilizzato per aggiornare una risorsa esistente o creare una nuova risorsa.
Introduzione ai servizi web RESTFul
Un servizio Web è una raccolta di protocolli aperti e standard utilizzati per lo scambio di dati tra applicazioni o sistemi. Le applicazioni software scritte in vari linguaggi di programmazione e in esecuzione su varie piattaforme possono utilizzare i servizi Web per scambiare dati su reti di computer come Internet in un modo simile alla comunicazione tra processi su un singolo computer. Questa interoperabilità (ad esempio, tra Java e Python, o applicazioni Windows e Linux) è dovuta all'uso di standard aperti.
I servizi Web basati sull'architettura REST sono noti come servizi Web RESTful. Questi servizi web utilizzano metodi HTTP per implementare il concetto di architettura REST. Un servizio Web RESTful di solito definisce un URI, Uniform Resource Identifier un servizio, fornisce una rappresentazione delle risorse come JSON e un insieme di metodi HTTP.
Creazione del servizio Web RESTFul
Nei prossimi capitoli, creeremo un servizio web per dire gestione utenti con le seguenti funzionalità:
Sr.No. | URI | Metodo HTTP | POST corpo | Risultato |
---|---|---|---|---|
1 | / UserService / utenti | OTTENERE | vuoto | Mostra l'elenco di tutti gli utenti. |
2 | / UserService / addUser | INVIARE | Stringa JSON | Aggiungi i dettagli del nuovo utente. |
3 | / UserService / getUser /: id | OTTENERE | vuoto | Mostra i dettagli di un utente. |
Questo tutorial ti guiderà su come preparare un ambiente di sviluppo con cui iniziare il tuo lavoro Jersey Frameworkper creare servizi Web RESTful. Attrezzi quadro JerseyJAX-RS 2.0API, che è una specifica standard per creare servizi Web RESTful. Questo tutorial ti insegnerà anche come configurareJDK, Tomcat e Eclipse sulla tua macchina prima di aver configurato Jersey Framework.
Configurazione di Java Development Kit (JDK)
È possibile scaricare l'ultima versione di SDK dal sito Java di Oracle - Download di Java SE . Troverai le istruzioni per l'installazione di JDK nei file scaricati. Segui le istruzioni fornite per installare e configurare il setup. Infine imposta il filePATH e JAVA_HOME variabili di ambiente per fare riferimento alla directory che contiene Java e Javac, in genere java_install_dir / bin e java_install_dir rispettivamente.
Se stai utilizzando Windows e hai installato JDK in C: \ jdk1.7.0_75, dovresti inserire la seguente riga nel tuo file C: \ autoexec.bat.
set PATH = C:\jdk1.7.0_75\bin;%PATH%
set JAVA_HOME = C:\jdk1.7.0_75
In alternativa, su Windows NT / 2000 / XP, è anche possibile fare clic con il pulsante destro del mouse su Risorse del computer → selezionare Proprietà → quindi Avanzate → quindi Variabili d'ambiente. Quindi, si aggiorna il valore PATH e si preme il pulsante OK.
Su Unix (Solaris, Linux, ecc.), Se l'SDK è installato in /usr/local/jdk1.7.0_75 e si utilizza la shell C, inserire quanto segue nel file .cshrc.
setenv PATH /usr/local/jdk1.7.0_75/bin:$PATH
setenv JAVA_HOME /usr/local/jdk1.7.0_75
In alternativa, se utilizzi un IDE (Integrated Development Environment) come Borland JBuilder, Eclipse, IntelliJ IDEA o Sun ONE Studio, compila ed esegui un semplice programma per confermare che l'IDE sa dove hai installato Java, altrimenti esegui la corretta configurazione come indicato nel documento dell'IDE.
Imposta Eclipse IDE
Tutti gli esempi in questo tutorial sono stati scritti utilizzando l'IDE Eclipse. Quindi, ti suggerirei di avere l'ultima versione di Eclipse installata sulla tua macchina.
Per installare Eclipse IDE, scarica gli ultimi binari Eclipse da https://www.eclipse.org/downloads/. Dopo aver scaricato l'installazione, decomprimere la distribuzione binaria in una posizione comoda. Ad esempio, in C: \ eclipse su Windows, o / usr / local / eclipse su Linux / Unix e infine imposta la variabile PATH in modo appropriato.
Eclipse può essere avviato eseguendo i seguenti comandi su una macchina Windows, oppure puoi semplicemente fare doppio clic su eclipse.exe.
%C:\eclipse\eclipse.exe
Eclipse può essere avviato eseguendo i seguenti comandi su una macchina Unix (Solaris, Linux, ecc.) -
$/usr/local/eclipse/eclipse
Dopo un avvio riuscito, se tutto va bene, lo schermo dovrebbe visualizzare il seguente risultato:
Imposta le librerie di Jersey Framework
Ora, se tutto va bene, puoi procedere alla configurazione del framework Jersey. Di seguito sono riportati alcuni semplici passaggi per scaricare e installare il framework sul tuo computer.
Scegli se installare Jersey su Windows o Unix, quindi procedi al passaggio successivo per scaricare il file .zip per Windows e quindi il file .tz per Unix.
Scarica l'ultima versione dei binari del framework Jersey dal seguente link: https://jersey.java.net/download.html.
Al momento della stesura di questo tutorial, ho scaricato jaxrs-ri-2.17.zip sulla mia macchina Windows e quando decomprimi il file scaricato, ti darà la struttura della directory all'interno di E: \ jaxrs-ri-2.17 \ jaxrs-ri come mostrato nello screenshot seguente.
Troverai tutte le librerie Jersey nelle directory C:\jaxrs-ri-2.17\jaxrs-ri\lib e dipendenze in C:\jaxrs-ri-2.17\jaxrs-ri\ext. Assicurati di impostare correttamente la tua variabile CLASSPATH su questa directory altrimenti incontrerai problemi durante l'esecuzione dell'applicazione. Se stai utilizzando Eclipse, non è necessario impostare CLASSPATH perché tutte le impostazioni verranno eseguite tramite Eclipse.
Imposta Apache Tomcat
Puoi scaricare l'ultima versione di Tomcat da https://tomcat.apache.org/. Dopo aver scaricato l'installazione, decomprimere la distribuzione binaria in una posizione comoda. Ad esempio in C: \ apache-tomcat-7.0.59 su Windows, o /usr/local/apache-tomcat-7.0.59 su Linux / Unix e impostare la variabile d'ambiente CATALINA_HOME che punta alle posizioni di installazione.
Tomcat può essere avviato eseguendo i seguenti comandi su una macchina Windows, oppure puoi semplicemente fare doppio clic su startup.bat.
%CATALINA_HOME%\bin\startup.bat
o
C:\apache-tomcat-7.0.59\bin\startup.bat
Tomcat può essere avviato eseguendo i seguenti comandi su una macchina Unix (Solaris, Linux, ecc.) -
$CATALINA_HOME/bin/startup.sh
o
/usr/local/apache-tomcat-7.0.59/bin/startup.sh
Dopo un avvio riuscito, le applicazioni Web predefinite incluse con Tomcat saranno disponibili visitando http://localhost:8080/. Se tutto va bene, dovrebbe visualizzare il seguente risultato:
Ulteriori informazioni sulla configurazione e l'esecuzione di Tomcat sono disponibili nella documentazione inclusa in questa pagina. Queste informazioni sono disponibili anche sul sito Web di Tomcat:https://tomcat.apache.org.
Tomcat può essere arrestato eseguendo i seguenti comandi su una macchina Windows:
%CATALINA_HOME%\bin\shutdown
o
C:\apache-tomcat-7.0.59\bin\shutdown
Tomcat può essere arrestato eseguendo i seguenti comandi su una macchina Unix (Solaris, Linux, ecc.) -
$CATALINA_HOME/bin/shutdown.sh
o
/usr/local/apache-tomcat-7.0.59/bin/shutdown.sh
Una volta terminato questo ultimo passaggio, sei pronto per procedere con il tuo primo esempio di Jersey che vedrai nel prossimo capitolo.
Cominciamo a scrivere i servizi web RESTful effettivi con Jersey Framework. Prima di iniziare a scrivere il tuo primo esempio utilizzando Jersey Framework, devi assicurarti di aver configurato correttamente il tuo ambiente Jersey come spiegato nel capitolo Servizi Web RESTful - Configurazione dell'ambiente . Qui, presumo anche che tu abbia una piccola conoscenza operativa di Eclipse IDE.
Quindi, procediamo a scrivere una semplice applicazione Jersey che esporrà un metodo di servizio web per visualizzare l'elenco degli utenti.
Creazione di un progetto Java
Il primo passo è creare un progetto Web dinamico utilizzando Eclipse IDE. Segui l'opzioneFile → New → Project e infine seleziona il file Dynamic Web Projectprocedura guidata dall'elenco delle procedure guidate. Ora assegna un nome al tuo progetto comeUserManagement utilizzando la finestra della procedura guidata come mostrato nello screenshot seguente -
Una volta che il tuo progetto è stato creato con successo, avrai il seguente contenuto nel tuo file Project Explorer -
Aggiunta delle librerie richieste
Come secondo passo aggiungiamo Jersey Framework e le sue dipendenze (librerie) nel nostro progetto. Copia tutti i jar dalle seguenti directory della cartella zip di download jersey nella directory WEB-INF / lib del progetto.
- \jaxrs-ri-2.17\jaxrs-ri\api
- \jaxrs-ri-2.17\jaxrs-ri\ext
- \jaxrs-ri-2.17\jaxrs-ri\lib
Ora, fai clic con il pulsante destro del mouse sul nome del tuo progetto UserManagement e poi segui l'opzione disponibile nel menu contestuale - Build Path → Configure Build Path per visualizzare la finestra Percorso build Java.
Ora usa Add JARs pulsante disponibile sotto Libraries scheda per aggiungere i JAR presenti nella directory WEBINF / lib.
Creazione dei file di origine
Ora creiamo i file sorgente effettivi sotto UserManagementprogetto. Per prima cosa dobbiamo creare un pacchetto chiamatocom.tutorialspoint. Per fare ciò, fai clic con il pulsante destro del mouse su src nella sezione Esplora pacchetti e segui l'opzione -New → Package.
Successivamente creeremo UserService.java, User.java,UserDao.java file nel pacchetto 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();
}
}
Ci sono due punti importanti da notare sul programma principale,
UserService.java
Il primo passaggio consiste nello specificare un percorso per il servizio Web utilizzando l'annotazione @Path in UserService.
Il secondo passaggio consiste nello specificare un percorso per il particolare metodo del servizio Web utilizzando l'annotazione @Path al metodo di UserService.
Creazione del file di configurazione Web.xml
È necessario creare un file di configurazione xml Web che è un file XML e viene utilizzato per specificare il servlet del framework Jersey per la nostra applicazione.
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>
Distribuzione del programma
Una volta che hai finito con la creazione di file di configurazione web e sorgente, sei pronto per questo passaggio che è la compilazione e l'esecuzione del tuo programma. Per fare ciò, utilizzando Eclipse, esporta la tua applicazione come file war e distribuisci lo stesso in Tomcat.
Per creare un file WAR utilizzando eclipse, segui l'opzione File → export → Web → War Filee infine selezionare Gestione utenti del progetto e cartella di destinazione. Per distribuire un file war in Tomcat, posizionare UserManagement.war nel fileTomcat Installation Directory → webapps directory e avvia il Tomcat.
Esecuzione del programma
Utilizziamo Postman , un'estensione di Chrome, per testare i nostri servizi web.
Fai una richiesta a UserManagement per ottenere l'elenco di tutti gli utenti. Metti http: // localhost: 8080 / UserManagement / rest / UserService / users in POSTMAN con la richiesta GET e vedi il seguente risultato.
Congratulazioni, hai creato con successo la tua prima applicazione RESTful.
Cos'è una risorsa?
L'architettura REST tratta ogni contenuto come una risorsa. Queste risorse possono essere file di testo, pagine HTML, immagini, video o dati aziendali dinamici. Il server REST fornisce semplicemente l'accesso alle risorse e il client REST accede e modifica le risorse. Qui ogni risorsa è identificata da URI / ID globali. REST utilizza varie rappresentazioni per rappresentare una risorsa in cui Text, JSON, XML. Le rappresentazioni più popolari delle risorse sono XML e JSON.
Rappresentanza delle risorse
Una risorsa in REST è un oggetto simile nella programmazione orientata agli oggetti o è come un'entità in un database. Una volta che una risorsa è stata identificata, la sua rappresentazione deve essere decisa utilizzando un formato standard in modo che il server possa inviare la risorsa nel suddetto formato e il client possa comprendere lo stesso formato.
Ad esempio, nel capitolo Servizi Web RESTful - Prima applicazione , un utente è una risorsa rappresentata utilizzando il seguente formato XML:
<user>
<id>1</id>
<name>Mahesh</name>
<profession>Teacher</profession>
</user>
La stessa risorsa può essere rappresentata in formato JSON come segue:
{
"id":1,
"name":"Mahesh",
"profession":"Teacher"
}
Buona rappresentazione delle risorse
REST non impone alcuna restrizione sul formato di una rappresentazione della risorsa. Un client può richiedere la rappresentazione JSON mentre un altro client può richiedere la rappresentazione XML della stessa risorsa al server e così via. È responsabilità del server REST passare al client la risorsa nel formato che il client comprende.
Di seguito sono riportati alcuni punti importanti da considerare durante la progettazione di un formato di rappresentazione di una risorsa nei servizi Web RESTful.
Understandability - Sia il server che il client dovrebbero essere in grado di comprendere e utilizzare il formato di rappresentazione della risorsa.
Completeness- Il formato dovrebbe essere in grado di rappresentare completamente una risorsa. Ad esempio, una risorsa può contenere un'altra risorsa. Il formato dovrebbe essere in grado di rappresentare strutture di risorse semplici e complesse.
Linkablity - Una risorsa può avere un collegamento a un'altra risorsa, un formato dovrebbe essere in grado di gestire tali situazioni.
Tuttavia, attualmente la maggior parte dei servizi Web rappresentano risorse utilizzando il formato XML o JSON. Sono disponibili numerose librerie e strumenti per comprendere, analizzare e modificare i dati XML e JSON.
I servizi Web RESTful utilizzano i protocolli HTTP come mezzo di comunicazione tra client e server. Un client invia un messaggio sotto forma di una richiesta HTTP e il server risponde sotto forma di una risposta HTTP. Questa tecnica viene definita messaggistica. Questi messaggi contengono dati e metadati del messaggio, ovvero informazioni sul messaggio stesso. Diamo uno sguardo alla richiesta HTTP e ai messaggi di risposta HTTP per HTTP 1.1.
Richiesta HTTP
Una richiesta HTTP ha cinque parti principali:
Verb - Indica i metodi HTTP come GET, POST, DELETE, PUT, ecc.
URI - Uniform Resource Identifier (URI) per identificare la risorsa sul server.
HTTP Version- Indica la versione HTTP. Ad esempio, HTTP v1.1.
Request Header- Contiene i metadati per il messaggio di richiesta HTTP come coppie chiave-valore. Ad esempio, tipo di client (o browser), formato supportato dal client, formato del corpo del messaggio, impostazioni della cache, ecc.
Request Body - Contenuto del messaggio o rappresentazione delle risorse.
Risposta HTTP
Una risposta HTTP ha quattro parti principali:
Status/Response Code- Indica lo stato del server per la risorsa richiesta. Ad esempio, 404 significa risorsa non trovata e 200 significa che la risposta è ok.
HTTP Version- Indica la versione HTTP. Ad esempio HTTP v1.1.
Response Header- Contiene i metadati per il messaggio di risposta HTTP come coppie di valori chiave. Ad esempio, lunghezza del contenuto, tipo di contenuto, data di risposta, tipo di server, ecc.
Response Body - Contenuto del messaggio di risposta o rappresentazione delle risorse.
Esempio
Come abbiamo spiegato nel capitolo Servizi Web RESTful - Prima applicazione , inseriamo http: // localhost: 8080 / UserManagement / rest / UserService / users nel POSTMAN con una richiesta GET. Se fai clic sul pulsante Anteprima che si trova vicino al pulsante di invio di Postman e quindi fai clic sul pulsante Invia, potresti vedere il seguente output.
Qui puoi vedere, il browser ha inviato una richiesta GET e ha ricevuto un corpo di risposta come XML.
L'indirizzamento si riferisce all'individuazione di una o più risorse che si trovano sul server. È analogo individuare un indirizzo postale di una persona.
Ogni risorsa nell'architettura REST è identificata dal suo URI (Uniform Resource Identifier). Un URI ha il seguente formato:
<protocol>://<service-name>/<ResourceType>/<ResourceID>
Lo scopo di un URI è individuare una o più risorse sul server che ospita il servizio web. Un altro attributo importante di una richiesta è VERBO che identifica l'operazione da eseguire sulla risorsa. Ad esempio, nel capitolo Servizi Web RESTful - Prima applicazione , l'URI èhttp://localhost:8080/UserManagement/rest/UserService/users e il VERBO è GET.
Costruire un URI standard
I seguenti sono punti importanti da considerare durante la progettazione di un URI:
Use Plural Noun- Usa un nome plurale per definire le risorse. Ad esempio, abbiamo utilizzato gli utenti per identificare gli utenti come una risorsa.
Avoid using spaces- Utilizzare il trattino basso (_) o il trattino (-) quando si utilizza un nome di risorsa lungo. Ad esempio, utilizza authorized_users invece di% 20users autorizzati.
Use lowercase letters - Sebbene l'URI non faccia distinzione tra maiuscole e minuscole, è buona norma mantenere l'URL solo in lettere minuscole.
Maintain Backward Compatibility- Poiché il servizio Web è un servizio pubblico, una volta reso pubblico dovrebbe essere sempre disponibile un URI. Nel caso in cui l'URI venga aggiornato, reindirizza l'URI precedente a un nuovo URI utilizzando il codice di stato HTTP, 300.
Use HTTP Verb- Usa sempre verbo HTTP come GET, PUT e DELETE per eseguire le operazioni sulla risorsa. Non è consigliabile utilizzare il nome delle operazioni nell'URI.
Esempio
Di seguito è riportato un esempio di un URI scadente per recuperare un utente.
http://localhost:8080/UserManagement/rest/UserService/getUser/1
Di seguito è riportato un esempio di un buon URI per recuperare un utente.
http://localhost:8080/UserManagement/rest/UserService/users/1
Come abbiamo discusso nei capitoli precedenti, il servizio Web RESTful utilizza molti verbi HTTP per determinare l'operazione da eseguire sulle risorse specificate. La tabella seguente riporta gli esempi dei verbi HTTP più comunemente usati.
Sr.No. | Metodo HTTP, URI e funzionamento |
---|---|
1 | GET http: // localhost: 8080 / UserManagement / rest / UserService / users Ottiene l'elenco degli utenti. (Sola lettura) |
2 |
GET http: // localhost: 8080 / UserManagement / rest / UserService / users / 1 Ottiene l'utente dell'ID 1 (Sola lettura) |
3 |
PUT http: // localhost: 8080 / UserManagement / rest / UserService / users / 2 Inserisce utente con ID 2 (Idempotente) |
4 |
POST http: // localhost: 8080 / UserManagement / rest / UserService / users / 2 Aggiorna l'utente con l'ID 2 (N / A) |
5 |
DELETE http: // localhost: 8080 / UserManagement / rest / UserService / users / 1 Elimina l'utente con ID 1 (Idempotente) |
6 |
OPTIONS http: // localhost: 8080 / UserManagement / rest / UserService / users Elenca le operazioni supportate in un servizio Web. (Sola lettura) |
7 |
HEAD http: // localhost: 8080 / UserManagement / rest / UserService / users Restituisce solo l'intestazione HTTP, nessun corpo. (Sola lettura) |
Devono essere considerati i seguenti punti.
Le operazioni GET sono di sola lettura e sono sicure.
Le operazioni PUT e DELETE sono idempotenti, il che significa che il loro risultato sarà sempre lo stesso, non importa quante volte queste operazioni vengono invocate.
Le operazioni PUT e POST sono quasi le stesse con la differenza che risiede solo nel risultato in cui l'operazione PUT è idempotente e l'operazione POST può causare un risultato diverso.
Esempio
Aggiorniamo un esempio creato nel capitolo Servizi Web RESTful - Prima applicazione per creare un servizio Web in grado di eseguire operazioni CRUD (Crea, Leggi, Aggiorna, Elimina). Per semplicità, abbiamo utilizzato un file I / O per sostituire le operazioni del database.
Cerchiamo di aggiornare il User.java, UserDao.java e UserService.java file nel pacchetto 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>";
}
}
Ora usando Eclipse, esporta la tua applicazione come file WAR Filee distribuire lo stesso in Tomcat. Per creare un file WAR utilizzando eclipse, segui questo percorso:File → export → Web → War Filee infine seleziona UserManagement del progetto e la cartella di destinazione. Per distribuire un file WAR in Tomcat, posizionare UserManagement.war nel fileTomcat Installation Directory → webapps directory e l'avvio di Tomcat.
Testare il servizio Web
Jersey fornisce API per creare un client di servizi Web per testare i servizi Web. Abbiamo creato una classe di test di esempioWebServiceTester.java nel pacchetto com.tutorialspoint nello stesso progetto.
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);
}
}
Ora esegui il tester usando Eclipse. Fare clic con il tasto destro sul file e seguire l'opzioneRun as → Java Application. Vedrai il seguente risultato nella console 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
In base all'architettura REST, un servizio Web RESTful non dovrebbe mantenere uno stato client sul server. Questa restrizione è chiamata apolidia. È responsabilità del client passare il proprio contesto al server e quindi il server può memorizzare questo contesto per elaborare l'ulteriore richiesta del client. Ad esempio, la sessione gestita dal server viene identificata dall'identificatore di sessione passato dal client.
I servizi Web RESTful dovrebbero aderire a questa restrizione. Lo abbiamo visto nel capitolo Servizi Web RESTful - Metodi , che i metodi del servizio Web non memorizzano alcuna informazione dal client da cui vengono richiamati.
Consider the following URL −
https: // localhost: 8080 / UserManagement / rest / UserService / users / 1
Se si preme l'URL sopra utilizzando il browser o un client basato su Java o utilizzando Postman, il risultato sarà sempre l'XML dell'utente il cui ID è 1 perché il server non memorizza alcuna informazione sul client.
<user>
<id>1</id>
<name>mahesh</name>
<profession>1</profession>
</user>
Vantaggi dell'apolidia
Di seguito sono riportati i vantaggi dell'apolidia nei servizi Web RESTful:
I servizi Web possono trattare ogni richiesta di metodo in modo indipendente.
I servizi Web non devono mantenere le interazioni precedenti del cliente. Semplifica la progettazione dell'applicazione.
Poiché HTTP è esso stesso un protocollo di apolidia, i servizi Web RESTful funzionano perfettamente con i protocolli HTTP.
Svantaggi dell'apolidia
Di seguito sono riportati gli svantaggi dell'apolidia nei servizi Web RESTful:
I servizi Web devono ottenere informazioni aggiuntive in ogni richiesta e quindi interpretare per ottenere lo stato del client nel caso in cui le interazioni del client debbano essere prese in considerazione.
La memorizzazione nella cache si riferisce alla memorizzazione della risposta del server nel client stesso, in modo che un client non debba effettuare una richiesta al server per la stessa risorsa ancora e ancora. Una risposta del server dovrebbe contenere informazioni su come eseguire la memorizzazione nella cache, in modo che un client memorizzi nella cache la risposta per un periodo di tempo o non memorizzi mai nella cache la risposta del server.
Di seguito sono riportate le intestazioni che una risposta del server può avere per configurare la memorizzazione nella cache di un client:
Sr.No. | Intestazione e descrizione |
---|---|
1 |
Date Data e ora della risorsa in cui è stata creata. |
2 |
Last Modified Data e ora della risorsa in cui è stata modificata l'ultima volta. |
3 |
Cache-Control Intestazione primaria per controllare la memorizzazione nella cache. |
4 |
Expires Data e ora di scadenza della memorizzazione nella cache. |
5 |
Age Durata in secondi da quando la risorsa è stata recuperata dal server. |
Intestazione controllo cache
Di seguito sono riportati i dettagli di un'intestazione Cache-Control:
Sr.No. | Direttiva e descrizione |
---|---|
1 |
Public Indica che la risorsa può essere memorizzata nella cache da qualsiasi componente. |
2 |
Private Indica che la risorsa può essere memorizzata nella cache solo dal client e dal server, nessun intermediario può memorizzare nella cache la risorsa. |
3 |
no-cache/no-store Indica che una risorsa non è memorizzabile nella cache. |
4 |
max-age Indica che la memorizzazione nella cache è valida fino a max-age in secondi. Successivamente, il cliente deve fare un'altra richiesta. |
5 |
must-revalidate Indicazione al server di riconvalidare la risorsa se la max-age è stata superata. |
Migliori pratiche
Mantieni sempre contenuti statici come immagini, CSS, JavaScript memorizzabili nella cache, con data di scadenza da 2 a 3 giorni.
Non mantenere mai la data di scadenza troppo alta.
Il contenuto dinamico dovrebbe essere memorizzato nella cache solo per poche ore.
Poiché i servizi Web RESTful funzionano con percorsi URL HTTP, è molto importante salvaguardare un servizio Web RESTful nello stesso modo in cui è protetto un sito Web.
Di seguito sono riportate le migliori pratiche a cui attenersi durante la progettazione di un servizio Web RESTful:
Validation- Convalida tutti gli input sul server. Proteggi il tuo server dagli attacchi di iniezione SQL o NoSQL.
Session Based Authentication - Utilizzare l'autenticazione basata sulla sessione per autenticare un utente ogni volta che viene effettuata una richiesta a un metodo del servizio Web.
No Sensitive Data in the URL - Non utilizzare mai nome utente, password o token di sessione in un URL, questi valori devono essere passati al servizio Web tramite il metodo POST.
Restriction on Method Execution- Consenti l'uso limitato di metodi come i metodi GET, POST e DELETE. Il metodo GET non dovrebbe essere in grado di eliminare i dati.
Validate Malformed XML/JSON - Verificare la presenza di un input ben formato passato a un metodo di servizio Web.
Throw generic Error Messages - Un metodo di servizio Web dovrebbe utilizzare messaggi di errore HTTP come 403 per mostrare l'accesso vietato, ecc.
Codice HTTP
Sr.No. | Codice HTTP e descrizione |
---|---|
1 |
200 OK - mostra successo. |
2 |
201 CREATED- quando una risorsa viene creata con successo utilizzando la richiesta POST o PUT. Restituisce il collegamento alla risorsa appena creata utilizzando l'intestazione della posizione. |
3 |
204 NO CONTENT- quando il corpo della risposta è vuoto. Ad esempio, una richiesta DELETE. |
4 |
304 NOT MODIFIED- utilizzato per ridurre l'utilizzo della larghezza di banda della rete in caso di richieste GET condizionali. Il corpo della risposta dovrebbe essere vuoto. Le intestazioni dovrebbero contenere data, posizione, ecc. |
5 |
400 BAD REQUEST- afferma che viene fornito un input non valido. Ad esempio, errore di convalida, dati mancanti. |
6 |
401 UNAUTHORIZED - afferma che l'utente sta utilizzando un token di autenticazione non valido o errato. |
7 |
403 FORBIDDEN- afferma che l'utente non ha accesso al metodo utilizzato. Ad esempio, Elimina accesso senza diritti di amministratore. |
8 |
404 NOT FOUND - afferma che il metodo non è disponibile. |
9 |
409 CONFLICT- indica la situazione di conflitto durante l'esecuzione del metodo. Ad esempio, l'aggiunta di voci duplicate. |
10 |
500 INTERNAL SERVER ERROR - afferma che il server ha generato qualche eccezione durante l'esecuzione del metodo. |
JAX-RSè l'acronimo di JAVA API per RESTful Web Services. JAX-RS è un'API e una specifica del linguaggio di programmazione basata su JAVA per fornire supporto per i servizi Web RESTful creati. La sua versione 2.0 è stata rilasciata il 24 maggio 2013. JAX-RS utilizza le annotazioni disponibili da Java SE 5 per semplificare lo sviluppo della creazione e della distribuzione di servizi Web basati su JAVA. Fornisce inoltre supporti per la creazione di client per servizi Web RESTful.
Specifiche
Di seguito sono riportate le annotazioni più comunemente utilizzate per mappare una risorsa come risorsa del servizio Web.
Sr.No. | Annotazione e descrizione |
---|---|
1 |
@Path Percorso relativo della classe / metodo della risorsa. |
2 |
@GET Richiesta HTTP Get, utilizzata per recuperare la risorsa. |
3 |
@PUT Richiesta HTTP PUT, utilizzata per aggiornare la risorsa. |
4 |
@POST Richiesta HTTP POST, utilizzata per creare una nuova risorsa. |
5 |
@DELETE Richiesta HTTP DELETE, utilizzata per eliminare la risorsa. |
6 |
@HEAD Richiesta HTTP HEAD, utilizzata per ottenere lo stato della disponibilità del metodo. |
7 |
@Produces Indica la risposta HTTP generata dal servizio web. Ad esempio, APPLICATION / XML, TEXT / HTML, APPLICATION / JSON ecc. |
8 |
@Consumes Indica il tipo di richiesta HTTP. Ad esempio, application / x-www-formurlencoded per accettare i dati del modulo nel corpo HTTP durante la richiesta POST. |
9 |
@PathParam Associa il parametro passato al metodo a un valore in path. |
10 |
@QueryParam Associa il parametro passato al metodo a un parametro di query nel percorso. |
11 |
@MatrixParam Associa il parametro passato al metodo a un parametro della matrice HTTP in path. |
12 |
@HeaderParam Associa il parametro passato al metodo a un'intestazione HTTP. |
13 |
@CookieParam Associa il parametro passato al metodo a un cookie. |
14 |
@FormParam Associa il parametro passato al metodo a un valore del modulo. |
15 |
@DefaultValue Assegna un valore predefinito a un parametro passato al metodo. |
16 |
@Context Contesto della risorsa. Ad esempio, HTTPRequest come contesto. |
Note- Abbiamo utilizzato Jersey, un'implementazione di riferimento di JAX-RS 2.0 di Oracle, nei capitoli RESTful Web Services - First Application e RESTful Web Services - Methods .