In questo post vediamo come realizzare una semplice applicazione web che gestisce entità di dati in visualizzazione come lista e come inserimento e dettaglio.
Per gestire al meglio i risultati in formato tabellare utilizziamo JSON.
Il contenuto del div può essere popolato dinamicamente lato Ajax con:
In questo esempio, preso dall'articolo presente su HTML.it (
link articolo), si può vedere come realizzare il servizio utilizzando JSON per la lettura dei dati.
Per generare lato server, dato l'oggetto Java, l'oggetto JSON corrispondente si utilizza la libreria
jabsorb-1.3.1.jar .
Tale libreria va posta dentro la directory lib del progetto web assieme anche alle seguenti altre librerie ( altrimenti con compila perchè sono jar utilizzati da questa libreria):
commons-logging-1.1.1.jar slf4j-jdk14-1.6.2.jar
jabsorb-1.3.1.jar slf4j-jdk14-1.6.2-sources.jar
jul-to-slf4j-1.6.2.jar slf4j-log4j12-1.6.2.jar
jul-to-slf4j-1.6.2-sources.jar slf4j-log4j12-1.6.2-sources.jar
slf4j-api-1.6.2.jar slf4j-migrator-1.6.2.jar
slf4j-api-1.6.2-sources.jar slf4j-nop-1.6.2.jar
slf4j-ext-1.6.2.jar slf4j-nop-1.6.2-sources.jar
slf4j-ext-1.6.2-sources.jar slf4j-simple-1.6.2.jar
slf4j-jcl-1.6.2.jar slf4j-simple-1.6.2-sources.jar
slf4j-jcl-1.6.2-sources.jar
Lato client invece si utilizzano le API native di Javascript in particolare la
JSON.parse (quindi gli esempi non funzionano con IE 7 e precedenti, per cui sarebbe necessario utilizzare la funzione eval di Javascript).
Ho trovato molto comodo lato js la lettura delle liste dati create in formato JSON lato server,il viceversa invece molto meno.
Nell'esempio dell'articolo citato si invitava infatti ad utilizzare JSON anche come input al metodo di inserimento, in questo caso ho trovato molto più semplice inviare al server direttamente i parametri e poi inserirli per creare l'articolo piuttosto che creare l'oggetto JSON.
Di seguito posto tutto il codice utilizzato.
L'entità dati trattata è l'oggetto Java Articolo così definito:
public class Articolo {
private String articolo;
private boolean pubblicato;
private boolean interessante;
private int [] data;
private Info info;
.... getter e setter
L'oggetto Info è definito invece così:
public class Info {
private String autore;
... getter e setter
}
Le operazioni da effettuare sull'entità sono definite dalla seguente interfaccia:
public interface ArticoloManager {
public List<Articolo> getAllArticles();
public Articolo getArticolo(String id);
public void insertArticolo(Articolo a);
}
L'implementazione dell'interfaccia è così definita (per semplicita si evita di andare su db e si caricano i dati direttamente in RAM):
public
class
ArticoloManagerMockImpl implements
ArticoloManager {
private
static
ArticoloManagerMockImpl istanza;
public
static
ArticoloManagerMockImpl getInstance(){
if(istanza==null)
{
istanza=new
ArticoloManagerMockImpl();
}
return
istanza;
}
private
void
caricaLista(){
l.add(generaArticolo("bianchi",
"1",
new
int[]{12,4,1978}));
l.add(generaArticolo("rossi",
"2",
new
int[]{12,4,1985}));
l.add(generaArticolo("verdi",
"3",
new
int[]{10,4,1978}));
l.add(generaArticolo("viola",
"4",
new
int[]{12,9,1978}));
l.add(generaArticolo("cutini",
"5",
new
int[]{31,4,1920}));
}
private
Articolo generaArticolo(String autore,String articolo,int[]
dataN){
Articolo a=new
Articolo();
Info a1=new
Info();
a1.setAutore(autore);
a.setArticolo(articolo);
a.setData(dataN);
a.setInteressante(true);
a.setPubblicato(true);
a.setInfo(a1);
return
a;
}
private
ArticoloManagerMockImpl(){
caricaLista();
}
private
List<Articolo> l=new
ArrayList<Articolo>();
@Override
public
List<Articolo> getAllArticles() {
//
TODO
Auto-generated method stub
return
l;
}
@Override
public
Articolo getArticolo(String id) {
Articolo
ret=null;
for(Articolo
a:l){
if(id.equals(a.getArticolo()))
{
ret=a;
break;
}
}
return
ret;
}
@Override
public
void
insertArticolo(Articolo a) {
l.add(a);
}
}
JSP
Lato Web ho una semplice JSP così definita:
<%@
page
language="java"
contentType="text/html;
charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE
html PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta
http-equiv="Content-Type"
content="text/html;
charset=UTF-8">
<script
type="text/javascript"
src="${pageContext.request.contextPath}/js/util.js"></script>
<title>Insert
title here</title>
</head>
<body>
<form
>
<table>
<tr><td>Articolo:
</td><td><input
type="text"
name="txtArticolo"
id="txtArticolo"/></td></tr>
<tr><td>Autore:
</td><td><input
type="text"
name="txtAutore"
id="txtAutore"/></td></tr>
<tr><td>Data:
</td><td><input
type="text"
name="txtData"
id="txtData"/></td></tr>
</table>
<input
type="button"
value="Visualizza
Tutti"
onclick="javascript:estraiTutti('${pageContext.request.contextPath}/Gestione')"/>
<input
type="button"
value="Inserisci"
onclick="javascript:insert('${pageContext.request.contextPath}/Gestione')"/>
<input
type="button"
value="Cerca
per Id Articolo"
onclick="javascript:getById('${pageContext.request.contextPath}/Gestione')"/>
</form>
<div
id="lista">
</div>
<div
id="inserimento"></div>
<div
id="dettaglio"></div>
</body>
</html>
I tre div lista inserimento e dettaglio servono a visualizzare o la lista risultati oppure il messaggio di inserimento ok oppure il dettaglio di una entità inserita (cerca per codice articolo).
Servlet
La servlet richiamata via Ajax è la seguente, Notare che alla fine ho utilizzato il metodo insertArticle invece di insertArticleJson suggerito dall'articolo di HTML.
public
class
Gestione extends
HttpServlet {
private
static
final
long
serialVersionUID
= 1L;
ArticoloManager
interfaccia;
JSONSerializer
serializer;
/**
*
@see
HttpServlet#HttpServlet()
*/
public
Gestione() {
super();
//
TODO
Auto-generated constructor stub
}
public
void
init()
{
serializer
= new
JSONSerializer();
interfaccia
= ArticoloManagerMockImpl.getInstance();
try
{
//
inizializza
i tipi
serializzatori
forniti
//
di
default con
la
libreria
serializer.registerDefaultSerializers();
}
catch
(Exception e)
{
e.printStackTrace();
}
}
/**
* @see
HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
response)
*/
protected
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
processRequest(request,
response);
}
private
void
processRequest(HttpServletRequest request, HttpServletResponse
response)
{
try
{
String op =
request.getParameter("op");
if
(op != null)
{
if
(op.equalsIgnoreCase("listAllArticles"))
listAllArticles(request, response);
else
if
(op.equalsIgnoreCase("listArticle"))
listArticle(request, response);
else
if
(op.equalsIgnoreCase("insert"))
insertArticle(request, response);
}
// op
è null
}
catch(Exception
ex){
}
}
private
void
listArticle(HttpServletRequest request, HttpServletResponse response)
throws
NumberFormatException, IOException, MarshallException
{
String articoloId =
request.getParameter("articolo");
//
Usa
la
logica
esistente
per recuperare
l'articolo
Articolo toRet =
interfaccia.getArticolo(articoloId);
List<Articolo> l=new
ArrayList<Articolo>();
l.add(toRet);
//
restituisce
l'articolo serializzato
in JSON tramite
//
l'oggetto serializer
response.getWriter().println(serializer.toJSON(l.toArray()));
}
private
void
listAllArticles(HttpServletRequest request, HttpServletResponse
response)
throws
NumberFormatException, IOException, MarshallException
{
//
Recupera
gli
articoli
con
la
logica
esistente
List<Articolo> toRet =
interfaccia.getAllArticles();
//
returns a JSON
response.getWriter().println(serializer.toJSON(toRet.toArray()));
}
private
String streamToString(InputStream in) throws
IOException
{
StringBuffer out = new
StringBuffer();
byte[]
b = new
byte[4096];
for
(int
n; (n = in.read(b)) != -1;) {
out.append(new
String(b, 0, n));
}
return
out.toString();
}
/*
*
Restituisce un Articolo in formato JSON
*
*
Parametri attesi: op, operazione
*/
private
void
insertArticleJson(HttpServletRequest
request, HttpServletResponse response)
throws
NumberFormatException, IOException, MarshallException,
UnmarshallException
{
//
riceve
il
messaggio
JSON da
POST
String json =
streamToString(request.getInputStream());
//
lo
de-serializza
Articolo newArticle = (Articolo)
serializer.fromJSON(json);
//
inserisce
l'articolo ricevuto
nel
DB
interfaccia.insertArticolo(newArticle);
response.getWriter().println("Ok
inserito");
}
private
void
insertArticle(HttpServletRequest request, HttpServletResponse
response)
throws
NumberFormatException, IOException, MarshallException,
UnmarshallException
{
String
articolo=request.getParameter("articolo");
String
autore=request.getParameter("autore");
String
data=request.getParameter("txtData");
String[] dati=data.split("/");
int
anno=Integer.valueOf(dati[2]);
int
mese=Integer.valueOf(dati[1]);
int
giorno=Integer.valueOf(dati[0]);
int[]
arrData=new
int[3];
arrData[0]=giorno;
arrData[1]=mese;
arrData[2]=anno;
Articolo art=new
Articolo();
Info i=new
Info();
i.setAutore(autore);
art.setArticolo(articolo);
art.setInfo(i);
art.setData(arrData);
art.setInteressante(true);
art.setPubblicato(true);
interfaccia.insertArticolo(art);
response.getWriter().println("Ok
inserito");
}
/**
* @see
HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
response)
*/
protected
void
doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException {
processRequest(request,
response);
}
}
JAVASCRIPT
function
getXMLHttpRequest() {
try
{
return
new
XMLHttpRequest();
}
catch
(e) {
try
{
return
new
ActiveXObject('Microsoft.XMLHTTP');
}
catch
(e) {
try
{
return
new
ActiveXObject('MSXML2.XMLHTTP.3.0');
}
catch(e)
{alert('errore');}
}
}
return
null;
}
function
getJsonResult(risultato)
{
var
result="";
var
i;
try
{
var
my_JSON_object
=
JSON.parse(risultato);
result="<table
border='1'><tr><td>Articolo</td><td>Autore</td><td>Data</td></tr>";
for(
i=0;i<my_JSON_object.length;i++){
result+="<tr>";
result+="<td>";
result+=my_JSON_object[i].articolo;
result+="</td>";
result+="<td>";
result+=my_JSON_object[i].info.autore;
result+="</td>";
result+="<td>";
result+=my_JSON_object[i].data;
result+="</td>";
result+="</tr>";
}
result+="</table>";
return
result;
}
catch(err){
alert(err);
}
}
function
insert(url){
var
xmlHttp=getXMLHttpRequest();
xmlHttp.onreadystatechange=function
(){
if(xmlHttp.readyState==4){
if(xmlHttp.status==200
||
xmlHttp.status==0){
var
risultatoTxt=xmlHttp.responseText;
var
dett=document.getElementById("dettaglio");
var
list=document.getElementById("lista");
var
ins=document.getElementById("inserimento");
dett.innerHTML="";
list.innerHTML="";
ins.innerHTML="";
ins.innerHTML=risultatoTxt;
}
else
{
alert('Comunicazione
fallita '+xmlHttp.status+"
Motivo: "+xmlHttp.statusText);
}
}
};
xmlHttp.open("POST",url,false);
xmlHttp.setRequestHeader("content-type",
"application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("connection",
"close");
var
txtArticolo=document.getElementById("txtArticolo").value;
var
txtAutore=document.getElementById("txtAutore").value;
var
txtData=document.getElementById("txtData").value;
xmlHttp.send("op=insert&articolo="+txtArticolo+"&autore="+txtAutore+"&txtData="+txtData);
}
function
getById(url){
var
xmlHttp=getXMLHttpRequest();
xmlHttp.onreadystatechange=function
(){
if(xmlHttp.readyState==4){
if(xmlHttp.status==200
||
xmlHttp.status==0){
var
risultatoTxt=xmlHttp.responseText;
var
dett=document.getElementById("dettaglio");
var
list=document.getElementById("lista");
var
ins=document.getElementById("inserimento");
dett.innerHTML="";
list.innerHTML="";
ins.innerHTML="";
dett.innerHTML=getJsonResult(risultatoTxt);
}
else
{
alert('Comunicazione
fallita '+xmlHttp.status+"
Motivo: "+xmlHttp.statusText);
}
}
};
xmlHttp.open("POST",url,false);
xmlHttp.setRequestHeader("content-type",
"application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("connection",
"close");
var
txtArticolo=document.getElementById("txtArticolo").value;
xmlHttp.send("op=listArticle&articolo="+txtArticolo);
}
function
estraiTutti(
url){
var
xmlHttp=getXMLHttpRequest();
xmlHttp.onreadystatechange=function
(){
if(xmlHttp.readyState==4){
if(xmlHttp.status==200
||
xmlHttp.status==0){
var
risultatoTxt=xmlHttp.responseText;
var
dett=document.getElementById("dettaglio");
var
list=document.getElementById("lista");
var
ins=document.getElementById("inserimento");
dett.innerHTML="";
list.innerHTML="";
ins.innerHTML="";
list.innerHTML="";
list.innerHTML=getJsonResult(risultatoTxt);
}
else
{
alert('Comunicazione
fallita '+xmlHttp.status+"
Motivo: "+xmlHttp.statusText);
}
}
};
xmlHttp.open("POST",url,false);
xmlHttp.setRequestHeader("content-type",
"application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("connection",
"close");
xmlHttp.send("op=listAllArticles");
}
Risultato finale