Visualizzazione post con etichetta java librerie. Mostra tutti i post
Visualizzazione post con etichetta java librerie. Mostra tutti i post

giovedì 7 marzo 2013

Apache POI impostare pagina orizzontale

Con queste semplici istruzioni su apache po 3.9 è possibile impostare il foglio in modo che sia tutto presente su una pagina e impostato orizzontale .
La proprietà per l'impostazione pagina orizzontale è la setLandScape(true) sull'interfaccia org.apache.poi.ss.usermodel.PrintSetup

Esempio:


HSSFSheet sheet = wb.createSheet(nome);
sheet.setAutobreaks(true);
PrintSetup ps = sheet.getPrintSetup();
ps.setLandscape(true);
ps.setFitHeight((short)1);
ps.setFitWidth((short)1);


giovedì 31 gennaio 2013

Taglib combo date

Ho avuto la necessità di realizzare una combo che date in input 2 date in formato gg/mm/aaaa (data inizio e data fine) mostrasse i dati nel formato MESE-AAAA (es. gennaio-2010...)ordinato dall'inizio alla fine e come valore AAAAMM concatenato.
La taglib è definita così (file tld)

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE taglib
  PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
  "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
  <taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>1.2</jsp-version>
  <short-name>c</short-name>
  <uri>http://gbresci.com</uri>
  <display-name>combo helper</display-name>
  <description>combo helper core library</description>
  <tag>
  <name>combo</name>
  <tag-class>it.gbresci.taglib.ComboDate</tag-class>
  <body-content>empty</body-content>
  <description>Gestione Combo</description>
  <attribute>
  <name>dataDa</name>
  <required>true</required>
  <rtexprvalue>true</rtexprvalue>
  </attribute>
   <attribute>
  <name>dataA</name>
  <required>true</required>
  <rtexprvalue>true</rtexprvalue>
  </attribute>
  <attribute>
  <name>primoVuoto</name>
  <required>false</required>
  <rtexprvalue>true</rtexprvalue>
  </attribute>
  <attribute>
  <name>id</name>
  <required>true</required>
  <rtexprvalue>true</rtexprvalue>
  </attribute>
  </tag>
  </taglib>



Il codice del Tag, che eredita da SimpleTagSupport, è il seguente:

package it.gbresci.taglib;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;

import java.io.IOException;
import java.util.*;

public class ComboDate extends SimpleTagSupport {
	private String id="";
	private String dataDa="";
	private String dataA="";
	private boolean primoVuoto=false;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public boolean isPrimoVuoto() {
		return primoVuoto;
	}
	public void setPrimoVuoto(boolean primoVuoto) {
		this.primoVuoto = primoVuoto;
	}
	
