mercoledì 13 giugno 2012

Lista con checkbox paginata (display table 1.1)

Nel post precedente ho utilizzato la versione di display table 1.2, che ha un decorator apposito per  la gestione delle checkbox.
Sulla 1.1 (dove dovevo lavorare) non era però disponibile tale decorator e allora mi sono dovuto un pò arrangiare per avere la stessa funzionalità.
Praticamente nel decorator che crea il checkbox ho aggiunto un javascript che effettua una chiamata ajax all'onclick dell'utente, trasmettendo l'id dell'oggetto e specificando se è stato selezionato o deselezionato.
La servlet richiamata si occupa quindi di controaggiornare i dati della lista in sessione.
Quindi paginando avanti e indietro, dato che la display table si aggancia sempre alla lista dati in sessione, trovo i dati aggiornati.
Non è il massimo da un punto di vista di performance.

Di seguito il codice

DECORATOR (per creare il check sulla lista)

package it.decorator;
import it.servlet.Nazione;
import javax.servlet.jsp.PageContext;
import org.displaytag.decorator.TableDecorator;
import org.displaytag.model.TableModel;
public class MyDecorator extends TableDecorator {
   
     public void init(PageContext pageContext, Object decorated, TableModel tableModel)
        {
         super.init(pageContext, decorated, tableModel);

        }

       public String getNome(){
         
        Nazione nazione=(Nazione)getCurrentRowObject();
        return "<a href=\"dettaglio.jsp?nazione="+nazione.getNome()+"\">"+nazione.getNome()+"</a>";
    }
    public String getChecked(){
        StringBuffer sb=new StringBuffer();
        Nazione nazione=(Nazione)getCurrentRowObject();
        if(nazione.isCheched()){
        sb.append("<input type=\"checkbox\" name=\"idChk\" value=\""+nazione.getId()+" \" id=\""+nazione.getId()+"\" onclick=\"chiamaServlet('"+ nazione.getId() +"')\" checked />");
        //    sb.append("<input type=\"hidden\" name=\"idChkHid\"  value=\"++ />");
        }
        else
        {
            sb.append("<input type=\"checkbox\" name=\"idChk\" id=\""+nazione.getId()+"\" onclick=\"chiamaServlet('"+ nazione.getId() +"')\" value=\""+nazione.getId()+" \" />");
        }
        return sb.toString();
    }
 
}

SERVLET (richiamata via Ajax per aggiornare il check in sessione)

......

String id=request.getParameter("id");
boolean checked=request.getParameter("param").equals("1")?true:false;
List<Nazione> listaNazioni=(List<Nazione>)request.getSession().getAttribute("LISTA_DATI");
for(Nazione n:listaNazioni){
              if(String.valueOf(n.getId()).equals(id.trim())){
                n.setCheched(checked);
                break;
                 }
                  }
request.getSession().setAttribute("LISTA_DATI",listaNazioni);

.....

SERVLET (richiamata alla pressione del bottone per visionare quanto selezionato)


......

PrintWriter pw=response.getWriter();
List<Nazione> lista=(List<Nazione>)request.getSession().getAttribute("LISTA_DATI");
int i=0;
pw.println("<br>");
for(Nazione n:lista){
            if(n.isCheched()){
                if(i==0) {
                    pw.println("<b>ELEMENTI SELEZIONATI</b>");
                    pw.println("<br>");
                }
               
                pw.println(n.getNome());
                pw.println("<br>");
                i++;
            }
           
            }
pw.flush();

.....



JSP (con il js per le chiamate ajax)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<script>
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 stampaSelezionati(){
        var xmlHttp=getXMLHttpRequest();
        xmlHttp.onreadystatechange=function (){
            if(xmlHttp.readyState==4){
            if(xmlHttp.status==200 || xmlHttp.status==0){
             var risultatoTxt=xmlHttp.responseText;
         
             var elem=document.getElementById("divRisultati");
             elem.innerHTML="";
            
             elem.innerHTML=risultatoTxt;
            }
            else
            {
            alert('Comunicazione fallita '+xmlHttp.status+" Motivo: "+xmlHttp.statusText);
            }
            }
            };
            xmlHttp.open("POST","StampaSelezionate",true);
            xmlHttp.setRequestHeader("content-type", "application/x-www-form-urlencoded");
            xmlHttp.setRequestHeader("connection", "close");
            xmlHttp.send(null);
    }
