Dandelion 0.10.0

101
Thibault Duchateau @tduchateau http://dandelion.github.io 1 / 101

description

A first presentation of the Dandelion project, recently released in v0.10.0. Slides are available online here: http://dandelion.github.io/slides/dandelion-0.10.0

Transcript of Dandelion 0.10.0

Page 1: Dandelion 0.10.0

Thibault Duchateau@tduchateau

http://dandelion.github.io

1 / 101

Page 2: Dandelion 0.10.0

Quick introduction

Brief historyDandelion-Core

Dandelion-DatatablesSome statistics

FutureDemo

2 / 101

Page 3: Dandelion 0.10.0

Quick introductionFree & Open Source Java framework

Focused on two aspects of Web development:

Assets management (js, css): organization in bundles, HTMLinjection, soon asset minification and merging

Integration of powerful Javascript librairies thanks to a set ofcomponents

Licensed under BSD 3-Clause

Hosted on Github

Current version: 0.10.0

3 / 101

Page 4: Dandelion 0.10.0

Thanks to...

4 / 101

Page 5: Dandelion 0.10.0

Quick introduction

Brief history

Dandelion-CoreDandelion-Datatables

Some statisticsFutureDemo

5 / 101

Page 6: Dandelion 0.10.0

Brief history

History

6 / 101

Page 7: Dandelion 0.10.0

Quick introductionBrief history

Dandelion-Core

Dandelion-DatatablesSome statistics

FutureDemo

7 / 101

Page 8: Dandelion 0.10.0

Overview

8 / 101

Page 9: Dandelion 0.10.0

Asset bundles

Declarative approach, via JSON (soon XML and JavaConfig)

{ "bundle" : "jquery", "assets": [ { "name": "jquery", "version": "1.11.1", "type": "js", "locations": { "webapp": "/assets/js/jquery-1.11.1.js" } } ]}

Several locations are allowed for each asset: webapp, classpath, CDN, JAR,WebJar and API!

See the docs

9 / 101

Page 10: Dandelion 0.10.0

Dependencies between bundles

You can declare one or more bundles as dependencies

{ "bundle" : "select2", "dependencies": [ "jquery" ], "assets": [ { "name": "select2", "version": "3.4.8", "type": "js", "locations": { "webapp": "/assets/js/select2.js" } }, { "name": "select2", "version": "3.4.8", "type": "css", "locations": { "webapp": "/assets/css/select2.css" } } ]}

10 / 101

Page 11: Dandelion 0.10.0

Asset locators

Internal components used by Dandelion to fetch assets indifferent ways

Used via the corresponding location key in the bundle declaration

See the docs

11 / 101

Page 12: Dandelion 0.10.0

Project your-project|__ src |__ main |__ webapp |__ assets |__ js |__ app.js

Asset locators — webapp

12 / 101

Page 13: Dandelion 0.10.0

Project

Bundle

{ "bundle" : "my-bundle", "assets": [{ "name": "my-application", "version": "1.0.0", "type": "js", "locations": { "webapp": "/assets/js/app.js" } }]}

Asset locators — webapp

13 / 101

Page 14: Dandelion 0.10.0

Project

Bundle

HTML

<script src="/[contextPath]/assets/js/app.js"></script>

Asset locators — webapp

14 / 101

Page 15: Dandelion 0.10.0

Project your-project|__ src |__ main |__ resources |__ js |__ app.js

Asset locators — classpath

15 / 101

Page 16: Dandelion 0.10.0

Project

Bundle

{ "bundle" : "my-bundle", "assets": [{ "name": "my-application", "version": "1.0.0", "type": "js", "locations": { "classpath": "js/app.js" } }]}

Asset locators — classpath

16 / 101

Page 17: Dandelion 0.10.0

Project

Bundle

HTML

<script src="/[contextPath] /dandelion-assets /[cacheKey] /app.js"></script>

Asset locators — classpath

17 / 101

Page 18: Dandelion 0.10.0

Bundle { "bundle" : "jquery", "assets": [{ "name": "jquery", "version": "1.11.0", "type": "js", "locations": { "cdn": "//cdnjs.cloudflare.com/.../jquery.js" } }]}

