Nel abbiamo dimostrato con un semplice esempio come creare un webservice con Jersey. Ora vediamo come sia altrettanto facile “consumare” i metodi esposti dal webservice realizzando una web application. L’applicazione avrà il compito di esporre in forma tabellare i dati restituiti dal servizio, visualizzare l’età media delle persone calcolata dal webservice e predisporre l’inserimento di un nuovo record. Per costruire la webapp ci serviremo di PrimeFaces, una suite open source che utilizza il framework Java Server Faces 2.0, e che si sta imponendo nello scenario delle tecnologie web di presentazione.
Il nostro lavoro si suddivide in tre parti: la definizione della webapp e dei file di configurazione, l’implementazione del client per la chiamata al servizio, e infine la costruzione dell’interfaccia utente.
Parte 1: la definizione della webapp
Iniziamo costruendo un nuovo progetto Maven con Eclipse che chiameremo jsfJersey. Poichè non disponiamo di un archetipo specifico procediamo spuntando il flag “Create a simple project (skip archetype selection)”.
Dalle properties del progetto selezioniamo la scheda “Project facets” e modifichiamo come da figura:
A seguito di questa impostazione è possibile ricevere la segnalazione: “Dynamic Web Module 3.0 requires Java 1.6 or newer”, pertanto vi consiglio di impostare il vostro progetto puntando ad un JDK 1.7.
Nel file pom.xml
inseriamo le dipendenze richieste per il client Jersey e per l’installazione di PrimeFaces:
com.sun.jersey jersey-client 1.13 com.sun.jersey jersey-server 1.13 com.sun.faces jsf-api 2.2.4 com.sun.faces jsf-impl 2.2.4 org.primefaces primefaces 5.0
Per elaborare i dati forniti dal servizio forniti in formato JSON, utilizzeremo la libreria , riportiamo di seguito la dipendenza.
com.google.code.gson gson 2.3
Abbiamo terminato la configurazione delle dipendenze, passiamo ora a definire le caratteristiche della nostra webapp integrando il file web.xml
. Innanzitutto inseriamo la chiamata a FacesServlet
, la servlet che gestisce il ciclo di vita dei processi e le interfacce delle applicazioni JSF2, aggiungiamola nella corrispondente sezione del file.
Faces Servlet javax.faces.webapp.FacesServlet 1
Includiamo ora alcuni parametri per la determinazione delle pagine JSF: STATE_SAVING_METHOD
specifica che lo stato dei componenti JSF verrà salvato nel client. Il tag url-pattern
indica la richiesta URL che l’utente deve usare per invocare la FacesServlet, mentre il parametro STATE_SAVING_METHOD
specifica che il suffisso fisico delle pagine JSF è .xhtml
. In questo modo assegnando come welcome-file la pagina index.jsf
verremo reindirizzati alla pagina index.xhtml
.
javax.faces.STATE_SAVING_METHOD client javax.faces.DEFAULT_SUFFIX .xhtml Faces Servlet *.jsf
JSF può richiedere delle configurazioni aggiuntive come convertitori, validatori o managed beans. Queste impostazioni vanno specificate in un file a parte chiamato faces-config.xml
da posizionare all’interno della cartella WEB-INF. Nel nostro esempio tuttavia non abbiamo bisogno di impostazioni particolari.
Parte 2: la creazione del client
Vediamo ora come richiamare il servizio REST definito nel e rendere disponibili i dati alla nostra applicazione. Partiamo inserendo una classe POJO Persona
con la stessa struttura definita nel webservice.
public class Persona implements Serializable { private String id; private String nome; private String cognome; private String eta; private String telefono; private String email; public Persona(String Id, String Nome, String Cognome, String Eta, String Telefono, String Email) { this.id = Id; this.nome = Nome; this.cognome = Cognome; this.eta = Eta; this.telefono = Telefono; this.email = Email; } // i getter e setter non sono riportati }
Passiamo quindi alla chiamata del servizio testJersey
: implementeremo la nostra classe PersService
che utilizza le librerie client di Jersey incapsulandone l’utilizzo.
Per accedere correttamente al servizio dobbiamo creare un’istanza della classe Client
, e passando a questa un URI, possiamo ottenere un oggetto WebResource
: utilizzeremo quest’ultimo per tutte le chiamate che ci servono.
PersService
contiene tre metodi. I primi due eseguono le richieste HTTP GET
per estrarre la lista di oggetti Persona
e l’età anagrafica media, il terzo consente di inviare dati.
Vediamo i due metodi di lettura dati: mentre l’età media è restituita come testo semplice e non richiede ulteriori elaborazioni, la lista di persone è serializzata in formato JSON. Per effettuarne la deserializzazione, come detto, ci affideremo a GSON. Per i dettagli su come funziona GSON rimandiamo ai post già su questo argomento.
L’invio dei dati avviene tramite il metodo processAction
, che, assegnando un oggetto Persona
ad una istanza della classe Form
, effettua la spedizione di parametri multipli tramite una richiesta di tipo POST.
@ManagedBean(name = "persService") @ApplicationScoped public class PersService { public String MY_REST = "/rest"; final String PERS = "persona"; final String ETAPERS = "persona/etamedia"; ClientConfig config = new DefaultClientConfig(); Client client = Client.create(config); WebResource service = client.resource(getBaseURI()); WebResource restWS = service.path(MY_REST); public String etaPers() { String etapers = restWS.path(ETAPERS).accept(MediaType.TEXT_PLAIN).get(String.class); return etapers; } public ListcreatePers() { List people = new ArrayList(); Gson gson = new Gson(); String Json = restWS.path(PERS).accept(MediaType.APPLICATION_JSON).get(String.class); JsonParser parser = new JsonParser(); JsonObject rootObejct = parser.parse(Json).getAsJsonObject(); JsonElement personaElemento = rootObejct.get("persona"); Type personaListaType = new TypeToken >() {}.getType(); people = gson.fromJson(personaElemento, personaListaType); return people; } public void processAction(Persona pers) { Form form = new Form(); form.add("id", pers.getId()); form.add("nome", pers.getNome()); form.add("cognome", pers.getCognome()); form.add("eta", pers.getEta()); form.add("telefono", pers.getTelefono()); form.add("email", pers.getEmail()); ClientResponse response = restWS.path(PERS).type(MediaType.APPLICATION_FORM_URLENCODED) .post(ClientResponse.class, form); } private static URI getBaseURI() { return UriBuilder.fromUri("testJersey").build(); } }
Parte 3: la definizione delle interfacce utente
Nell’ultima parte di questo tutorial, costruiremo l’interfaccia utente che consiste in due pagine JSF e i relativi ManagedBean
di cui riporteremo solamente le parti salienti, mentre potrete consultare il progetto completo su GitHub. La prima pagina rappresenta i dati restituiti dal servizio, la seconda contiene il form di raccolta dati per la spedizione verso il webservice.
La prima pagina è index
dove inseriamo due componenti per la visualizzazione dei dati. Nello specifico utilizziamo un oggetto Datatable per l’esposizione della lista di persone, e una finestra di messaggio azionata da un pulsante per la visualizzazione dell’età media.
Una menzione particolare merita DataTable
, un oggetto del framework JQuery
che espone i dati in forma tabellare ed interattiva. Questo è uno strumento molto importante, poiché ci aiuta in una delle necessità più comuni nello sviluppo di un’applicazione, ovvero l’esposizione tabellare dei dati risultato di una query nel database. L’uso di entrambi i componenti è documentato nello ShowCase di PrimeFaces.
Eseguendo la webapp, il codice appena visto genera la pagina seguente:
La gestione dei dati visualizzati nella pagina index
è a carico del bean BasicView
che richiama i metodi della classe PersService
per ottenere i dati dal webservice. Da notare l’annotazione @PostConstruct
in fase di caricamento della lista di oggetti Persona, che ci garantisce il popolamento del Datatable dopo che il bean è stato istanziato.
@ManagedBean(name="dtBasicView") @ViewScoped public class BasicView implements Serializable { private Listpers; @ManagedProperty("#{persService}") private PersService service; @PostConstruct public void init() { pers = service.createPers(); }
Il metodo info
assegna il dato relativo all’età media al componente messages
di PrimeFaces.
public void info() { String etaPers = service.etaPers(); FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "", "L'età media delle persone è " + etaPers)); }
Cliccando il pulsante “Inserisci nuovo record” si viene reindirizzati alla seconda pagina aggiungiPersona
che contiene invece il form di inserimento dati da inviare al webservice.
Di seguito la pagina risultato:
Il bean MaskView
ha il compito di mappare i dati del form in un oggetto Persona
e richiamare il metodo processAction
, già visto in precedenza, per la spedizione al servizio.
public String addPersona() { pers = new Persona(id, nome, cognome, eta, telefono, email); service.processAction(pers); return "index"; }
Conclusioni
Molti tutorial che illustrano i webservice, si focalizzano sulla costruzione del servizio, ma spiegano poco sulla costruzione del client. Per questo, dopo aver illustrato la definizione del servizio, abbiamo costruito un’applicazione web client completa introducendo anche PrimeFaces, una suite di componenti open source per Java Server Faces dalle grandi potenzialità.
Il progetto jsfJersey è interamente consultabile su GitHub.