Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dandelion 0.10.0

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

Dandelion 0.10.0

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

Avatar for Thibault Duchateau

Thibault Duchateau

July 09, 2014

Other Decks in Programming

Transcript

  1. Quick introduction Free & Open Source Java framework Focused on

    two aspects of Web development: Assets management (js, css): organization in bundles, HTML injection, soon asset minification and merging Integration of powerful Javascript librairies thanks to a set of components Licensed under BSD 3-Clause Hosted on Github Current version: 0.10.0 3 / 101
  2. Asset bundles Declarative approach, via JSON (soon XML and JavaConfig)

    { " b u n d l e " : " j q u e r y " , " a s s e t s " : [ { " n a m e " : " j q u e r y " , " v e r s i o n " : " 1 . 1 1 . 1 " , " t y p e " : " j s " , " l o c a t i o n s " : { " w e b a p p " : " / a s s e t s / j s / j q u e r y - 1 . 1 1 . 1 . j s " } } ] } Several locations are allowed for each asset: webapp, classpath, CDN, JAR, WebJar and API! See the docs 9 / 101
  3. Dependencies between bundles You can declare one or more bundles

    as dependencies { " b u n d l e " : " s e l e c t 2 " , " d e p e n d e n c i e s " : [ " j q u e r y " ] , " a s s e t s " : [ { " n a m e " : " s e l e c t 2 " , " v e r s i o n " : " 3 . 4 . 8 " , " t y p e " : " j s " , " l o c a t i o n s " : { " w e b a p p " : " / a s s e t s / j s / s e l e c t 2 . j s " } } , { " n a m e " : " s e l e c t 2 " , " v e r s i o n " : " 3 . 4 . 8 " , " t y p e " : " c s s " , " l o c a t i o n s " : { " w e b a p p " : " / a s s e t s / c s s / s e l e c t 2 . c s s " } } ] } 10 / 101
  4. Asset locators Internal components used by Dandelion to fetch assets

    in different ways Used via the corresponding location key in the bundle declaration See the docs 11 / 101
  5. Project y o u r - p r o j

    e c t | _ _ s r c | _ _ m a i n | _ _ w e b a p p | _ _ a s s e t s | _ _ j s | _ _ a p p . j s Asset locators — webapp 12 / 101
  6. Project Bundle { " b u n d l e

    " : " m y - b u n d l e " , " a s s e t s " : [ { " n a m e " : " m y - a p p l i c a t i o n " , " v e r s i o n " : " 1 . 0 . 0 " , " t y p e " : " j s " , " l o c a t i o n s " : { " w e b a p p " : " / a s s e t s / j s / a p p . j s " } } ] } Asset locators — webapp 13 / 101
  7. Project Bundle HTML < s c r i p t

    s r c = " / [ c o n t e x t P a t h ] / a s s e t s / j s / a p p . j s " > < / s c r i p t > Asset locators — webapp 14 / 101
  8. Project y o u r - p r o j

    e c t | _ _ s r c | _ _ m a i n | _ _ r e s o u r c e s | _ _ j s | _ _ a p p . j s Asset locators — classpath 15 / 101
  9. Project Bundle { " b u n d l e

    " : " m y - b u n d l e " , " a s s e t s " : [ { " n a m e " : " m y - a p p l i c a t i o n " , " v e r s i o n " : " 1 . 0 . 0 " , " t y p e " : " j s " , " l o c a t i o n s " : { " c l a s s p a t h " : " j s / a p p . j s " } } ] } Asset locators — classpath 16 / 101
  10. Project Bundle HTML < s c r i p t

    s r c = " / [ c o n t e x t P a t h ] / d a n d e l i o n - a s s e t s / [ c a c h e K e y ] / a p p . j s " > < / s c r i p t > Asset locators — classpath 17 / 101
  11. Bundle { " b u n d l e "

    : " j q u e r y " , " a s s e t s " : [ { " n a m e " : " j q u e r y " , " v e r s i o n " : " 1 . 1 1 . 0 " , " t y p e " : " j s " , " l o c a t i o n s " : { " c d n " : " / / c d n j s . c l o u d f l a r e . c o m / . . . / j q u e r y . j s " } } ] } Asset locators — cdn 18 / 101
  12. Bundle HTML < s c r i p t s

    r c = " / / c d n j s . c l o u d f l a r e . c o m / . . . / j q u e r y . j s " > < / s c r i p t > Asset locators — cdn 19 / 101
  13. JAR d a t a t a b l e

    s - c o r e | _ _ s r c | _ _ m a i n | _ _ r e s o u r c e s | _ _ M E T A - I N F | _ _ r e s o u r c e s | _ _ f o l d e r | _ _ j s | _ _ a p p . j s Asset locators — jar 20 / 101
  14. JAR Bundle { " b u n d l e

    " : " m y - b u n d l e " , " a s s e t s " : [ { " n a m e " : " m y - a p p " , " v e r s i o n " : " 1 . 0 . 0 " , " t y p e " : " j s " , " l o c a t i o n s " : { " j a r " : " f o l d e r / j s / a p p . j s " } } ] } Asset locators — jar 21 / 101
  15. JAR Bundle HTML Inside a Servlet 2.0+ container: < s

    c r i p t s r c = " / [ c o n t e x t P a t h ] / d a n d e l i o n - a s s e t s / [ c a c h e K e y ] / a p p . j s " > < / s c r i p t > Inside a Servlet 3.0+ container: < s c r i p t s r c = " / [ c o n t e x t P a t h ] / f o l d e r / j s / a p p . j s " > < / s c r i p t > Dandelion automatically detects whether the running server is using the Servlet 3.x API or lower Asset locators — jar 22 / 101
  16. New dependency < d e p e n d e

    n c y > < g r o u p I d > c o m . g i t h u b . d a n d e l i o n < / g r o u p I d > < a r t i f a c t I d > d a n d e l i o n - w e b j a r s < / a r t i f a c t I d > < v e r s i o n > 0 . 1 0 . 0 < / v e r s i o n > < / d e p e n d e n c y > This artifact brings a new dependency to the webjars- locator project, which is internally used by the locator to locate assets inside WebJars Asset locators — webjar 23 / 101
  17. New dependency WebJar < d e p e n d

    e n c y > < g r o u p I d > o r g . w e b j a r s < / g r o u p I d > < a r t i f a c t I d > b o o t s t r a p < / a r t i f a c t I d > < v e r s i o n > 3 . 2 . 0 < / v e r s i o n > < / d e p e n d e n c y > Asset locators — webjar 24 / 101
  18. New dependency WebJar Bundle { " b u n d

    l e " : " m y - b u n d l e " , " a s s e t s " : [ { " n a m e " : " b o o t s t r a p " , " v e r s i o n " : " 3 . 2 . 0 " , " t y p e " : " c s s " , " l o c a t i o n s " : { " w e b j a r " : " b o o t s t r a p . c s s " } } ] } Asset locators — webjar 25 / 101
  19. New dependency WebJar Bundle HTML Inside a Servlet 2.0+ container:

    < l i n k r e l = " s t y l e s h e e t " h r e f = " / [ c o n t e x t P a t h ] / d a n d e l i o n - a s s e t s / [ c a c h e K e y ] / b o o t s t r a p . c s s " / > Inside a Servlet 3.0+ container: < l i n k r e l = " s t y l e s h e e t " h r e f = " / [ c o n t e x t P a t h ] / w e b j a r s / b o o t s t r a p / 3 . 2 . 0 / c s s / b o o t s t r a p . c s s " / > Dandelion automatically detects whether the running server is using the Servlet 3.x API or lower Asset locators — webjar 26 / 101
  20. Asset locators — delegate Reads the content of an asset

    from a special parameter stored inside the A s s e t R e q u e s t C o n t e x t This special parameter: must be stored under the D e l e g a t e L o c a t o r . D E L E G A T E D _ C O N T E N T _ P A R A M key must be a class that implements D e l e g a t e d C o n t e n t and where the g e t C o n t e n t ( ) method must return the asset content to be injected ] 27 / 101
  21. Bundle { " b u n d l e "

    : " m y - b u n d l e " , " a s s e t s " : [ { " n a m e " : " m y - g e n e r a t e d - a s s e t " , " v e r s i o n " : " 1 . 0 . 0 " , " t y p e " : " j s " , " l o c a t i o n s " : { " d e l e g a t e " : " a p p . j s " } } ] } Asset locators — delegate 28 / 101
  22. Bundle Generator p u b l i c c l

    a s s S o m e J a v a s c r i p t G e n e r a t o r i m p l e m e n t s D e l e g a t e d C o n t e n t { @ O v e r r i d e p u b l i c S t r i n g g e t C o n t e n t ( H t t p S e r v l e t R e q u e s t r e q u e s t ) { r e t u r n " a l e r t ( ' H e y ! ' ) ; " ; } } Asset locators — delegate 29 / 101
  23. Bundle Generator ARC A s s e t R e

    q u e s t C o n t e x t . g e t ( r e q u e s t ) . a d d P a r a m e t e r ( " m y - g e n e r a t e d - a s s e t " , D e l e g a t e L o c a t o r . D E L E G A T E D _ C O N T E N T _ P A R A M , n e w S o m e J a v a s c r i p t G e n e r a t o r ( ) ) ; Asset locators — delegate 30 / 101
  24. Bundle Generator ARC HTML < s c r i p

    t s r c = " / [ c o n t e x t P a t h ] / d a n d e l i o n - a s s e t s / [ c a c h e K e y ] / a p p . j s " > < / s c r i p t > Where a p p . j s : a l e r t ( ' H e y ! ' ) ; Asset locators — delegate 31 / 101
  25. 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
  26. Bundle graph On the application startup, Dandelion creates a C

    o n t e x t that will be injected into each request. This C o n t e x t provide several information: all configuration options (coming from the properties files) a bundle graph (DAG), built from all scanned bundles Example: s r c | _ _ m a i n | _ _ r e s o u r c e s | _ _ d a n d e l i o n | _ _ j q u e r y . j s o n | _ _ s e l e c t 2 . j s o n See the docs 33 / 101
  27. Interacting with the bundle graph 1/4) Using the JSP taglib

    < % @ t a g l i b p r e f i x = " d a n d e l i o n " u r i = " h t t p : / / g i t h u b . c o m / d a n d e l i o n " % > < d a n d e l i o n : b u n d l e i n c l u d e s = " s e l e c t 2 " / > 2/4) Using the Thymeleaf dialect < ! D O C T Y P E h t m l > < h t m l x m l n s : t h = " h t t p : / / w w w . t h y m e l e a f . o r g " x m l n s : d d l = " h t t p : / / g i t h u b . c o m / d a n d e l i o n " d d l : b u n d l e - i n c l u d e s = " s e l e c t 2 " > . . . < / h t m l > See the docs 34 / 101
  28. Interacting with the bundle graph 3/4) Using the fluent API

    A s s e t R e q u e s t C o n t e x t . g e t ( ( H t t p S e r v l e t R e q u e s t ) r e q u e s t ) . a d d B u n d l e ( " s e l e c t 2 " ) ; 4/4) Using the configuration file ("permanent" bundles) b u n d l e . i n c l u d e s = s e l e c t 2 See the docs 35 / 101
  29. Interacting with the bundle graph Whatever the technology used, Dandelion

    automatically injects all requested assets into the HTML code: in the right order in the configured position, by default CSS in < h e a d > and JS just before < / b o d y > and (soon) applies the right HTTP headers, therefore optimizing browser caching < h t m l > < h e a d > < l i n k h r e f = " / c o n t e x t / a s s e t s / c s s / s e l e c t 2 . c s s " / > < / h e a d > < b o d y > . . . < s c r i p t s r c = " / c o n t e x t / a s s e t s / j s / j q u e r y - 1 . 1 1 . 1 . j s " > < / s c r i p t > < s c r i p t s r c = " / c o n t e x t / a s s e t s / j s / s e l e c t 2 . j s " > < / s c r i p t > < / b o d y > < / h t m l > 36 / 101
  30. Asset processors Intended to process assets, in different ways... Built-in

    processors: jsMinYui:JS minification based on Yahoo's YUI Compressor cssMinYui:CSS minification based on Yahoo's YUI Compressor cssMin:CSS minification based on a fork of YUI jsMin:JS minification based on a fork of YUI cssUrlRewriting:Image URLs rewriting in CSS Soon: cssLess: Convert Less resources to CSS cssSass: Convert Sass resources to CSS cssImport: Processes @import coffeeScript: Convert CoffeeScript to JavaScript ... See the docs 37 / 101
  31. Development/production modes Development mode Built-in dev tools available Server-side caching

    disabled Browser caching disabled Production mode No bundle graph viewer, no bundle reloading Minification enabled Server-side caching enabled (soon) Browser caching enabled (soon) GZIP compression (soon) Asset versioning (soon) JMX monitoring 38 / 101
  32. Dev tools Bundle graph viewer Dev tool allowing to visualize

    how Dandelion-Core handles assets, in the current request h t t p : / / e x a m p l e . c o m / c o n t e x t / s o m e / u r i ? s h o w G r a p h Available in development mode only See the docs 39 / 101
  33. Dev tools Bundle graph viewer Asset reloading During development, both

    server-side and client-side caching are disabled. Client-side, Dandelion-Core applies the following HTTP headers: Cache-Control = n o - c a c h e , n o - s t o r e , m u s t - r e v a l i d a t e (HTTP 1.1) Pragma = n o - c a c h e (HTTP 1.0) Expires = 0 (Proxies) 40 / 101
  34. Dev tools Bundle graph viewer Asset reloading Bundle reloading During

    development, all changes made in asset bundles can be reflected. Just manually append a new r e l o a d B u n d l e s request parameter to the current URL to perform a full bundle reloading. h t t p : / / e x a m p l e . c o m / c o n t e x t / s o m e / u r i ? r e l o a d B u n d l e s Available in development mode only 41 / 101
  35. Properties dandelion.properties d a n d e l i o

    n . m o d e = p r o d u c t i o n Configuration options 42 / 101
  36. Properties Filter init param filter init param > dandelion.properties <

    f i l t e r > < f i l t e r - n a m e > d a n d e l i o n < / f i l t e r - n a m e > < f i l t e r - c l a s s > . . . D a n d e l i o n F i l t e r < / f i l t e r - c l a s s > < i n i t - p a r a m > < p a r a m - n a m e > d a n d e l i o n . m o d e < p a r a m - n a m e > < p a r a m - v a l u e > p r o d u c t i o n < / p a r a m - v a l u e > < / i n i t - p a r a m > < / f i l t e r > Configuration options 43 / 101
  37. Properties Filter init param System property system property > filter

    init param > dandelion.properties - D d a n d e l i o n . m o d e = p r o d u c t i o n Configuration options See the docs 44 / 101
  38. Introducing Dandelion-Datatables First and most advanced component of the Dandelion

    framework Facilitates the integration of DataTables, an awesome jQuery plugin which will add advanced interaction controls to any HTML table Easy to use Easy to extend Inspired by the excellent DisplayTag library 46 / 101
  39. Key features JSP & Thymeleaf support Typical features such as

    paging, filtering and sorting DOM sources, AJAX sources and server-side processing Responsive design Export in multiple formats Several themes available: Bootstrap 2, Bootstrap 3, jQueryUI I18n Integration with Spring/Spring MVC and other projects 47 / 101
  40. What it looks like with JSP? < % @ t

    a g l i b p r e f i x = " d a t a t a b l e s " u r i = " h t t p : / / g i t h u b . c o m / d a n d e l i o n / d a t a t a b l e s " % > < d a t a t a b l e s : t a b l e i d = " m y T a b l e I d " d a t a = " $ { p e r s o n s } " > < d a t a t a b l e s : c o l u m n t i t l e = " I d " p r o p e r t y = " i d " / > < d a t a t a b l e s : c o l u m n t i t l e = " L a s t N a m e " p r o p e r t y = " l a s t N a m e " / > < d a t a t a b l e s : c o l u m n t i t l e = " F i r s t N a m e " p r o p e r t y = " f i r s t N a m e " / > < d a t a t a b l e s : c o l u m n t i t l e = " C i t y " p r o p e r t y = " a d d r e s s . t o w n . n a m e " / > < d a t a t a b l e s : c o l u m n t i t l e = " M a i l " p r o p e r t y = " m a i l " / > < / d a t a t a b l e s : t a b l e > i d : HTML pass-through attribute d a t a : DOM source, collection of POJOs t i t l e : sets the content of the column header p r o p e r t y : name of the object's attribute of the collection being iterated on 48 / 101
  41. What it looks like with Thymeleaf? < t a b

    l e i d = " m y T a b l e I d " d t : t a b l e = " t r u e " > < t h e a d > < t r > < t h > I d < / t h > < t h > F i r s t n a m e < / t h > < t h > L a s t n a m e < / t h > < t h > C i t y < / t h > < t h > M a i l < / t h > < / t r > < / t h e a d > < t b o d y > < t r t h : e a c h = " p e r s o n : $ { p e r s o n s } " > < t d t h : t e x t = " $ { p e r s o n . i d } " > 1 < / t d > < t d t h : t e x t = " $ { p e r s o n . f i r s t N a m e } " > J o h n < / t d > < t d t h : t e x t = " $ { p e r s o n . l a s t N a m e } " > D o e < / t d > < t d t h : t e x t = " $ { p e r s o n ? . a d d r e s s ? . t o w n ? . n a m e } " > N o b o d y k n o w s ! < / t d > < t d t h : t e x t = " $ { p e r s o n . m a i l } " > j o h n @ d o e . c o m < / t d > < / t r > < / t b o d y > < / t a b l e > d t : t a b l e : enables the Dandelion-Datatables dialect in the current table 49 / 101
  42. HTML The HTML is generated: either by Dandelion-Datatables (JSP) or

    directly by Thymeleaf < t a b l e i d = " m y T a b l e I d " > < t h e a d > < t r > < t h > I d < / t h > < t h > F i r s t n a m e < / t h > < t h > L a s t n a m e < / t h > < t h > C i t y < / t h > < t h > M a i l < / t h > < / t r > < / t h e a d > < t b o d y > < t r > < t d > 1 < / t d > < t d > W i n g < / t d > < t d > C u n n i n g h a m < / t d > < t d > < / t d > < t d > o r n a r e . l i b e r o @ m a i l . e d u < / t d > < / t r > . . . < / t b o d y > < / t a b l e > How it works? 50 / 101
  43. HTML JavaScript As well as the JS code that initializes

    DataTables v a r o T a b l e _ m y T a b l e I d = $ ( ' # m y T a b l e I d ' ) ; v a r o T a b l e _ m y T a b l e I d _ p a r a m s = { " a o C o l u m n s " : [ { " m D a t a " : " i d " , " s D e f a u l t C o n t e n t " : " " } , { " m D a t a " : " l a s t N a m e " , " s D e f a u l t C o n t e n t " : " " } , { " m D a t a " : " f i r s t N a m e " , " s D e f a u l t C o n t e n t " : " " } , { " m D a t a " : " a d d r e s s . t o w n . n a m e " , " s D e f a u l t C o n t e n t " : " " } , { " m D a t a " : " m a i l " , " s D e f a u l t C o n t e n t " : " " } ] } $ ( d o c u m e n t ) . r e a d y ( f u n c t i o n ( ) { o T a b l e _ m y T a b l e I d . d a t a T a b l e ( o T a b l e _ m y T a b l e I d _ p a r a m s ) ; } ) ; How it works? 51 / 101
  44. HTML JavaScript Required assets An A s s e t

    R e q u e s t C o n t e x t is filled with the required assets, either by the JSP taglib or by the Thymeleaf dialect... A s s e t R e q u e s t C o n t e x t . g e t ( r e q u e s t ) . a d d B u n d l e ( " d a t a t a b l e s " ) . a d d B u n d l e ( " d d l - d t " ) . . . ; ... so that they will be injected by Dandelion-Core into the response < l i n k h r e f = " / / c d n / j q u e r y . d a t a T a b l e s . c s s " / > . . . < s c r i p t s r c = " / / c d n / j q u e r y . j s " > < / s c r i p t > < s c r i p t s r c = " / / c d n / j q u e r y . d a t a T a b l e s . j s " > < / s c r i p t > < s c r i p t s r c = " / [ c o n t e x t P a t h ] / d a n d e l i o n - a s s e t s / [ S H A ] / d a n d e l i o n - d a t a t a b l e s - 0 . 1 0 . 0 . j s " > < / s c r i p t > How it works? 52 / 101
  45. HTML (DOM) sources Read data directly from the DOM Works

    well with small/medium data sources 54 / 101
  46. Controller Example with a Spring MVC controller @ C o

    n t r o l l e r p u b l i c c l a s s C o n t r o l l e r { @ M o d e l A t t r i b u t e ( " p e r s o n s " ) p u b l i c L i s t < P e r s o n > p o p u l a t e T a b l e ( ) { r e t u r n p e r s o n S e r v i c e . f i n d A l l ( ) ; } } HTML sources — example 55 / 101
  47. Controller JSP < d a t a t a b

    l e s : t a b l e i d = " m y T a b l e I d " d a t a = " $ { p e r s o n s } " > < d a t a t a b l e s : c o l u m n t i t l e = " I d " p r o p e r t y = " i d " / > . . . < / d a t a t a b l e s : t a b l e > HTML sources — example 56 / 101
  48. Controller JSP Thymeleaf < t a b l e i

    d = " m y T a b l e I d " d t : t a b l e = " t r u e " > . . . < t b o d y > < t r t h : e a c h = " p e r s o n : $ { p e r s o n s } " > < t d t h : t e x t = " $ { p e r s o n . i d } " > 1 < / t d > . . . < / t r > < / t b o d y > < t a b l e > HTML sources — example 57 / 101
  49. AJAX sources Read data from virtually any JSON data source

    that can be obtained by AJAX Client-side processing Works well with small/medium data sources 58 / 101
  50. Controller Example with a Spring MVC controller @ C o

    n t r o l l e r p u b l i c c l a s s A j a x C o n t r o l l e r { @ R e q u e s t M a p p i n g ( v a l u e = " / p e r s o n s " ) p u b l i c @ R e s p o n s e B o d y L i s t < P e r s o n > f i n d A l l ( ) { r e t u r n p e r s o n S e r v i c e . f i n d A l l ( ) ; } } AJAX sources 59 / 101
  51. Controller JSP < d a t a t a b

    l e s : t a b l e i d = " m y T a b l e I d " u r l = " / p e r s o n s " > < d a t a t a b l e s : c o l u m n t i t l e = " I d " p r o p e r t y = " i d " / > . . . < / d a t a t a b l e s : t a b l e > Dandelion-Datatables rewrites URLs by appending the context path, if needed. AJAX sources 60 / 101
  52. Controller JSP Thymeleaf < t a b l e i

    d = " m y T a b l e I d " d t : t a b l e = " t r u e " d t : u r l = " @ { / p e r s o n s } " > . . . < t b o d y > < t r t h : e a c h = " p e r s o n : $ { p e r s o n s } " > < t d t h : t e x t = " $ { p e r s o n . i d } " > 1 < / t d > . . . < / t r > < / t b o d y > < t a b l e > AJAX sources 61 / 101
  53. AJAX sources + server-side processing Read data from virtually any

    JSON data source that can be obtained by AJAX Server-side processing Each draw of the table will result in a new AJAX request being made to get the required data Works well with small/medium/large data sources 62 / 101
  54. AJAX sources + server-side processing Dandelion-Datatables provides a convenient API

    D a t a t a b l e s C r i t e r i a s Stores all DataTables parameters (current page, entries to display, sorted columns, ...) @ R e q u e s t M a p p i n g ( v a l u e = " / p e r s o n s " ) p u b l i c @ R e s p o n s e B o d y D a t a t a b l e s R e s p o n s e < P e r s o n > f i l t e r ( H t t p S e r v l e t R e q u e s t r e q u e s t ) { / / M a p s r e q u e s t p a r a m e t e r t o a D a t a t a b l e s C r i t e r i a s i n s t a n c e D a t a t a b l e s C r i t e r i a s c r i t e r i a s = D a t a t a b l e s C r i t e r i a s . g e t F r o m R e q u e s t ( r e q u e s t ) ; . . . 63 / 101
  55. AJAX sources + server-side processing Dandelion-Datatables provides a convenient API

    D a t a S e t All entries returned by the data access layer should be wrapped in this class in order to build a D a t a T a b l e s R e s p o n s e . . . / / G e t f i l t e r e d a n d p a g e d d a t a D a t a S e t < P e r s o n > p e r s o n s = p e r s o n S e r v i c e . f i n d P e r s o n s ( c r i t e r i a s ) ; . . . 64 / 101
  56. AJAX sources + server-side processing Dandelion-Datatables provides a convenient API

    D a t a T a b l e s R e s p o n s e Contains a builder that helps to return the data in the format required by DataTables Must be converted into JSON . . . / / B u i l d t h e r e s p o n s e t h a t w i l l b e c o n v e r t e d t o J S O N r e t u r n D a t a t a b l e s R e s p o n s e . b u i l d ( p e r s o n s , c r i t e r i a s ) ; } 65 / 101
  57. Controller Example with a Spring MVC AJAX controller @ R

    e q u e s t M a p p i n g ( v a l u e = " / p e r s o n s " ) p u b l i c @ R e s p o n s e B o d y D a t a t a b l e s R e s p o n s e < P e r s o n > f i l t e r ( H t t p S e r v l e t R e q u e s t r e q u e s t ) { / / M a p s r e q u e s t p a r a m e t e r t o a D a t a t a b l e s C r i t e r i a s i n s t a n c e D a t a t a b l e s C r i t e r i a s c r i t e r i a s = D a t a t a b l e s C r i t e r i a s . g e t F r o m R e q u e s t ( r e q u e s t ) ; / / G e t f i l t e r e d a n d p a g e d d a t a D a t a S e t < P e r s o n > p e r s o n s = p e r s o n S e r v i c e . f i n d P e r s o n s ( c r i t e r i a s ) ; / / B u i l d t h e r e s p o n s e t h a t w i l l b e c o n v e r t e d t o J S O N r e t u r n D a t a t a b l e s R e s p o n s e . b u i l d ( p e r s o n s , c r i t e r i a s ) ; } AJAX sources + server-side processing 66 / 101
  58. Controller JSP < d a t a t a b

    l e s : t a b l e . . . u r l = " / p e r s o n s " s e r v e r S i d e = " t r u e " > < d a t a t a b l e s : c o l u m n p r o p e r t y = " i d " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " f i r s t N a m e " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " l a s t N a m e " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " a d d r e s s . t o w n . n a m e " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " m a i l " / > < / d a t a t a b l e s : t a b l e > AJAX sources + server-side processing 67 / 101
  59. Controller JSP Thymeleaf < t a b l e .

    . . d t : u r l = " @ { / p e r s o n s } " d t : s e r v e r S i d e = " t r u e " > < t h e a d > < t r > < t h d t : p r o p e r t y = " i d " > I d < / t h > < t h d t : p r o p e r t y = " f i r s t N a m e " > F i r s t n a m e < / t h > < t h d t : p r o p e r t y = " l a s t N a m e " > L a s t n a m e < / t h > < t h d t : p r o p e r t y = " a d d r e s s . t o w n . n a m e " > C i t y < / t h > < t h d t : p r o p e r t y = " m a i l " > M a i l < / t h > < / t r > < / t h e a d > < / t a b l e > AJAX sources + server-side processing 68 / 101
  60. JSP < d a t a t a b l

    e s : t a b l e . . . p a g e a b l e = " f a l s e " > < d a t a t a b l e s : c o l u m n . . . s o r t a b l e = " f a l s e " / > < d a t a t a b l e s : c o l u m n . . . f i l t e r a b l e = " t r u e " / > . . . < / d a t a t a b l e s : t a b l e > Paging, sorting, filtering 69 / 101
  61. JSP Thymeleaf < t a b l e . .

    . d t : p a g e a b l e = " f a l s e " > < t h e a d > < t h d t : s o r t a b l e = " f a l s e " > I d < / t h > < t h d t : f i l t e r a b l e = " t r u e " > L a s t N a m e < / t h > . . . < / t h e a d > . . . < t a b l e > Paging, sorting, filtering 70 / 101
  62. 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 format is enabled the corresponding library in compile scope (e.g. Apache POI for the XLS format) Available extras: PDF: datatables-export-itext XLS: datatables-export-poi XLSX: datatables-export-poi-ooxml 72 / 101
  63. Export — 2 ways Filter-based Fast to set up Always

    export full data source Only compatible with DOM sources Controller-based Requires a bit more work to set up WYSIWYE => What You See Is What You ... Export! Compatible with DOM and AJAX sources 73 / 101
  64. New dependency < d e p e n d e

    n c y > < g r o u p I d > c o m . g i t h u b . d a n d e l i o n < / g r o u p I d > < a r t i f a c t I d > d a t a t a b l e s - e x p o r t - i t e x t < / a r t i f a c t I d > < v e r s i o n > 0 . 1 0 . 0 < / v e r s i o n > < / d e p e n d e n c y > Export — filter-based 74 / 101
  65. New dependency web.xml < ! - - D a n

    d e l i o n - D a t a t a b l e s f i l t e r u s e d f o r b a s i c e x p o r t - - > < f i l t e r > < f i l t e r - n a m e > d a t a t a b l e s < / f i l t e r - n a m e > < f i l t e r - c l a s s > . . . D a t a t a b l e s F i l t e r < / f i l t e r - c l a s s > < / f i l t e r > < f i l t e r - m a p p i n g > < f i l t e r - n a m e > d a t a t a b l e s < / f i l t e r - n a m e > < u r l - p a t t e r n > / * < / u r l - p a t t e r n > < / f i l t e r - m a p p i n g > Export — filter-based 75 / 101
  66. New dependency web.xml JSP < d a t a t

    a b l e s : t a b l e . . . e x p o r t = " p d f " > < d a t a t a b l e s : c o l u m n p r o p e r t y = " i d " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " f i r s t N a m e " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " l a s t N a m e " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " a d d r e s s . t o w n . n a m e " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " m a i l " / > < / d a t a t a b l e s : t a b l e > Export — filter-based 76 / 101
  67. New dependency web.xml JSP Thymeleaf < t a b l

    e i d = " m y T a b l e " d t : t a b l e = " t r u e " d t : e x p o r t = " p d f " > < t h e a d > < t r > < t h > I d < / t h > < t h > F i r s t n a m e < / t h > < t h > L a s t n a m e < / t h > < t h > C i t y < / t h > < t h > M a i l < / t h > < / t r > < / t h e a d > < t b o d y > < t r t h : e a c h = " p e r s o n : $ { p e r s o n s } " > < t d t h : t e x t = " $ { p e r s o n . i d } " > 1 < / t d > < t d t h : t e x t = " $ { p e r s o n . f i r s t N a m e } " > J o h n < / t d > < t d t h : t e x t = " $ { p e r s o n . l a s t N a m e } " > D o e < / t d > < t d t h : t e x t = " $ { p e r s o n . a d d r e s s . t o w n . n a m e } " > N o b o d y k n o w s ! < / t d > < t d t h : t e x t = " $ { p e r s o n . m a i l } " > j o h n @ d o e . c o m < / t d > < / t r > < / t b o d y > < / t a b l e > Export — filter-based 77 / 101
  68. New dependency < d e p e n d e

    n c y > < g r o u p I d > c o m . g i t h u b . d a n d e l i o n < / g r o u p I d > < a r t i f a c t I d > d a t a t a b l e s - e x p o r t - i t e x t < / a r t i f a c t I d > < v e r s i o n > 0 . 1 0 . 0 < / v e r s i o n > < / d e p e n d e n c y > Export — controller-based 78 / 101
  69. New dependency JSP < d a t a t a

    b l e s : t a b l e i d = " m y T a b l e I d " u r l = " / p e r s o n s " e x p o r t = " p d f " > < d a t a t a b l e s : c o l u m n p r o p e r t y = " i d " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " f i r s t N a m e " / > . . . < d a t a t a b l e s : e x p o r t t y p e = " c s v " u r l = " / e x p o r t . p d f " / > < / d a t a t a b l e s : t a b l e > Export — controller-based 79 / 101
  70. New dependency JSP Thymeleaf < d i v d t

    : c o n f = " m y T a b l e I d " > < d i v d t : c o n f T y p e = " e x p o r t " d t : t y p e = " p d f " d t : u r l = " @ { / e x p o r t . p d f } " > < / d i v > < / d i v > < t a b l e . . . d t : u r l = " @ { / p e r s o n s } " d t : e x p o r t = " p d f " > < t h e a d > < t r > < t h d t : p r o p e r t y = " i d " > I d < / t h > < t h d t : p r o p e r t y = " f i r s t N a m e " > F i r s t n a m e < / t h > < t h d t : p r o p e r t y = " l a s t N a m e " > L a s t n a m e < / t h > < t h d t : p r o p e r t y = " a d d r e s s . t o w n . n a m e " > C i t y < / t h > < t h d t : p r o p e r t y = " m a i l " > M a i l < / t h > < / t r > < / t h e a d > < / t a b l e > Export — controller-based 80 / 101
  71. New dependency JSP Thymeleaf Controller (1/4) @ R e q

    u e s t M a p p i n g ( v a l u e = " / e x p o r t " , p r o d u c e s = " a p p l i c a t i o n / p d f " ) p u b l i c v o i d p d f ( @ D a t a t a b l e s P a r a m s D a t a t a b l e s C r i t e r i a s c r i t e r i a s , H t t p S e r v l e t R e q u e s t r e q u e s t , H t t p S e r v l e t R e s p o n s e r e s p o n s e ) { / / G e t d a t a t o e x p o r t u s i n g t h e p r o v i d e d c r i t e r i a L i s t < P e r s o n > p e r s o n s = p e r s o n S e r v i c e . f i n d P e r s o n s ( c r i t e r i a s ) ; . . . Export — controller-based 81 / 101
  72. New dependency JSP Thymeleaf Controller (2/4) . . . /

    / B u i l d t h e e x p o r t c o n f i g u r a t i o n E x p o r t C o n f e x p o r t P d f C o n f = n e w E x p o r t C o n f . B u i l d e r ( " p d f " ) . h e a d e r ( t r u e ) . e x p o r t C l a s s ( n e w P d f E x p o r t ( ) ) . b u i l d ( ) ; . . . Export — controller-based 82 / 101
  73. New dependency JSP Thymeleaf Controller (3/4) . . . /

    / B u i l d t h e t a b l e t o e x p o r t u s i n g t h e a b o v e d a t a / / a n d t h e e x p o r t c o n f i g u r a t i o n H t m l T a b l e t a b l e = n e w H t m l T a b l e B u i l d e r < P e r s o n > ( ) . n e w B u i l d e r ( " t a b l e I d " , p e r s o n s , r e q u e s t , e x p o r t P d f C o n f ) . c o l u m n ( ) . f i l l W i t h P r o p e r t y ( " i d " ) . t i t l e ( " I d " ) . c o l u m n ( ) . f i l l W i t h P r o p e r t y ( " f i r s t N a m e " ) . t i t l e ( " F i r t n a m e " ) . c o l u m n ( ) . f i l l W i t h P r o p e r t y ( " l a s t N a m e " ) . t i t l e ( " L a s t n a m e " ) . c o l u m n ( ) . f i l l W i t h P r o p e r t y ( " a d d r e s s . t o w n . n a m e " ) . t i t l e ( " C i t y " ) . c o l u m n ( ) . f i l l W i t h P r o p e r t y ( " m a i l " ) . t i t l e ( " M a i l " ) . c o l u m n ( ) . f i l l W i t h P r o p e r t y ( " b i r t h D a t e " , " { 0 , d a t e , d d - M M - y y y y } " ) . t i t l e ( " B i r t h D a t e " ) . b u i l d ( ) ; . . . Export — controller-based 83 / 101
  74. New dependency JSP Thymeleaf Controller (4/4) . . . /

    / R e n d e r t h e e x p o r t f i l e i n t h e b r o w s e r E x p o r t U t i l s . r e n d e r E x p o r t ( t a b l e , e x p o r t P d f C o n f , r e s p o n s e ) ; } Export — controller-based 84 / 101
  75. I18n: DataTables' information datatables.properties: non-translatable properties g l o b

    a l . c s s . c l a s s = t a b l e t a b l e - s t r i p e d t a b l e - b o r d e r e d t a b l e - c o n d e n s e d g l o b a l . e x t r a . t h e m e = b o o t s t r a p 2 datatables_EN.properties: all EN translations g l o b a l . i 1 8 n . m s g . p r o c e s s i n g = P r o c e s s i n g . . . g l o b a l . i 1 8 n . m s g . s e a r c h = S e a r c h : g l o b a l . i 1 8 n . m s g . i n f o = S h o w i n g _ S T A R T _ t o _ E N D _ o f _ T O T A L _ e n t r i e s datatables_FR.properties: all FR translations g l o b a l . i 1 8 n . m s g . p r o c e s s i n g = T r a i t e m e n t e n c o u r s . . . g l o b a l . i 1 8 n . m s g . s e a r c h = R e c h e r c h e r : g l o b a l . i 1 8 n . m s g . i n f o = A f f i c h a g e d e l ' é l é m e n t _ S T A R T _ à _ E N D _ s u r _ T O T A L _ é l é m e n t s 85 / 101
  76. I18n: column headers Based on L o c a l

    e R e s o l v e r and M e s s a g e R e s o l v e r interfaces Built-in implementations: S p r i n g L o c a l e R e s o l v e r / S p r i n g M e s s a g e R e s o l v e r J s t l L o c a l e R e s o l v e r / J s t l M e s s a g e R e s o l v e r S t r u t s 1 L o c a l e R e s o l v e r / S t r u t s 1 M e s s a g e R e s o l v e r S t r u t s 2 L o c a l e R e s o l v e r / S t r u t s 2 M e s s a g e R e s o l v e r Possible to plug-in custom locale and message resolvers 86 / 101
  77. Spring config < b e a n i d =

    " m e s s a g e S o u r c e " c l a s s = " . . . " > < p r o p e r t y n a m e = " b a s e n a m e " v a l u e = " c l a s s p a t h : m e s s a g e s " / > < / b e a n > I18n: example with Spring 87 / 101
  78. Spring config Resource bundles Location: s r c | _

    _ m a i n | _ _ r e s o u r c e s | _ _ m e s s a g e s . p r o p e r t i e s | _ _ m e s s a g e s _ F R . p r o p e r t i e s messages.properties: t a b l e . h e a d e r . l a s t n a m e = L a s t n a m e t a b l e . h e a d e r . f i r s t n a m e = F i r s t n a m e messages_FR.properties: t a b l e . h e a d e r . l a s t n a m e = N o m t a b l e . h e a d e r . f i r s t n a m e = P r é n o m I18n: example with Spring 88 / 101
  79. Spring config Resource bundles JSP < d a t a

    t a b l e s : t a b l e i d = " m y T a b l e I d " d a t a = " $ { p e r s o n s } " > . . . < d a t a t a b l e s : c o l u m n t i t l e K e y = " t a b l e . h e a d e r . f i r s t n a m e " . . . / > < d a t a t a b l e s : c o l u m n t i t l e K e y = " t a b l e . h e a d e r . l a s t n a m e " . . . / > . . . < / d a t a t a b l e s : t a b l e > I18n: example with Spring 89 / 101
  80. Spring config Resource bundles JSP Thymeleaf < t a b

    l e i d = " m y T a b l e I d " d t : t a b l e = " t r u e " > < t h e a d > < t r > . . . < t h t h : t e x t = " # { t a b l e . h e a d e r . f i r s t n a m e } " > F i r s t n a m e < / t h > < t h t h : t e x t = " # { t a b l e . h e a d e r . l a s t n a m e } " > L a s t n a m e < / t h > . . . < / t r > < / t h e a d > . . . < / t a b l e > I18n: example with Spring 90 / 101
  81. JSP < d a t a t a b l

    e s : t a b l e . . . t h e m e = " b o o t s t r a p 3 " c s s C l a s s = " t a b l e " > < d a t a t a b l e s : c o l u m n p r o p e r t y = " i d " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " f i r s t N a m e " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " l a s t N a m e " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " a d d r e s s . t o w n . n a m e " / > < d a t a t a b l e s : c o l u m n p r o p e r t y = " m a i l " / > < / d a t a t a b l e s : t a b l e > Theming 92 / 101
  82. JSP Thymeleaf < t a b l e . .

    . d t : t h e m e = " b o o t s t r a p 3 " c l a s s = " t a b l e " > < t h e a d > < t r > < t h > I d < / t h > < t h > F i r s t n a m e < / t h > < t h > L a s t n a m e < / t h > < t h > S t r e e t < / t h > < t h > M a i l < / t h > < / t r > < / t h e a d > < t b o d y > < t r t h : e a c h = " p e r s o n : $ { p e r s o n s } " > < t d t h : t e x t = " $ { p e r s o n ? . i d } " > 1 < / t d > < t d t h : t e x t = " $ { p e r s o n ? . f i r s t N a m e } " > J o h n < / t d > < t d t h : t e x t = " $ { p e r s o n ? . l a s t N a m e } " > D o e < / t d > < t d t h : t e x t = " $ { p e r s o n ? . a d d r e s s ? . t o w n ? . n a m e } " > N o b o d y k n o w s ! < / t d > < t d t h : t e x t = " $ { p e r s o n ? . m a i l } " > j o h n @ d o e . c o m < / t d > < / t r > < / t b o d y > < / t a b l e > Theming 93 / 101
  83. Some statistics 35 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
  84. Dandelion- Core Full support for asset minification and merging Improvements

    on asset bundles: externalization, configuration via XML, JavaConfig Add new processors for meta-frameworks (CoffeeScript, Less, ...) Add support for conditionnal assets (e.g. IE8+, IE9+) Add support for CSS sprites New A s s e t C a c h e implementation based on Hazelcast JBoss Forge plugin allowing to scaffold a project based on Dandelion Add support for RequireJS Bower integration Future 97 / 101
  85. Dandelion- Core Dandelion- Datatables New extension for editable tables (Editor,

    jEditable, ...) Add support for more DataTables' extensions Add support for DataTables 1.10.0 New theme for Foundation Add WebSocket support for continously-updating tables (Atmosphere, Spring MVC 4) Add support for Spring Data REST Future 98 / 101