Asset locators — cdn

18 / 101

Page 19: Dandelion 0.10.0

Bundle

HTML

<script src="//cdnjs.cloudflare.com/.../jquery.js"></script>

Asset locators — cdn

19 / 101

Page 20: Dandelion 0.10.0

JAR datatables-core|__ src |__ main |__ resources |__ META-INF |__ resources |__ folder |__ js |__ app.js

Asset locators — jar

20 / 101

Page 21: Dandelion 0.10.0

JAR

Bundle

{ "bundle" : "my-bundle", "assets": [{ "name": "my-app", "version": "1.0.0", "type": "js", "locations": { "jar": "folder/js/app.js" } }]}

Asset locators — jar

21 / 101

Page 22: Dandelion 0.10.0

JAR

Bundle

HTML

Inside a Servlet 2.0+ container:

<script src="/[contextPath] /dandelion-assets /[cacheKey] /app.js"></script>

Inside a Servlet 3.0+ container:

<script src="/[contextPath]/folder/js/app.js"></script>

Dandelion automatically detects whether therunning server is using the Servlet 3.x API or lower

Asset locators — jar

22 / 101

Page 23: Dandelion 0.10.0

Newdependency

<dependency> <groupId>com.github.dandelion</groupId> <artifactId>dandelion-webjars</artifactId> <version>0.10.0</version></dependency>

This artifact brings a new dependency to the webjars-locator project, which is internally used by the locator tolocate assets inside WebJars

Asset locators — webjar

23 / 101

Page 24: Dandelion 0.10.0

Newdependency

WebJar

<dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>3.2.0</version></dependency>

Asset locators — webjar

24 / 101

Page 25: Dandelion 0.10.0

Newdependency

WebJar

Bundle

{ "bundle" : "my-bundle", "assets": [{ "name": "bootstrap", "version": "3.2.0", "type": "css", "locations": { "webjar": "bootstrap.css" } }]}

Asset locators — webjar

25 / 101

Page 26: Dandelion 0.10.0

Newdependency

WebJar

Bundle

HTML

Inside a Servlet 2.0+ container:

<link rel="stylesheet" href="/[contextPath] /dandelion-assets /[cacheKey] /bootstrap.css"/>

Inside a Servlet 3.0+ container:

<link rel="stylesheet" href="/[contextPath] /webjars /bootstrap /3.2.0 /css /bootstrap.css" />

Dandelion automatically detects whether therunning server is using the Servlet 3.x API or lower

Asset locators — webjar

26 / 101

Page 27: Dandelion 0.10.0

Asset locators — delegateReads the content of an asset from a special parameter stored inside theAssetRequestContext

This special parameter:

must be stored under the DelegateLocator.DELEGATED_CONTENT_PARAMkey

must be a class that implements DelegatedContent and where thegetContent() method must return the asset content to be injected ]

27 / 101

Page 28: Dandelion 0.10.0

Bundle { "bundle": "my-bundle", "assets": [{ "name": "my-generated-asset", "version": "1.0.0", "type": "js", "locations": { "delegate": "app.js" } }]}

Asset locators — delegate

28 / 101

Page 29: Dandelion 0.10.0

Bundle

Generator

public class SomeJavascriptGenerator implements DelegatedContent {

@Override public String getContent(HttpServletRequest request) { return "alert('Hey!');"; }}

Asset locators — delegate

29 / 101

Page 30: Dandelion 0.10.0

Bundle

Generator

ARC

AssetRequestContext .get(request) .addParameter("my-generated-asset", DelegateLocator.DELEGATED_CONTENT_PARAM, new SomeJavascriptGenerator());

Asset locators — delegate

30 / 101

Page 31: Dandelion 0.10.0

Bundle

Generator

ARC

HTML

<script src="/[contextPath] /dandelion-assets /[cacheKey] /app.js"></script>

Where app.js:

alert('Hey!');

Asset locators — delegate

31 / 101

Page 32: Dandelion 0.10.0

Bundle loaders

Scan for bundles in the classpath, in the following order:

VendorBundleLoader: intended to load vendor bundles (e.g. jquery.json)

