domenica 16 ottobre 2011

Java Ajax e JSON

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:
  • Codice HTML;
  • XML;
  • JSON.
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.ja
r
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')"/>
&nbsp;&nbsp;&nbsp;
<input type="button" value="Inserisci" onclick="javascript:insert('${pageContext.request.contextPath}/Gestione')"/>
&nbsp;&nbsp;&nbsp;
<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




 

Nessun commento:

Posta un commento