function chiamaServlet( id){
    var xmlHttp=getXMLHttpRequest();
    var miaCheck=document.getElementById(id);
   
    var param=0;
    if(miaCheck.checked){
        param=1;
    }
    xmlHttp.onreadystatechange=function (){
    if(xmlHttp.readyState==4){
    if(!(xmlHttp.status==200 || xmlHttp.status==0)){
    alert('Comunicazione fallita '+xmlHttp.status+" Motivo: "+xmlHttp.statusText);
    }
    }
    };
    xmlHttp.open("POST","GetSelection",true);
    xmlHttp.setRequestHeader("content-type", "application/x-www-form-urlencoded");
    xmlHttp.setRequestHeader("connection", "close");
    xmlHttp.send("id="+document.getElementById(id).value+"&param="+param);
    }

</script>
<%@ taglib uri="http://displaytag.sf.net" prefix="display" %>
<!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">
<title>Insert title here</title>
</head>
 <!--  String numPag=request.getParameter("d-49653-p")==null?"1":request.getParameter("d-49653-p");
   session.setAttribute("numPag", numPag);
   requestURI="${pageContext.request.contextPath}/GetSelection"
 -->
 <jsp:include page="version.jsp"></jsp:include>
<body>
<form name="formTest" action="">
<display:table name="${LISTA_DATI}" class="dataTable"  decorator="it.decorator.MyDecorator" pagesize="5">
<display:column property="checked"></display:column>
<display:column property="nome"></display:column>
<display:column property="continente"></display:column>
<display:column property="abitanti"></display:column>
<display:column property="ranking"></display:column>
</display:table>
<input type="hidden" name="prova"  id="test" value="test"/>

<input type="button" name="btnInvio2" id="btnInvio2" value="Invio" onclick="stampaSelezionati()" >
<div id="divRisultati">

</div>
</form>
</body>
</html>


Lista con checkbox paginata (con decorator)

Utilizzando display table 1.2 è possibile utilizzare un apposito decorator, org.displaytag.decorator.CheckboxTableDecorator, per garantire una navigazione mantenendo le checkbox selezionate.
Il link con la documentazione (piuttosto scarna a dire il vero) è presente qui.
Praticamente ad ogni click sulla paginazione, oltre ai parametri necessari alla displaytable per la paginazione stessa, si aggiungono i parametri selezionati, quindi andando avanti e indietro non si perdono tali scelte.
L'oggetto della tabella deve avere poi una proprietà "id" che lo identifichi univocamente, e che sarà il valore poi passato in query string.
Ho avuto solo qualche problema  all'atto del post del form, infatti se quella pagina è l'ultima visitata allora i parametri impostati non sono ancora presenti in query string, e mi sono dovuto fare un metodo javascript che li recuperava dal form.
Di seguito posto il codice.

Per simulare il caricamento dati da db ho utilizzato una servlet che carica una lista di oggetti di tipo Nazione, con la proprietà id e quella checked.
Caricati i dati a mano, per fare in modo che all'ingresso in lista risultino già selezionate quelle nazioni con la proprietà checked=true, bisogna aggiungere in query string i parametri _chk  con le apposite id.

.....

request.getSession().setAttribute("LISTA_DATI", listaNazioni);
String parametersToAdd=getParametriDaAggiungere(listaNazioni);
request.getRequestDispatcher("listaNew.jsp"+parametersToAdd).forward(request, response);

....

Dove il metodo getParametriDaAggiungere fa l'append in queryString dei parametri

private String getParametriDaAggiungere(List<Nazione> lista){
        StringBuffer sb=new StringBuffer();
        sb.append("?");
        for(Nazione n: lista){
            if(n.isCheched()){
                sb.append("_chk=");
                sb.append(n.getId());
                sb.append("&");
            }
        }
        return sb.toString();
    }

 La jsp listaNew.jsp è definita così (in grassetto la definizione del decorator come specificato da fare sul sito di display table):

<%@ taglib uri="http://displaytag.sf.net" prefix="display" %>
<script>