ComponentBundleLoader: intended to load components bundles (e.g. ddl-dt.json)

DandelionBundleLoader: intended to load user bundles (e.g. custom-bundle.json)See the docs

32 / 101

Page 33: Dandelion 0.10.0

Bundle graphOn the application startup, Dandelion creates a Context that will be injectedinto each request.

This Context provide several information:

all configuration options (coming from the properties files)a bundle graph (DAG), built from all scanned bundles

Example:

src|__ main |__ resources |__ dandelion |__ jquery.json |__ select2.json

See the docs

33 / 101

Page 34: Dandelion 0.10.0

Interacting with the bundle graph

1/4) Using the JSP taglib

<%@ taglib prefix="dandelion" uri="http://github.com/dandelion" %>

<dandelion:bundle includes="select2" />

2/4) Using the Thymeleaf dialect

<!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org" xmlns:ddl="http://github.com/dandelion" ddl:bundle-includes="select2"> ...</html>

See the docs

34 / 101

Page 35: Dandelion 0.10.0

Interacting with the bundle graph

3/4) Using the fluent API

AssetRequestContext .get((HttpServletRequest) request) .addBundle("select2");

4/4) Using the configuration file ("permanent" bundles)

bundle.includes=select2

See the docs

35 / 101

Page 36: Dandelion 0.10.0

Interacting with the bundle graph

Whatever the technology used, Dandelion automatically injects allrequested assets into the HTML code:

in the right orderin the configured position, by default CSS in <head> and JS just before</body>and (soon) applies the right HTTP headers, therefore optimizing browsercaching

<html> <head> <link href="/context/assets/css/select2.css" /> </head> <body> ... <script src="/context/assets/js/jquery-1.11.1.js"></script> <script src="/context/assets/js/select2.js"></script> </body></html>

36 / 101

Page 37: Dandelion 0.10.0

Asset processors

Intended to process assets, in different ways...

Built-in processors:

jsMinYui:JS minification based on Yahoo's YUI CompressorcssMinYui:CSS minification based on Yahoo's YUI CompressorcssMin:CSS minification based on a fork of YUIjsMin:JS minification based on a fork of YUIcssUrlRewriting:Image URLs rewriting in CSS

Soon:

cssLess: Convert Less resources to CSScssSass: Convert Sass resources to CSScssImport: Processes @importcoffeeScript: Convert CoffeeScript to JavaScript...

See the docs

37 / 101

Page 38: Dandelion 0.10.0

Development/production modes

Development mode

Built-in dev tools availableServer-side caching disabledBrowser caching disabled

Production mode

No bundle graph viewer, no bundle reloadingMinification enabledServer-side caching enabled(soon) Browser caching enabled(soon) GZIP compression(soon) Asset versioning(soon) JMX monitoring

38 / 101

Page 39: Dandelion 0.10.0

Dev tools

Bundle graphviewer

Dev tool allowing to visualize how Dandelion-Corehandles assets, in the current request

http://example.com/context/some/uri?showGraph

Available in development mode only

See the docs

39 / 101

Page 40: Dandelion 0.10.0

Dev tools

Bundle graphviewer

Assetreloading

During development, both server-side and client-sidecaching are disabled.

Client-side, Dandelion-Core applies the following HTTPheaders:

Cache-Control = no-cache, no-store, must-revalidate (HTTP 1.1)Pragma = no-cache (HTTP 1.0)Expires = 0 (Proxies)

40 / 101

Page 41: Dandelion 0.10.0

Dev tools

Bundle graphviewer

Assetreloading

Bundlereloading

During development, all changes made in asset bundlescan be reflected.

Just manually append a new reloadBundles requestparameter to the current URL to perform a full bundlereloading.

http://example.com/context/some/uri?reloadBundles

Available in development mode only

41 / 101

Page 42: Dandelion 0.10.0

Properties dandelion.properties

dandelion.mode=production

Configuration options

42 / 101

Page 43: Dandelion 0.10.0

Properties

Filter initparam

filter init param > dandelion.properties