	public String getDataDa() {
		return dataDa;
	}
	public void setDataDa(String dataDa) {
		this.dataDa = dataDa;
	}
	public String getDataA() {
		return dataA;
	}
	public void setDataA(String dataA) {
		this.dataA = dataA;
	}
	private boolean validate()
	{
		boolean retVal=true;
		if(this.dataDa!= null && this.dataDa.length()==10 
			&& this.dataA!=null && this.dataA.length()==10){
			try
			{
				Date data1=getDateFromString(dataDa);
				Date data2=getDateFromString(dataA);
				if(data2.getTime()<data1.getTime()){
					retVal=false;
				}
				
			}
			catch(Exception ex){
				//log
				retVal=false;
			}
		}
		return retVal;
	}
	public void doTag() throws JspException {

		PageContext pageContext = (PageContext) getJspContext();
		JspWriter out = pageContext.getOut();
		StringBuffer sb = new StringBuffer();
        if(validate()){
		try {
			
			sb.append("<select id=\"");
			sb.append(this.id);
			sb.append("\" name=\"");
			sb.append(this.id);
			sb.append("\"");
			sb.append(">");
			if(primoVuoto){
				sb.append("<option value=\"\"> </option>");
			}
			Map<String,String> myMap=getMappaValori();
			Set<String> chiavi=myMap.keySet();
			for(String s:chiavi){
				sb.append("<option value=\"");
				sb.append(s);
				sb.append("\">");
				sb.append(myMap.get(s));
				sb.append("</option>");
				
			}
			sb.append("</select>");
			out.println(sb.toString());

		} catch (Exception e) {
			e.printStackTrace();
		}
        }
        else
        {
        	try {
				out.println("<h1><b>Attenzione errore nel popolamanto controllo, controllare gli estremi delle date!!</b></h1>");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }

	}
	private Map<String,String> getMappaValori(){
		Map<String,String> myMap=new LinkedHashMap<String, String>();
		Date dataDatag=getDateFromString(dataDa);
		Date dataAtag=getDateFromString(dataA);
		Date dataTempTag=dataDatag;
		do
		{
			myMap.put(getChiaveFromDate(dataTempTag), getValoreFromDate(dataTempTag));
			Calendar c=Calendar.getInstance();
			c.setTime(dataTempTag);
			c.add(Calendar.MONTH, 1);
			dataTempTag=c.getTime();
		}
		while(dataTempTag.getTime()<dataAtag.getTime());
		return myMap;
	}
	private Date getDateFromString(String d){
		Calendar c=Calendar.getInstance();
		String giorno=d.substring(0, 2);
		String mese=d.substring(3, 5);
		String anno=d.substring(6);
		c.set(Calendar.DAY_OF_MONTH,Integer.parseInt(giorno));
		c.set(Calendar.MONTH, Integer.parseInt(mese)-1);
		c.set(Calendar.YEAR, Integer.parseInt(anno));
		return c.getTime();
	}
	private String getChiaveFromDate(Date d){
		Calendar c=Calendar.getInstance();
		c.setTime(d);
		int anno=c.get(Calendar.YEAR);
		int mese=c.get(Calendar.MONTH)+1;
		StringBuffer sb=new StringBuffer();
		sb.append(anno);
		String mes=String.valueOf(mese);
		if(mes.length()==1){
			sb.append("0");
		}
		sb.append(mes);
		return sb.toString();
	}
	private String getValoreFromDate(Date d){
		Calendar c=Calendar.getInstance();
		c.setTime(d);
		int anno=c.get(Calendar.YEAR);
		int mese=c.get(Calendar.MONTH);
		StringBuffer sb=new StringBuffer();
		switch(mese){
		case 0:
			sb.append("GENNAIO-");
			break;
		case 1:
			sb.append("FEBBRAIO-");
			break;
		case 2:
			sb.append("MARZO-");
			break;
		case 3:
			sb.append("APRILE-");
			break;
		case 4:
			sb.append("MAGGIO-");
			break;
		case 5:
			sb.append("GIUGNO-");
			break;
		case 6:
			sb.append("LUGLIO-");
			break;
		case 7:
			sb.append("AGOSTO-");
			break;
		case 8:
			sb.append("SETTEMBRE-");
			break;
		case 9:
			sb.append("OTTOBRE-");
			break;
		case 10:
			sb.append("NOVEMBRE-");
			break;
		case 11:
			sb.append("DICEMBRE-");
			break;
		
			
		}
		sb.append(anno);
		return sb.toString();
	}

}



Sulla jsp avremo infine l'importazione e definizione della taglib:

<%@ taglib prefix="x" uri="http://gbresci.com" %>
......
Data Test: <x:combo dataA="31/12/2012" dataDa="01/01/2009" id="qwerty"/> 

Si ricorda che :
  • Il file .tld deve essere salvato dentro la directory WEB-INF;
  • Il campo URI definito nel tld deve essere uguale a quello definito sulla jsp e NON è necessario che punti ad una vera url, si tratta soltanto di un nome logico;
  • Settando nella taglib il valore RTEXPRVALUE a true si rende possibile inserire all'interno del campo sulla jsp anche del codice java che interpeti il valore a runtime.

martedì 22 gennaio 2013

Display Table, decorator per singola colonna

Con Display Table è possibile creare una classe che faccia da decoratore a tutti i dati della collection rappresentata a video, ma in molti casi questa operazione risulta ripetitiva.
Un caso tipico è quello della formattazione di date, valute etc. che ci arrivano in formati diversi dal db.
In tali casi è possibile utilizzare dei decoratori sulle singole colonne, quindi si definisce una classe per la formattazione e in tutte le colonne in cui se ne ha bisogno si aggancia il decoratore.
Tale decoratore implementa l'interfaccia DisplaytagColumnDecorator, che dalla versione 1.1 sostituisce la precedente ColumnDecorator, ora deprecata.
Vediamo un esempio, ottenuto con la libreria display-tag-1.2.

La classe decoratore è definita così:


import javax.servlet.jsp.PageContext;
import org.displaytag.decorator.DisplaytagColumnDecorator;
import org.displaytag.exception.DecoratorException;
import org.displaytag.properties.MediaTypeEnum;
public class DateColumnDecorator implements DisplaytagColumnDecorator {
public Object decorate(Object colonna, PageContext arg1, MediaTypeEnum arg2)
   throws DecoratorException {
   StringBuffer sb=new StringBuffer();
   String data=(String)colonna;
   if(data !=null && data.length()==8){
   String anno=data.substring(0,4);
   String mese=data.substring(4, 6);
   String giorno=data.substring(6,8);
   sb.append(giorno);
   sb.append("/");
   sb.append(mese);
   sb.append("/");
   sb.append(anno);
   }
   else
   {
    sb.append(data);
   }
  return sb.toString();
 }
}


Lo scopo è quello di formattare date che arrivano nel formato AAAAMMGG in GG/MM/AAAA.

Il frammento di display table in cui si richiama il decoratore è il seguente:


<display:column property="dt_reg" title="Data Immissione Verifica"  decorator="org.gianos.form.decorator.DateColumnDecorator"  sortable="true"/>


mercoledì 12 dicembre 2012

Itext per generare tabella rtf

In questo esempio vediamo come generare un RTF con IText in cui posizioniamo una tabella generata dinamicamente, passando al metodo di creazione :
  • un array di Stringhe che rappresentano gli header di colonne;
  • una lista di Stringhe che rappresentano i valori , e che devono essere un multiplo della size dell'array di header, esempio con 4 colonne di intestazione per avere 2 righe la size di questa lista deve essere di 8.
Il vantaggio di avere questa tabella è che Itext (a differenza di Jasper Report o meglio del Jasper report che ho usato io qualche anno fa, non so le ultime versioni) genera tabelle facilmente modificabili, mentre Jasper mette dei place holders tipo caselle di testo che rendono molto difficoltoso modificare il file.

Sotto posto il codice:

package chart.example;
import java.awt.Color;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import com.lowagie.text.Cell;
import com.lowagie.text.Document;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Table;
import com.lowagie.text.rtf.RtfWriter2;

public class TableCreator {
 
