Un problema affrontato è stato quello di generare report in maniera del tutto dinamica.
Utilizzando strumenti come BIRT o JasperReport è possibile creare dei report statici che permettono la visualizzazione di risultati su fogli di stile ad-hoc (definiti dal prodotto) che inglobano una query SQL e permettono la visualizzazione di un risultato che non cambierà mai per quanto riguarda gli attributi da visualizzare.
Cosa fare se ci devossere servire un report dove gli attributi da visualizzare cambiano nel tempo in funzione delle scelte dell’utente?
Supponiamo che abbiamo realizzato un’interfaccia che ci permetta di impostare le Viste (VIEW SQL) sulle quali fare delle JOIN e visualizzare delle informazioni, ma i dati che compongono le informazioni vengono scenlte arbitrariamente. E’ possibile utilizzare JasperReport per ottenere il risultato atteso.
Librerie Maven da integrare:
<dependencies> <!-- PostgreSQL Connector --> <dependency> <groupid>org.postgresql</groupid> <artifactid>postgresql</artifactid> <scope>runtime</scope> <version>${postgresql.version}</version> </dependency> <dependency> <groupid>net.sourceforge.dynamicreports</groupid> <artifactid>dynamicreports-core</artifactid> <version>5.1.0</version> </dependency> <dependency> <groupid>net.sourceforge.dynamicreports</groupid> <artifactid>dynamicreports-adhoc</artifactid> <version>5.1.0</version> </dependency> <dependency> <groupid>net.sourceforge.dynamicreports</groupid> <artifactid>dynamicreports-googlecharts</artifactid> <version>5.1.0</version> </dependency> <!-- https://mvnrepository.com/artifact/com.healthmarketscience.jackcess/jackcess --> <dependency> <groupid>com.healthmarketscience.jackcess</groupid> <artifactid>jackcess</artifactid> <version>2.1.11</version> </dependency> </dependencies> |
Dopo aver impostato le dipendenze occorre scrivere il codice che ci permetterà di creare il nostro report (notare che alcune costanti sono da impostare per il vostro codice)
Connection connection = null; try { connection = getConnection(); } catch (SQLException e) { e.printStackTrace(); } String query = "SELECT name, surname, email from people"; // questo e' lo stile per i titoli dedelle colonne da visualizzare StyleBuilder columnTitleStyle = stl.style() .setName("columnTitleStyle") .setBorder(stl.pen1Point()) .setHorizontalTextAlignment(HorizontalTextAlignment.CENTER) .setBackgroundColor(Color.LIGHT_GRAY); // questo e' lo stile per i risultati da visualizzare StyleBuilder columnResultStyle = stl.style() .setName("columnResultStyle") .setHorizontalTextAlignment(HorizontalTextAlignment.CENTER) ; JasperReportBuilder jasperReportBuilder = report() .columns( createColumnBuilder(query, connection) ) .title( //title of the report Components.text("SimpleReportExample") .setHorizontalTextAlignment(HorizontalTextAlignment.CENTER) ) .title( //image of the report Components.image(TOP_BANNER_CUSTOM_PNG) .setHorizontalImageAlignment(HorizontalImageAlignment.CENTER) ) .setColumnTitleStyle(columnTitleStyle) .setColumnStyle(columnResultStyle) .pageFooter(Components.pageXofY()) .setDataSource(query, connection); try { //jasperReportBuilder.toPdf(new FileOutputStream()); byte[] report = JasperExportManager.exportReportToPdf(jasperReportBuilder.toJasperPrint()); //to help debug my problem I write it to a file FileOutputStream fos = new FileOutputStream(PDF_FILE_NAME); fos.write(report); fos.flush(); fos.close(); } catch (DRException e) { e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (JRException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { connection.close(); } |
Il metodo createColumnBuilder(query, connection) ci permette di creare le colonne che rappresentano il nostro report:
private static ColumnBuilder[] createColumnBuilder(String sql, Connection connection) throws SQLException { String selectSQL = sql + " LIMIT 1 "; PreparedStatement preparedStatement = connection.prepareStatement(selectSQL); ResultSet rs = preparedStatement.executeQuery( ); ResultSetMetaData md = rs.getMetaData(); ColumnBuilder[] columnBuilders = new ColumnBuilder[md.getColumnCount()]; for (int i = 1; i < = md.getColumnCount(); i++) { String column = md.getColumnName(i); columnBuilders[i -1] = col.column( column, column, String.class); } return columnBuilders; } |
Per semplicità è stato messo tutto a stringa, ma possiamo anche migliorare il codice riconoscendo il tipo di dato e assegnare al columnBuilders il corretto tipo.