<filter> <filter-name>dandelion</filter-name> <filter-class>...DandelionFilter</filter-class> <init-param> <param-name>dandelion.mode<param-name> <param-value>production</param-value> </init-param></filter>

Configuration options

43 / 101

Page 44: Dandelion 0.10.0

Properties

Filter initparam

Systemproperty

system property > filter init param >dandelion.properties

-Ddandelion.mode=production

Configuration options

See the docs

44 / 101

Page 45: Dandelion 0.10.0

Quick introductionBrief history

Dandelion-Core

Dandelion-Datatables

Some statisticsFutureDemo

45 / 101

Page 46: Dandelion 0.10.0

Introducing Dandelion-DatatablesFirst and most advanced component of the Dandelion framework

Facilitates the integration of DataTables, an awesome jQueryplugin which will add advanced interaction controls to any HTMLtable

Easy to use

Easy to extend

Inspired by the excellent DisplayTag library

46 / 101

Page 47: Dandelion 0.10.0

Key featuresJSP & Thymeleaf supportTypical features such as paging, filtering and sortingDOM sources, AJAX sources and server-side processingResponsive designExport in multiple formatsSeveral themes available: Bootstrap 2, Bootstrap 3, jQueryUII18nIntegration with Spring/Spring MVC and other projects

47 / 101

Page 48: Dandelion 0.10.0

What it looks like with JSP?

<%@ taglib prefix="datatables" uri="http://github.com/dandelion/datatables" %>

<datatables:table id="myTableId" data="${persons}"> <datatables:column title="Id" property="id" /> <datatables:column title="LastName" property="lastName" /> <datatables:column title="FirstName" property="firstName" /> <datatables:column title="City" property="address.town.name" /> <datatables:column title="Mail" property="mail" /></datatables:table>

id: HTML pass-through attributedata: DOM source, collection of POJOstitle: sets the content of the column headerproperty: name of the object's attribute of the collection being iterated on

48 / 101

Page 49: Dandelion 0.10.0

What it looks like with Thymeleaf?

<table id="myTableId" dt:table="true"> <thead> <tr> <th>Id</th> <th>Firstname</th> <th>Lastname</th> <th>City</th> <th>Mail</th> </tr> </thead> <tbody> <tr th:each="person : ${persons}"> <td th:text="${person.id}">1</td> <td th:text="${person.firstName}">John</td> <td th:text="${person.lastName}">Doe</td> <td th:text="${person?.address?.town?.name}">Nobody knows!</td> <td th:text="${person.mail}">[email protected]</td> </tr> </tbody></table>

dt:table: enables the Dandelion-Datatables dialect in the current table

49 / 101

Page 50: Dandelion 0.10.0

HTML The HTML is generated:

either by Dandelion-Datatables (JSP)or directly by Thymeleaf

<table id="myTableId"> <thead> <tr> <th>Id</th> <th>Firstname</th> <th>Lastname</th> <th>City</th> <th>Mail</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>Wing</td> <td>Cunningham</td> <td></td> <td>[email protected]</td> </tr> ... </tbody></table>

How it works?

50 / 101

Page 51: Dandelion 0.10.0

HTML

JavaScript

As well as the JS code that initializes DataTables

var oTable_myTableId = $('#myTableId');var oTable_myTableId_params = { "aoColumns":[ { "mData":"id", "sDefaultContent":"" }, { "mData":"lastName", "sDefaultContent":"" }, { "mData":"firstName", "sDefaultContent":"" }, { "mData":"address.town.name", "sDefaultContent":"" }, { "mData":"mail", "sDefaultContent":"" } ]}

$(document).ready(function(){ oTable_myTableId.dataTable(oTable_myTableId_params);});

How it works?

51 / 101

Page 52: Dandelion 0.10.0

HTML

JavaScript

Requiredassets

An AssetRequestContext is filled with the required assets,either by the JSP taglib or by the Thymeleaf dialect...

AssetRequestContext .get(request) .addBundle("datatables") .addBundle("ddl-dt") ...;

... so that they will be injected by Dandelion-Core into theresponse

<link href="//cdn/jquery.dataTables.css"/>...<script src="//cdn/jquery.js"></script><script src="//cdn/jquery.dataTables.js"></script><script src="/[contextPath] /dandelion-assets /[SHA] /dandelion-datatables-0.10.0.js"></script>