function settaValore(val){
    var input = document.createElement("input");
    input.setAttribute("type", "hidden");
    input.setAttribute("name", "pageSelection");
   
    input.setAttribute("value", val);
    document.getElementById("container").appendChild(input);
}
function sendRequest(){
    var form1=document.getElementById("displ");
    var testo=form1["_chk"];
    var len = testo.length;

     for(var i=0;i<len;i++)
     {
         if(testo[i].checked){
             settaValore(testo[i].value);
         }
     }
     
     document.getElementById("container").submit();
}
</script>
<%
org.displaytag.decorator.CheckboxTableDecorator decorator = new org.displaytag.decorator.CheckboxTableDecorator();
  decorator.setId("id");
  decorator.setFieldName("_chk");
 
  pageContext.setAttribute("checkboxDecorator", decorator);

%>

<form name="displ" id="displ" action="?" method="get">
<display:table name="${LISTA_DATI}" class="dataTable"  decorator="checkboxDecorator" pagesize="5" form="displ" excludedParams="_chk">
<display:column property="checkbox"></display:column>
<display:column property="nome"></display:column>
<display:column property="continente"></display:column>
<display:column property="abitanti"></display:column>
<display:column property="ranking"></display:column>
</display:table>
<%
String[] val=request.getParameterValues("_chk");
request.getSession().setAttribute("selected", val); %>
</form>
<form name="container" id="container" action="<%=request.getContextPath() %>/ListaSelezionate">
<input type="button" name="btnInvio" id="btnInvio" value="Invio" onclick="sendRequest();">
</form>

La servlet di arrivo recupera dunque sia i dati in sessione (attributo selected) sia i dati nella request corrente (attributo pageSelection) e ricostruisce da queste informazioni i dati selezionati:

private void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HashSet<String> hset=new LinkedHashSet<String>();
        String[] parametri=request.getParameterValues("pageSelection");
        String[] parInSessione=(String[])request.getSession().getAttribute("selected");
        PrintWriter pw=response.getWriter();
        pw.println("<html>");
        //pw.println("Parametri in request");
        if(parametri!=null){
        for(String s:parametri){
            //pw.println(s);
            hset.add(s);
        }
        }
       
       
        if(parInSessione!=null){
        for(String s:parInSessione){
            hset.add(s);
        }
        }
       
        List<Nazione> lista=(List<Nazione>)request.getSession().getAttribute("LISTA_DATI");
        List<Nazione> selezionati=new LinkedList<Nazione>();
        for(Nazione n: lista){
            Iterator it=hset.iterator();
            while(it.hasNext()){
                String cc=(String)it.next();
                if(cc.equals(String.valueOf(n.getId()))){
                    selezionati.add(n);
                    continue;
                }
            }
        }
        pw.println("<b>Nazioni selezionate</b>: <br>");
        for(Nazione n:selezionati){
        pw.println(n.getNome());
        pw.println("<br>");
        }
       
        pw.println("</html>");
    }


lunedì 11 giugno 2012

Visionare log ODBC

Per vedere i log delle quey effettivamente trasmesse al db, se si utilizza ODBC per la connessione, occorre fare così.

1) Da Pannello di Controllo scegliere"Strumenti di amministrazione" e quindi "Origine Dati ODBC";
2) Andare nel pannello "Analisi"

Apparirà una schermata di questo tipo:

3) Premere il tasto "Analisi", comparirà una schermata di questo tipo:

Quindi conviene svuotare il file indicato in "Percorso file registro" , che si chiama SQL.log.
4) Premere il tasto "Avvia Analisi";

A questo punto saranno loggate tutte le query inviate in base dati, la sintassi è piuttosto verbosa e dopo aver effettuato le operazioni interessate conviene premere il tasto "interrompi analisi" e quindi visionare i log.

lunedì 4 giugno 2012

Clausola over partition by con Sql Server

E' una utile funzionalità che in DBMS come Sql Server consente di effettuare sotto aggregazioni specifiche di colonna e consente di risparmiare lunghe e complesse join.


Sintassi da usare nella select

[FUNZIONE(ad esempio di aggregazione)] OVER (partition by [nome_campo] order by ..) as 'Nome logico'

Esempi utili si trovano sul sito Microsoft (qui )