 public static void main(String[] args) throws Exception
 {
  FileOutputStream fos = new FileOutputStream("file/executive_summary.rtf");
  Document d=new Document();
  RtfWriter2.getInstance(d, fos );
     d.open();
     String[] lista=new String[]{"Lunedi","Martedi","Mercoledi","Giovedi"};
     List<String> valTot=new ArrayList<String>();
     valTot.add("12");
     valTot.add("15");
     valTot.add("16");
     valTot.add("98");
     valTot.add("12");
     valTot.add("15");
     valTot.add("16");
     valTot.add("98");
     valTot.add("dsfddsdsf");
     valTot.add("baiaffa");
     valTot.add("16");
     valTot.add("98");
     valTot.add("ssssss");
     valTot.add("baiaffone");
     valTot.add("13");
     valTot.add("983");
     valTot.add("dsdsdsdsds");
     valTot.add("baiaffone");
     valTot.add("13");
     valTot.add("983");
     d.add(getSimpleTable(lista, valTot));
     d.close();
    
 }
 
 public static int myFontStyle = Font.UNDEFINED;
 public static Font baseFont = new Font ( myFontStyle, 12, Font.NORMAL );
 public static Font baseFontTabelleHeader=new Font ( myFontStyle, 10, Font.NORMAL );
 public static Table getSimpleTable( String[] header_cells, List<String> column_cells ) throws Exception
 {
  Table table = new Table( header_cells.length );
        if(column_cells.size()%header_cells.length!=0){
        throw new IllegalArgumentException("Attenzione il numero di valori " +
           "deve essere un multiplo del numero di colonne, " +
           "quindi di "+header_cells.length+" " +
             "il valore risulta invece "+column_cells.size());
        }
  table.setBorderWidth(1);
  table.setPadding(2);
        table.setSpacing(0);

        for ( int i = 0 ; i < header_cells.length ; i++ )
        {
         table.addCell( getHeaderCell( header_cells[i], baseFontTabelleHeader ) );
        }
       
        for ( int i = 0 ; i < column_cells.size() ;  )
        {
         for(int k=0;k<header_cells.length;k++){
          table.addCell( getCell( column_cells.get(i), baseFont ) );
          i++;
         }
        }

  return table;
 }

 public static Cell getHeaderCell( String text, Font font ) throws Exception
 {
  Font f = new Font( font );
  f.setStyle(Font.BOLD);
  Cell cell = new Cell( new Paragraph( text, f ) );
        cell.setHeader(true);
        cell.setBackgroundColor( new Color(0xE1E1E1) );
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        return cell;
 }

 public static Cell getCell( String text, Font font ) throws Exception
 {
  Cell cell = new Cell( new Paragraph( text, font ) );
  cell.setHeader(false);
        cell.setHorizontalAlignment(Element.ALIGN_LEFT);
        return cell;
 }

 public static Cell getCenteredCell( String text, Font font ) throws Exception
 {
  Cell cell = new Cell( new Paragraph( text, font ) );
  cell.setHeader(false);
        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
        return cell;
 }
}



sabato 8 dicembre 2012

JFreeChart, esempi realizzazione grafici

In questo posto vediamo come generare 4 tipologie di grafici con JFreeChart, in particolare:

  • Tachimetro (grafico a lancetta);
  • Torta;
  • Istogramma semplice;
  • Istogramma multiplo.
Ho creato un semplice Java Project includendo le seguenti librerie nel classpath:

  • jfreechart-1.0.9.jar;
  • jcommon-1.0.12.jar;
  • iText-2.0.8.jar.
Di seguito incollo la classe main principale, con dei metodi statici che generano delle immagini png per ciascun tipo grafico definito:


package chart.example;
import java.awt.BasicStroke;
import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DialShape;
import org.jfree.chart.plot.MeterInterval;
import org.jfree.chart.plot.MeterPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.Range;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.DefaultValueDataset;
import org.jfree.ui.TextAnchor;
import com.lowagie.text.Font;
public class ChartCreator {
 public static int myFontStyle = Font.UNDEFINED;
 public static Font baseFont = new Font ( myFontStyle, 12, Font.NORMAL );
 public static void main(String[] args) throws Exception {
   creaGraficoATorta();
        creaIstogrammaMultiplo();
        creaTachimetro();
        creaIstogrammaSemplice();
 }
 private static void creaGraficoATorta() throws Exception{
  OutputStream fos=new FileOutputStream(new File("out/torta.png"));
  String[] componenti=new String[]{"Inter","Milan","Rubentus"};
  double[] valori=new double[]{18.0,18.0,28.0};
  JFreeChart chart=creaGraficoATorta(componenti, valori, false);
  ChartUtilities.writeChartAsPNG(fos, chart, 500, 300);
 }
 private static void creaIstogrammaMultiplo() throws Exception{
  OutputStream fos=new FileOutputStream(new File("out/istoMul.png"));
  double[] valori=new double[9];
  valori[0]=20.0;
  valori[1]=65.0;
  valori[2]=15.0;
  valori[3]=30.0;
  valori[4]=50.0;
  valori[5]=20.0;
  valori[6]=25.0;
  valori[7]=60.0;
  valori[8]=15.0;
  String[] componenti=new String[3];
  componenti[0]="Lazio";
  componenti[1]="Lombardia";
  componenti[2]="Toscana";
  String[] sottocomponenti=new String[3];
  sottocomponenti[0]="Ricchi";
  sottocomponenti[1]="Classe Media";
  sottocomponenti[2]="Poveri";
  JFreeChart chart=creaIstogramma(componenti,sottocomponenti, valori, "Ripartizione classi sociali", "Regioni", "Percentuali");
   ChartUtilities.writeChartAsPNG(fos, chart, 500, 300);
 }
 
 private static void creaIstogrammaSemplice() throws Exception
 {
  OutputStream fos=new FileOutputStream(new File("out/isto.png"));
  String[] componenti=new String[]{"Alto","Medio","Basso"};
  double[] valori=new double[]{85.5,75.12,45.56};
  JFreeChart chart=creaIstogramma(componenti, valori, "Andamenti", "", "");
  ChartUtilities.writeChartAsPNG(fos, chart, 500, 300);
 }
 private static void creaTachimetro() throws Exception{
  OutputStream fos=new FileOutputStream(new File("out/tachimetro.png"));
  BigDecimal a=new BigDecimal(37.0);
  BigDecimal b=new BigDecimal(49.0);
  BigDecimal res=a.divide(b,2,RoundingMode.HALF_UP);
  double v=res.doubleValue()*(double)100;
  JFreeChart chart=creaTachimetro(new Double(v), "Esempio", "", Color.WHITE);
  ChartUtilities.writeChartAsPNG(fos, chart, 500, 300);
 }