How it works?

52 / 101

Page 53: Dandelion 0.10.0

Usage examples

53 / 101

Page 54: Dandelion 0.10.0

HTML (DOM) sourcesRead data directly from the DOM

Works well with small/medium data sources

54 / 101

Page 55: Dandelion 0.10.0

Controller Example with a Spring MVC controller

@Controllerpublic class Controller {

@ModelAttribute("persons") public List<Person> populateTable() { return personService.findAll(); }}

HTML sources — example

55 / 101

Page 56: Dandelion 0.10.0

Controller

JSP

<datatables:table id="myTableId" data="${persons}"> <datatables:column title="Id" property="id" /> ...</datatables:table>

HTML sources — example

56 / 101

Page 57: Dandelion 0.10.0

Controller

JSP

Thymeleaf

<table id="myTableId" dt:table="true"> ... <tbody> <tr th:each="person : ${persons}"> <td th:text="${person.id}">1</td> ... </tr> </tbody><table>

HTML sources — example

57 / 101

Page 58: Dandelion 0.10.0

AJAX sourcesRead data from virtually any JSON data source that can be obtained byAJAX

Client-side processing

Works well with small/medium data sources

58 / 101

Page 59: Dandelion 0.10.0

Controller Example with a Spring MVC controller

@Controllerpublic class AjaxController {

@RequestMapping(value = "/persons") public @ResponseBody List<Person> findAll() { return personService.findAll(); }}

AJAX sources

59 / 101

Page 60: Dandelion 0.10.0

Controller

JSP

<datatables:table id="myTableId" url="/persons"> <datatables:column title="Id" property="id" /> ...</datatables:table>

Dandelion-Datatables rewrites URLs by appending thecontext path, if needed.

AJAX sources

60 / 101

Page 61: Dandelion 0.10.0

Controller

JSP

Thymeleaf

<table id="myTableId" dt:table="true" dt:url="@{/persons}"> ... <tbody> <tr th:each="person : ${persons}"> <td th:text="${person.id}">1</td> ... </tr> </tbody><table>

AJAX sources

61 / 101

Page 62: Dandelion 0.10.0

AJAX sources + server-side processingRead data from virtually any JSON data source that can be obtained byAJAX

Server-side processing

Each draw of the table will result in a new AJAX request being made toget the required data

Works well with small/medium/large data sources

62 / 101

Page 63: Dandelion 0.10.0

AJAX sources + server-side processing

Dandelion-Datatables provides a convenient API

DatatablesCriterias

Stores all DataTables parameters (current page, entries to display,sorted columns, ...)

@RequestMapping(value = "/persons")public @ResponseBody DatatablesResponse<Person> filter(HttpServletRequest request) {

// Maps request parameter to a DatatablesCriterias instance DatatablesCriterias criterias = DatatablesCriterias.getFromRequest(request);

...

63 / 101

Page 64: Dandelion 0.10.0

AJAX sources + server-side processing

Dandelion-Datatables provides a convenient API

DataSet

All entries returned by the data access layer should be wrapped in thisclass in order to build a DataTablesResponse

...

// Get filtered and paged data DataSet<Person> persons = personService.findPersons(criterias);

...

64 / 101

Page 65: Dandelion 0.10.0

AJAX sources + server-side processing

Dandelion-Datatables provides a convenient API

DataTablesResponse

Contains a builder that helps to return the data in the format requiredby DataTables

Must be converted into JSON

...

// Build the response that will be converted to JSON return DatatablesResponse.build(persons, criterias);}

65 / 101

Page 66: Dandelion 0.10.0

Controller Example with a Spring MVC AJAX controller

@RequestMapping(value = "/persons")public @ResponseBody DatatablesResponse<Person> filter(HttpServletRequest request) {

// Maps request parameter to a DatatablesCriterias instance DatatablesCriterias criterias = DatatablesCriterias.getFromRequest(request);

// Get filtered and paged data DataSet<Person> persons = personService.findPersons(criterias);

// Build the response that will be converted to JSON return DatatablesResponse.build(persons, criterias);}

AJAX sources + server-side processing

66 / 101

Page 67: Dandelion 0.10.0

Controller

JSP

<datatables:table ... url="/persons" serverSide="true"> <datatables:column property="id" /> <datatables:column property="firstName" /> <datatables:column property="lastName" /> <datatables:column property="address.town.name" /> <datatables:column property="mail" /></datatables:table>

AJAX sources + server-side processing

67 / 101

Page 68: Dandelion 0.10.0

Controller

JSP

Thymeleaf

<table ... dt:url="@{/persons}" dt:serverSide="true"> <thead> <tr> <th dt:property="id">Id</th> <th dt:property="firstName">Firstname</th> <th dt:property="lastName">Lastname</th> <th dt:property="address.town.name">City</th> <th dt:property="mail">Mail</th> </tr> </thead></table>

AJAX sources + server-side processing

68 / 101

Page 69: Dandelion 0.10.0

JSP <datatables:table ... pageable="false"> <datatables:column ... sortable="false" /> <datatables:column ... filterable="true" /> ...</datatables:table>

Paging, sorting, filtering

69 / 101

Page 70: Dandelion 0.10.0

JSP

Thymeleaf

<table ... dt:pageable="false" > <thead> <th dt:sortable="false">Id</th> <th dt:filterable="true">LastName</th> ... </thead> ...<table>

Paging, sorting, filtering

70 / 101

Page 71: Dandelion 0.10.0

Export — what formats?

Text-based formats: CSV, XML

Built-in support, no dependency or extra required.

71 / 101

Page 72: Dandelion 0.10.0

Export — what formats?

Binary-based formats: PDF, XLS, XLSX

Some extras already exist and provide:

an export class that is used by default if the corresponding export formatis enabledthe corresponding library in compile scope (e.g. Apache POI for the XLSformat)

Available extras:

PDF: datatables-export-itextXLS: datatables-export-poiXLSX: datatables-export-poi-ooxml

72 / 101

Page 73: Dandelion 0.10.0

Export — 2 ways

Filter-based

Fast to set upAlways export full data sourceOnly compatible with DOM sources

Controller-based

Requires a bit more work to set upWYSIWYE => What You See Is What You ... Export!Compatible with DOM and AJAX sources

73 / 101

Page 74: Dandelion 0.10.0

Newdependency

<dependency> <groupId>com.github.dandelion</groupId> <artifactId>datatables-export-itext</artifactId> <version>0.10.0</version></dependency>

Export — filter-based

74 / 101

Page 75: Dandelion 0.10.0

Newdependency

web.xml

<!-- Dandelion-Datatables filter used for basic export --><filter> <filter-name>datatables</filter-name> <filter-class>...DatatablesFilter</filter-class></filter><filter-mapping> <filter-name>datatables</filter-name> <url-pattern>/*</url-pattern></filter-mapping>

Export — filter-based

75 / 101

Page 76: Dandelion 0.10.0

Newdependency

web.xml

JSP

<datatables:table ... export="pdf"> <datatables:column property="id" /> <datatables:column property="firstName" /> <datatables:column property="lastName" /> <datatables:column property="address.town.name" /> <datatables:column property="mail" /></datatables:table>

Export — filter-based

76 / 101

Page 77: Dandelion 0.10.0

Newdependency

web.xml

JSP

Thymeleaf

<table id="myTable" dt:table="true" dt:export="pdf"> <thead> <tr> <th>Id</th> <th>Firstname</th> <th>Lastname</th> <th>City</th> <th>Mail</th> </tr> </thead> <tbody> <tr th:each="person : ${persons}"> <td th:text="${person.id}">1</td> <td th:text="${person.firstName}">John</td> <td th:text="${person.lastName}">Doe</td> <td th:text="${person.address.town.name}">Nobody knows!</td> <td th:text="${person.mail}">[email protected]</td> </tr> </tbody></table>

Export — filter-based

77 / 101

Page 78: Dandelion 0.10.0

Newdependency

<dependency> <groupId>com.github.dandelion</groupId> <artifactId>datatables-export-itext</artifactId> <version>0.10.0</version></dependency>

Export — controller-based

78 / 101

Page 79: Dandelion 0.10.0

Newdependency

JSP

<datatables:table id="myTableId" url="/persons" export="pdf"> <datatables:column property="id" /> <datatables:column property="firstName" /> ... <datatables:export type="csv" url="/export.pdf" /></datatables:table>

Export — controller-based

79 / 101

Page 80: Dandelion 0.10.0

Newdependency

JSP

Thymeleaf

<div dt:conf="myTableId"> <div dt:confType="export" dt:type="pdf" dt:url="@{/export.pdf}"></div></div>

<table ... dt:url="@{/persons}" dt:export="pdf"> <thead> <tr> <th dt:property="id">Id</th> <th dt:property="firstName">Firstname</th> <th dt:property="lastName">Lastname</th> <th dt:property="address.town.name">City</th> <th dt:property="mail">Mail</th> </tr> </thead></table>

Export — controller-based

80 / 101

Page 81: Dandelion 0.10.0

Newdependency

JSP

Thymeleaf

Controller(1/4)

@RequestMapping(value = "/export", produces = "application/pdf")public void pdf(@DatatablesParams DatatablesCriterias criterias, HttpServletRequest request, HttpServletResponse response) {

// Get data to export using the provided criteria List<Person> persons = personService.findPersons(criterias);

...

Export — controller-based

81 / 101

Page 82: Dandelion 0.10.0

Newdependency

JSP

Thymeleaf

Controller(2/4)

...

// Build the export configuration ExportConf exportPdfConf = new ExportConf.Builder("pdf") .header(true) .exportClass(new PdfExport()) .build();

...

Export — controller-based

82 / 101

Page 83: Dandelion 0.10.0

Newdependency

JSP

Thymeleaf

Controller(3/4)

...

// Build the table to export using the above data // and the export configuration HtmlTable table = new HtmlTableBuilder<Person>() .newBuilder("tableId", persons, request, exportPdfConf) .column().fillWithProperty("id").title("Id") .column().fillWithProperty("firstName").title("Firtname") .column().fillWithProperty("lastName").title("Lastname") .column().fillWithProperty("address.town.name").title("City") .column().fillWithProperty("mail").title("Mail") .column() .fillWithProperty("birthDate", "{0,date,dd-MM-yyyy}") .title("BirthDate") .build();

...

Export — controller-based

83 / 101

Page 84: Dandelion 0.10.0

Newdependency

JSP

Thymeleaf

Controller(4/4)

...

// Render the export file in the browser ExportUtils.renderExport(table, exportPdfConf, response);}

Export — controller-based

84 / 101

Page 85: Dandelion 0.10.0

I18n: DataTables' informationdatatables.properties: non-translatable properties

global.css.class=table table-striped table-bordered table-condensedglobal.extra.theme=bootstrap2

datatables_EN.properties: all EN translations

global.i18n.msg.processing=Processing...global.i18n.msg.search=Search:global.i18n.msg.info=Showing _START_ to _END_ of _TOTAL_ entries

datatables_FR.properties: all FR translations

global.i18n.msg.processing=Traitement en cours...global.i18n.msg.search=Rechercher :global.i18n.msg.info=Affichage de l'élément _START_ à _END_ sur _TOTAL_ éléments

85 / 101

Page 86: Dandelion 0.10.0

I18n: column headersBased on LocaleResolver and MessageResolver interfaces

Built-in implementations:

SpringLocaleResolver / SpringMessageResolverJstlLocaleResolver / JstlMessageResolverStruts1LocaleResolver / Struts1MessageResolverStruts2LocaleResolver / Struts2MessageResolver

Possible to plug-in custom locale and message resolvers

86 / 101

Page 87: Dandelion 0.10.0

Spring config <bean id="messageSource" class="..."> <property name="basename" value="classpath:messages" /></bean>

I18n: example with Spring

87 / 101

Page 88: Dandelion 0.10.0

Spring config

Resourcebundles

Location:

src|__ main |__ resources |__ messages.properties |__ messages_FR.properties

messages.properties:

table.header.lastname=Lastnametable.header.firstname=Firstname

messages_FR.properties:

table.header.lastname=Nomtable.header.firstname=Prénom

I18n: example with Spring

88 / 101

Page 89: Dandelion 0.10.0

Spring config

Resourcebundles

JSP

<datatables:table id="myTableId" data="${persons}"> ... <datatables:column titleKey="table.header.firstname" ... /> <datatables:column titleKey="table.header.lastname" ... /> ...</datatables:table>

I18n: example with Spring

89 / 101

Page 90: Dandelion 0.10.0

Spring config

Resourcebundles

JSP

Thymeleaf

<table id="myTableId" dt:table="true"> <thead> <tr> ... <th th:text="#{table.header.firstname}">Firstname</th> <th th:text="#{table.header.lastname}">Lastname</th> ... </tr> </thead> ...</table>

I18n: example with Spring

90 / 101

Page 92: Dandelion 0.10.0

JSP <datatables:table ... theme="bootstrap3" cssClass="table"> <datatables:column property="id" /> <datatables:column property="firstName" /> <datatables:column property="lastName" /> <datatables:column property="address.town.name" /> <datatables:column property="mail" /></datatables:table>

Theming

92 / 101

Page 93: Dandelion 0.10.0

JSP

Thymeleaf

<table ... dt:theme="bootstrap3" class="table"> <thead> <tr> <th>Id</th> <th>Firstname</th> <th>Lastname</th> <th>Street</th> <th>Mail</th> </tr> </thead> <tbody> <tr th:each="person : ${persons}"> <td th:text="${person?.id}">1</td> <td th:text="${person?.firstName}">John</td> <td th:text="${person?.lastName}">Doe</td> <td th:text="${person?.address?.town?.name}">Nobody knows!</td> <td th:text="${person?.mail}">[email protected]</td> </tr> </tbody></table>

Theming

93 / 101

Page 94: Dandelion 0.10.0

Quick introductionBrief history

Dandelion-CoreDandelion-Datatables

Some statistics

FutureDemo

94 / 101

Page 95: Dandelion 0.10.0

Some statistics35 releases (source: GitHub, all repos)15 pull requests merged (source: GitHub, all repos)9 contributors from 6 countries (source: GitHub, all repos)1432 commits (source: Ohloh)121,770 LOC (source: Ohloh)98 GitHub stars (source: GitHub, all repos)~80 followers on Twitter (source: Twitter)~270 topics, ~10000 views in the forum (source: Nabble)3200+ redeploys/restarts prevented, saving about 106h (source: JRebel)

95 / 101

Page 96: Dandelion 0.10.0

Quick introductionBrief history

Dandelion-CoreDandelion-Datatables

Some statistics

Future

Demo

96 / 101

Page 97: Dandelion 0.10.0

Dandelion-Core

Full support for asset minification and mergingImprovements on asset bundles: externalization,configuration via XML, JavaConfigAdd new processors for meta-frameworks(CoffeeScript, Less, ...)Add support for conditionnal assets (e.g. IE8+, IE9+)Add support for CSS spritesNew AssetCache implementation based on HazelcastJBoss Forge plugin allowing to scaffold a project basedon DandelionAdd support for RequireJSBower integration

Future

97 / 101

Page 98: Dandelion 0.10.0

Dandelion-Core

Dandelion-Datatables

New extension for editable tables (Editor, jEditable, ...)Add support for more DataTables' extensionsAdd support for DataTables 1.10.0New theme for FoundationAdd WebSocket support for continously-updatingtables (Atmosphere, Spring MVC 4)Add support for Spring Data REST

Future

98 / 101

Page 99: Dandelion 0.10.0

Dandelion-Core

Dandelion-Datatables

Newcomponents!

Dandelion-GUA? (Google Universal Analytics)Dandelion-Forms?All ideas are welcome!

Future

99 / 101

Page 100: Dandelion 0.10.0

Quick introductionBrief history

Dandelion-CoreDandelion-Datatables

Some statisticsFuture

Demo

100 / 101

Page 101: Dandelion 0.10.0

Demo

https://github.com/dandelion/dandelion-samples

101 / 101