 public static JFreeChart creaTachimetro(Double valore, String titolo, String sottotitolo, Color bgcolor)
 {
  DefaultValueDataset ds = new DefaultValueDataset();
  ds.setValue(valore);
  MeterPlot plot = new MeterPlot(ds);
  plot.setUnits("%");
  plot.setRange(new Range(0, 100));
  plot.setMeterAngle(210);
  plot.addInterval(new MeterInterval("Intervallo1", new Range(90.0, 100.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 0, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo2", new Range(80.0, 90.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 51, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo3", new Range(70.0, 80.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 102, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo4", new Range(60.0, 70.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 153, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo5", new Range(50.0, 60.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 204, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo6", new Range(40.0, 50.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(255, 255, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo7", new Range(30.0, 40.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(192, 255, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo8", new Range(20.0, 30.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(128, 255, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo9", new Range(10.0, 20.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(64, 255, 0, 200)));
  plot.addInterval(new MeterInterval("Intervallo10", new Range(0.0, 10.0), Color.LIGHT_GRAY, new BasicStroke(1.0f), new Color(0, 255, 0, 200)));
  plot.setBackgroundPaint(bgcolor);
  plot.setNeedlePaint(Color.BLACK);
  plot.setDialBackgroundPaint(bgcolor);
  plot.setDialOutlinePaint(bgcolor);
  plot.setDialShape(DialShape.CIRCLE);
  plot.setTickLabelsVisible(false);
  plot.setTickSize(100.0);
  plot.setTickPaint(Color.GRAY);
  plot.setValueFont(new java.awt.Font("Dialog", Font.BOLD, 14));
  plot.setValuePaint(Color.BLACK);
  JFreeChart chart = new JFreeChart(null, null, plot, false);
  chart.setBackgroundPaint(bgcolor);
  if (!titolo.equals("")) {
   TextTitle title = new TextTitle(titolo);
   title.setFont(new java.awt.Font("Verdana", Font.BOLD, 12));
   title.setPaint(new Color(0x2684B3));
   chart.setTitle(title);
  }
  if (!sottotitolo.equals("")) {
   TextTitle subtitle = new TextTitle(sottotitolo);
   subtitle.setFont(new java.awt.Font("Verdana", java.awt.Font.ITALIC, 11));
   subtitle.setPaint(new Color(0x2684B3));
   chart.addSubtitle(subtitle);
  }
  return chart;
 }
 public static JFreeChart creaIstogramma(String[] componenti,String[] sottocomponenti,double[] valori,String titolo,String ascissa,String ordinata){
  DefaultCategoryDataset cds=new DefaultCategoryDataset();
  int j=0;
  int cambioComponente=sottocomponenti.length;
  String comp=componenti[j];
  int sottoComp=0;
        for(int i=0;i 1) {
   for (int i = 0; i < componenti.length; i++) {
    renderer.setSeriesItemLabelsVisible(i, true);
    renderer.setSeriesItemLabelGenerator(i, new SeriesLabelGenerator());
   }
  } else {
   renderer.setSeriesItemLabelsVisible(0, true);
   renderer.setSeriesItemLabelGenerator(0, new LabelGenerator(null));
  }
      return chart;
 }
 public static JFreeChart creaIstogramma(String[] componenti,double[] valori,String titolo,String ascissa,String ordinata){
  DefaultCategoryDataset cds=new DefaultCategoryDataset();
        for(int i=0;i

Nel codice sono utilizzate due classi (LabelGenerator e SeriesLabelGenerator) che servono a mostrare nei grafici a torta e a istogramma semplice (LabelGenerator) e nel grafico a istogramma multiplo (SeriesLabelGenerator) i valori con le percentuali.

LabelGenerator


package chart.example;
import java.text.NumberFormat;
import org.jfree.chart.labels.AbstractCategoryItemLabelGenerator;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.data.category.CategoryDataset;
public class LabelGenerator extends AbstractCategoryItemLabelGenerator implements CategoryItemLabelGenerator {

 private static final long serialVersionUID = 7389531138610633787L;
 private Integer category;
 private NumberFormat formatter = NumberFormat.getPercentInstance();
 public LabelGenerator(int category) {
  this(new Integer(category));
 }
 public LabelGenerator(Integer category) {
  super("", NumberFormat.getInstance());
 this.category = category;
 }
 public String generateLabel(CategoryDataset dataset, int series, int category ) {
  String result = null;
  double base = 0.0;
  if (this.category != null) {
   final Number b = dataset.getValue(series, this.category.intValue());
   base = b.doubleValue();
  }
  else {
   base = calculateSeriesTotal(dataset, series);
  }
  Number value = dataset.getValue(series, category);
  if (value != null) {
   final double v = value.doubleValue();
   //  you could apply some formatting here
   result = "     "+ value.toString() + " (" + this.formatter.format(v / base) + ")";
  }
  return result;
 }
 private double calculateSeriesTotal(CategoryDataset dataset, int series) {
  double result = 0.0;
  for (int i = 0; i < dataset.getColumnCount(); i++) {
   Number value = dataset.getValue(series, i);
   if (value != null) {
    result = result + value.doubleValue();
    }
  }
  return result;
 }
}



SeriesLabelGenerator



package chart.example;
import java.text.NumberFormat;
import org.jfree.chart.labels.AbstractCategoryItemLabelGenerator;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.data.category.CategoryDataset;
public class SeriesLabelGenerator extends AbstractCategoryItemLabelGenerator implements CategoryItemLabelGenerator {
 private static final long serialVersionUID = 7389531138610633787L;
 private NumberFormat formatter = NumberFormat.getPercentInstance();
 public SeriesLabelGenerator() {
  super("", NumberFormat.getInstance());
 }
 public String generateLabel(CategoryDataset dataset, int series, int category ) {
  String result = null;
  double base = 0.0;
  base = calculateCategoryTotal(dataset, category);
  Number value = dataset.getValue(series, category);
  if (value != null) {
   final double v = value.doubleValue();
   result = "     "+ value.toString() + " (" + this.formatter.format(v / base) + ")";
  }
  return result;
 }
 private double calculateCategoryTotal(CategoryDataset dataset, int category) {
  double result = 0.0;
  for (int i = 0; i < dataset.getRowCount(); i++) {
   Number value = dataset.getValue(i,category);
   if (value != null) {
    result = result + value.doubleValue();
    }
  }
  return result;
 }
}



Il risultato del codice è la generazione delle seguenti immagini:

Torta





Istogramma semplice


Istogramma multiplo


Grafico a lancetta




venerdì 30 novembre 2012

Display tag decorator export e autosize colonne excel

Visualizzando una lista avevo 2 necessità:

  1. Decodificare dei valori in visualizzazione (es. a fronte di alcuni codici dare la relativa descrizione);
  2. Esportare questi valori in excel in modo da avere le colonne excel già adattate alla descrizione, senza doverlo fare a mano.
Per il punto 1 sono ricorso ad un decorator, solo che nell'export excel ancora avevo il campo codice invece della descrizione.
Infatti nella tabella bisogna specificare questo:

<display:setproperty name="decorator.media.excel" value="org.decorator.MyDecorator">



In modo da forzare ad utilizzare il decorator anche nell'export, quindi non basta definirlo soltanto a livello di tabella con l'attributo decorator.

Per quanto riguarda invece il punto 2 nel file displaytable.properties occorre dichiarare la seguente proprietà:



export.excel.class=org.displaytag.export.excel.ExcelHssfView

In questo modo tale modifica vale per tutte le tabelle dell'applicazione.
Per fare questa modifica premetto che occorre avere la versione 1.2 della libreria assieme al displaytag-export-poi-1.2.jar.
Nel mio caso poi, avendo l'applicazione la libreria POI-3.5 a Runtime avevo un errore di questo tipo:


java.lang.NoSuchMethodError: org.apache.poi.hssf.usermodel.HSSFRow.createCell(I)Lorg/apache/poi/hssf/usermodel

Evidentemente serviva una versione più recente della libreria ma essendo questa utilizzata in altri modi nell'applicazione ho deciso di ridefinirmi l'exporter nel file displaytag.properties facendolo puntare ad una mia classe.
Quindi ho decompilato la classe ExcelHssfView (che si trova dentro displaytag-export-poi-1.2.jar) e corretto manualmente gli errori trovati.
In particolare nel metodo doExport ho dovuto fare questa modifica:


                HSSFCellStyle headerStyle = wb.createCellStyle();
         headerStyle.setFillPattern((short)2);
         headerStyle.setFillBackgroundColor((short)54);
         HSSFFont bold = wb.createFont();
         bold.setBoldweight((short)700);
         bold.setColor((short)9);
         headerStyle.setFont(bold);

Inserendo il cast a short per i valori numerici.
Mentre invece nel costruttore della classe statica  ExcelGenerationException ho dovuto commentare il costruttore:


super(Messages.getString("ExcelView.errorexporting"), cause);

In quanto non definito nella libreria displaytag-1.2.jar (!?...) sostituendolo con

super(ExcelGenerationException.class,Messages.getString("ExcelView.errorexporting"));

Adesso tutto funziona come volevo.

mercoledì 21 novembre 2012

Java ottenere MimeType da bytes[]

Esiste una comoda libreria che consente , dato l'array di byte, di determinare il mime type del file.
La libreria si chiama jmimemagic-0.1.0.jar ( si può scaricare qui ).
Richiede come dipendenza i 2 seguenti jar:
  • commons-logging.jar;
  • jakarta-oro.jar.
Vediamo un esempio su un progetto Java, in cui ho incluso nel classpath i 3 jar.


Magic m=new Magic();
byte[] lb=FileUtil.load(new File("file/WS.png"));
MagicMatch match = m.getMagicMatch(lb);
System.out.println(match.getMimeType());

L'array di byte dal file è stato ottenuto  con il seguente metodo statico di una classe denominata FileUtil di cui incollo il codice:

import java.io.*;
public class FileUtil {

  public final static byte[] load(String fileName)
   {
     try { 
       FileInputStream fin=new FileInputStream(fileName);
       return load(fin);
     }
     catch (Exception e) {
  
       return new byte[0];
     }
   }

   public final static byte[] load(File file)
   {
     try { 
       FileInputStream fin=new FileInputStream(file);
       return load(fin);
     }
     catch (Exception e) {
      
       return new byte[0];
     }
   }

   public final static byte[] load(FileInputStream fin)
   {
     byte readBuf[] = new byte[512*1024];
   
     try { 
       ByteArrayOutputStream bout = new ByteArrayOutputStream();
     
       int readCnt = fin.read(readBuf);
       while (0 < readCnt) {
         bout.write(readBuf, 0, readCnt);
         readCnt = fin.read(readBuf);
       }
       
       fin.close();
       
       return bout.toByteArray();
     }
     catch (Exception e) {
      
       return new byte[0];
     }
   }
}


martedì 28 agosto 2012

Offuscare codice Java con PROGUARD

Utilizzando PROGUARD è possibile effettuare un efficace offuscamento del codice e anche comprimere nel caso sia necessario ottimizzare spazio.
Si utilizza da riga di comando.
Per usarlo ho per prima cosa scritto un progetto di prova, un semplice java project che effettua una criptazione utilizzando l'algoritmo AES con chiave a 16 bit.

Testato il programma ho creato il jar.
Quindi ho esportato il jar dentro la cartella lib di PROGUARD.
Ho inserito sempre qui sotto la lib di PROGUARD anche il jar commons-codec-1.3.jar che è utilizzato dal mio codice.
Quindi ho creato (sempre sotto la lib) un file denominato parametri.pro così definito

-injars  cipher.jar
-outjars cipher_obs.jar

-libraryjars C:\Programmi\Java\jdk1.6.0_29\jre\lib\rt.jar;C:\Programmi\Java\jdk1.6.0_29\jre\lib\jce.jar;commons-codec-1.3.jar

-keep public class it.oasi.cipher.Cypher {
    public static void main(java.lang.String[]);
}




injars e outjars rappresentano rispettivamente il jar da offuscare e il jar prodotto dall'offuscamento

libraryjars indica tutte le librerie (comprese quelle generali della jdk come si può vedere) utilizzate dal jar. Si noti che ho onserito anche il jce.jar per avere il supporto della classe javax.crypto.Cipher

keep serve a mantenere l'entry point del codice (in questo caso il codice main)

Per generare il jar offuscato posizionarsi via shell sulla directory lib e digitare il seguente comando

 java -jar proguard.jar @parametri.pro


Il risultato è il seguente

Classe originale

import java.io.IOException;
import java.security.Key;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class Cypher
{
  private static Cypher istanza;


public static Cypher getInstance(){
      if(istanza==null){
          istanza=new Cypher();
      }
      return istanza;
  }

  private  Key getKey()
  {
    Date data = getDateForKey();
    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
    String chiave = sdf.format(data) + "abcdre";
   
    byte[] rawdata = chiave.getBytes();
   
    SecretKeySpec skeySpec = new SecretKeySpec(rawdata, "AES");
    return skeySpec; }

  private  Date getDateForKey() {
    Calendar c = Calendar.getInstance();
    c.set(1, 1978);
    c.set(2, 3);
    c.set(5, 20);
    return c.getTime(); }

  private  byte[] encrypt(String valore) throws Exception {
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(1, getKey());
    return cipher.doFinal(valore.getBytes());
  }

  private  byte[] decrypt(byte[] valore) throws Exception {
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(2, getKey());
    return cipher.doFinal(valore);
  }

  public  String cifra(String valore) throws Exception {
    return toBase64(encrypt(valore));
  }

  public  String decifra(String valore) throws Exception {
        return new String(decrypt(fromBase64(valore)));
      }
  private  String toBase64(byte[] valore)
  {
    return new String(new Base64().encode(valore));
  }

  private  byte[] fromBase64(String valore)
    throws IOException
  {
    return new Base64().decode(valore.getBytes());
  }

  public static void main(String[] args)
    throws Exception
  {
      Cypher c=Cypher.getInstance();
     
   String cifratoB64 = c.cifra("abilitatoDrillDown");
   String decifrato = c.decifra(cifratoB64);
    System.out.println("Cifrato: " + cifratoB64);
    System.out.println("Decifrato: " + decifrato);
  }
}


Se provo a decompilare il jar offuscato ottengo qualcosa di vagamente incomprensibile:


import java.io.PrintStream;
import java.security.Key;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class Cypher
{
  private static Cypher a;

  private Key a()
  {
    (localObject = Calendar.getInstance()).set(1, 1978);
    ((Calendar)localObject).set(2, 3);
    ((Calendar)localObject).set(5, 20);
    Object localObject = ((Calendar)localObject).getTime();
    SimpleDateFormat localSimpleDateFormat = new SimpleDateFormat("dd-MM-yyyy");
    localObject = (localObject = localSimpleDateFormat.format((Date)localObject) + "abcdre").getBytes();
    return (Key)(localObject = new SecretKeySpec(localObject, "AES"));
  }

  public static void main(String[] paramArrayOfString)
  {
    if (a == null)
      a = new Cypher();
    Object localObject2 = "abilitatoDrillDown";
    localObject2 = localObject2;
    Object localObject1 = localObject1 = paramArrayOfString = a;
    Cipher localCipher;
    (localCipher = Cipher.getInstance("AES")).init(1, ((Cypher)localObject1).a());
    localObject1 = localCipher.doFinal(((String)localObject2).getBytes());
    String str = new String(new Base64().encode(localObject1));
    localObject2 = str;
    localObject1 = paramArrayOfString;
    localObject1 = localObject2;
    localObject2 = new Base64().decode(((String)localObject1).getBytes());
    localObject1 = localObject1;
    (localCipher = Cipher.getInstance("AES")).init(2, ((Cypher)localObject1).a());
    paramArrayOfString = new String(localCipher.doFinal(localObject2));
    System.out.println("Cifrato: " + str);
    System.out.println("Decifrato: " + paramArrayOfString);
  }
}


NB: in questo caso anche importando il jar su un  nostro progetto sarà visibile solo il metodo main, per fare in modo che lo siano anche altri metodi occorre specificarli qui.

Esempio:

-keep public class it.oasi.cipher.Cypher {
    public static void main(java.lang.String[]);
    public static it.oasi.cipher.Cypher getInstance();
    public java.lang.String decifra(java.lang.String );
}


Da notare come le variabili di input non vanno specificati così come i tipi, se disgraziatamente doveste farlo (ad esempio nel decifra dopo il tipo di input definire la variabile valore) si incappa nel seguente messaggio di errore

Error: Expecting separating ',' or closing ')' before 'valore' in line 8 of file
 'parametri.pro',
  included from argument number 1

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>");
    }


martedì 15 maggio 2012

Display Table escludere colonne dall'export

Con display-table è possibile escludere una colonna da un export semplicemente specificando nell'attributo media per quali tipi di export deve essere abilitata (il default è ALL).
Quindi per escludere una colonna dall'export è sufficiente specificare dentro la colonna media="html".
E' quindi possibile anche il viceversa, ossia non mostrare una colonna a video ma solo in output, ad esemprio specificando media="pdf excel" la colonna sarà visibile soltanto negli export pdf ed excel e non a video

martedì 10 aprile 2012

Display Table tornare indietro su lista dati paginata

Utilizzando display tag spesso ci si imbatte in questo scenario.
Abbiamo una lista di dati paginata e linkata, quindi cliccando su un elemento si accede ad un dettaglio su un’altra pagina e da questa pagina si vuole tornare indietro esattamente nella lista paginata di partenza (es si era a pagina 3 di 4 e si vuole tornare esattamente lì e non alla pagina iniziale).
La display table di dispay tag utilizza un identificatore univoco per tabella sia per la paginazione che per l’ordinamento.
Tale identificatore è visibile in querystring quando si naviga da una pagina all’altra.
Sono possibili quindi 2 approcci.

Soluzione 1

Si prende nota dell’identificatore generato dalla display-table.
Quindi nella jsp di partenza (nella griglia di dati), si inserisce un codice di questo tipo:

<% String numPag=request.getParameter("d-49653-p")==null?"1":request.getParameter("d-49653-p");
   session.setAttribute("numPag", numPag);
%>


In modo che ad ogni paginazione il valore del numero di pagina sia salvato in sessione prendendolo dalla request.

Sulla jsp di destinazione avremo invece:

<a href="index.jsp?d-49653-p=${numPag}">Indietro</a>

Soluzione 2

In questo caso si realizza un filtro http che provvede ad analizzare la queryString e quando trova una espressione che identifica l’indicatore di pagina della display table mette in sessione il valore.
Quindi la jsp di partenza non avrà nessun codice particolare, la jsp di destinazione invece sarà uguale a quella vista nella soluzione 1.
Il filtro http invece avrà il seguente codice nel metodo doFilter.


public void doFilter(ServletRequest request, ServletResponse response,
                                   FilterChain chain) throws IOException, ServletException {
                        HttpServletRequest req = (HttpServletRequest) request;

                        String query_string = req.getQueryString();
                        if (null != query_string && query_string.length() > 0) {
                                   Pattern p = Pattern.compile("d-\\d*-p=(\\d*)");
                                   Matcher m = p.matcher(query_string);
                                   if (m.find()) {
                                               String val = m.group(1);

                                               req.getSession().setAttribute("numPag", val);

                                   }

                        }

                        chain.doFilter(request, response);
            }

La regular expression indicata in grassetto intercetta tutti i paramentri costituiti da una struttura del tipo d-[numeri]-p=[numeroPagina] e consentirà di intercettare quindi tutti i flag di paginazione di qualunque display table.
In questo modo quindi si evita di toccare ogni jsp annotando mettendo esplicitamente in sessione il valore della paginazione (anche se di tale valore bisogna comunque prendere nota per mostrarlo sulla jsp di arrivo alla pressione del tasto indietro).