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

Isomorphic templating with Spring Boot, Nashorn and React

Isomorphic templating with Spring Boot, Nashorn and React

After an introduction presenting the upcoming Spring Framework 4.2 Script Templating support, this talk will show, with code samples, how to develop an application performing the same templates rendering on client AND server based on Spring Boot, Nashorn and Javascript based template engines like React (the latest game changer Javascript library released by Facebook).

The rendering of Javascript templates is performed initially on server-side thanks to a Spring MVC + Nashorn integration, then enriched on client side with a push mechanism (Websocket or Server-Sent Events).

This kind of isomorphic templating + the disruptive innovation brought by React with his virtual DOM mechanism make it possible to build a new kind of applications : responsive, with a great UX while being accessible.

Sébastien Deleuze

September 16, 2015
Tweet

More Decks by Sébastien Deleuze

Other Decks in Programming

Transcript

  1. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ SPRINGONE2GX WASHINGTON, DC Isomorphic templating with
 Spring Boot, Nashorn and React Sébastien Deleuze @sdeleuze
  2. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Agenda • Isomorphic? • Script based templating support in Spring • Handlebars support • What is React? • Isomorphic application with Spring and React • Demo • What’s next? 2
  3. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Isomorphic? 3
  4. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Isomorphic 4 Shared code that runs on both the client & server
  5. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Use cases • Templating - User interface • I18n • Application logic • Routing • Model validation 5
  6. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Why? 1. Performance • Initial pageload speed • Huge impact on mobile 2. Maintainability • Share more code between client and server • A single technology to learn 3. SEO - Accessibility • Make your site more crawlable and accessible 6
  7. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Principle 7 Server Client Ȑ Content + UI Content + UI +
 DOM event listeners
  8. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Your website is … 8 Application
 centric Content
 centric
  9. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ GitHub as an example 9
  10. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Script based templating
 support in Spring 10
  11. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Support JSR 223 script engines 11 https://jira.spring.io/browse/SPR-12266: Support JavaScript Templating
  12. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Nashorn • Bundled with JRE 8+ • Evolve fast • Min. requirement: Java 8u66 12
  13. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Nashorn code sample 13 ScriptEngineManager manager = new ScriptEngineManager();
 ScriptEngine engine = manager.getEngineByName("nashorn");
 Invocable invocable = (Invocable)engine;
 
 String result = (String)invocable.invokeFunction("hello", "Brian"); function hello(name) {
 return "Hello " + name;
 }
  14. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Available in Spring Framework 4.2 14 And in the upcoming Spring Boot 1.3 GA
  15. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Javascript based template engines 15 Mustache
  16. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Handlebars templates 16 <html>
 <head>
 <title>{{title}}</title>
 </head>
 <body>
 <ul>
 {{#each comments}}
 <li>{{author}} {{content}}</li>
 {{/each}}
 </ul>
 </body>
 </html>
  17. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring MVC controller 17 @Controller
 public class HandlebarsController {
 
 @RequestMapping(path = "/home", method = RequestMethod.GET)
 String home(Model model) {
 model.addAttribute("title", "Title example");
 List comments = Arrays.asList(
 new Comment("author1", "content1"),
 new Comment("author2", "content2"),
 new Comment("author3", "content3"));
 model.addAttribute("comments", comments);
 return "home";
 }
 }
  18. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring MVC controller revisited 18 @Controller
 public class HandlebarsController {
 
 @RequestMapping(path = "/home", method = RequestMethod.GET)
 Map<String, ?> home() {
 return hash(title -> "Title example",
 comments -> asList(
 new Comment("author1", "content1"),
 new Comment("author2", "content2"),
 new Comment("author3", "content3"))
 );
 }
 } View name guessed from the URL
 thanks to RequestToViewNameTranslator Hash literal using java 8u60 with -parameters and lambda type references
  19. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring MVC controller re-revisited 19 @Controller
 public class HandlebarsController {
 
 @Get("/home")
 Map<String, ?> home() {
 return hash(title -> "Title example",
 comments -> asList(
 new Comment("author1", "content1"),
 new Comment("author2", "content2"),
 new Comment("author3", "content3"))
 );
 }
 } spring-composed annotation based on @AliasFor https://github.com/sbrannen/spring-composed
  20. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Dependency Management 20 <dependency>
 <groupId>org.webjars</groupId>
 <artifactId>handlebars</artifactId>
 <version>3.0.0-1</version>
 </dependency>
  21. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Script based templating configuration 21 @Bean
 ViewResolver viewResolver() {
 ScriptTemplateViewResolver viewResolver = new ScriptTemplateViewResolver();
 viewResolver.setPrefix("/static/templates/");
 viewResolver.setSuffix(".html");
 return viewResolver;
 } View resolver
  22. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Script based templating configuration 22 @Bean
 ScriptTemplateConfigurer configurer() {
 ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
 configurer.setEngineName("nashorn");
 configurer.setScripts("/static/polyfill.js",
 "/META-INF/resources/webjars/handlebars/3.0.0-1/handlebars.js",
 "/static/render.js");
 configurer.setRenderFunction("render");
 configurer.setSharedEngine(false);
 return configurer;
 } Configurer
  23. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Concurrency with Nashorn 23 • In web browsers, no simultaneous execution of your code • Nashorn itself is NOT thread-safe by design • The behavior depends of your Javascript code • Worth to read Nashorn Multithreading and MT-safety
  24. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ The sharedEngine property 24 • When sharedEngine is set to false, Spring uses ThreadLocal<ScriptEngine> • Handlebars and React need sharedEngine=false • Mustache works perfectly with a single ScriptEngine (defaults) • Be careful on memory consumption
  25. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ polyfill.js 25 var window = {};
  26. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ render.js 26 /** String template: the template content Map model: the view model String url: the template url (since 4.2.2) **/ function render(template, model, url) {
 // ...
 }
 
 // Since url is optional, you can also declare: function render(template, model) {
 // ...
 }
  27. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Handlebars render() implementation 27 var templates = {};
 
 function render(template, model, url) {
 var compiledTemplate;
 if (templates[url] === undefined) {
 compiledTemplate = Handlebars.compile(template);
 templates[url] = compiledTemplate;
 }
 else {
 compiledTemplate = templates[url];
 }
 return compiledTemplate(toJsonObject(model));
 }
 
 // Create a real JSON object from the model Map
 function toJsonObject(model) { … }
  28. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Model to JSON Object conversion 28 // Create a real JSON object from the model Map
 function toJsonObject(model) {
 var o = {};
 for (var k in model) {
 // Convert Iterable like List to real JSON array
 if (model[k] instanceof Java.type("java.lang.Iterable")) {
 o[k] = Java.from(model[k]);
 }
 else {
 o[k] = model[k];
 
 }
 }
 return o;
 }
  29. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Is it fast? 29
  30. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Yes :-) 30 6000 page/s on my laptop
  31. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring MVC + Handlebars production ready ? 31 • Nice to use • handlebars-layouts • Easy to customize • Quite fast • Young stack • Latest Java 8 needed • Load partials from classpath nashorn.eval(new InputStreamReader(getClass().getResourceAsStream("file.js")));
  32. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Experiment, contribute! 32 https://github.com/sdeleuze/spring-boot-sample-web-handlebars
  33. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ What is React? 33
  34. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 34 • A Javascript library for building user interfaces • Component oriented • Not a full-stack framework • Virtual DOM diffing/updating • Server side rendering
  35. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ DOM diffing 35 http://techblog.constantcontact.com/software-development/reactive-component-based-uis/
  36. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ It’s Like Source Control for the DOM 36
  37. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Before showing you JSX code … 37
  38. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ React component: comment.js 38 var Comment = React.createClass({
 handleClick: function(event) {
 alert(this.props.content);
 },
 render: function () {
 return (
 <div className="col-md-4">
 <h2>{ this.props.author }</h2>
 <p>{ this.props.content } </p>
 <p><a className="btn btn-default » href="#" role=« button" onClick={ this.handleClick }>View details &raquo; </a> </p>
 </div>
 )
 }
 });
  39. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ JSX transformer 39 <div className="col-md-4">
 <h2>{ this.props.author }</h2>
 <p>{ this.props.content } </p>
 <p><a className="btn btn-default" href="#" role=« button" onClick={ this.handleClick }>View details &raquo;</a></p>
 </div> React.createElement("div", {className: "col-md-4"}, 
 React.createElement("h2", null, this.props.author), 
 React.createElement("p", null, this.props.content, " "), 
 React.createElement("p", null, React.createElement("a", {className: "btn btn-default", href: "#", role: "button", onClick: this.handleClick}, "View details") )
 )
  40. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ The most interesting man in the world about JSX … 40
  41. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ React component: comment-list.js 41 var CommentList = React.createClass({
 getInitialState: function () {
 return this.props;
 },
 render: function () {
 var commentNodes = this.state.comments.map(function (comment) {
 return <Comment author={ comment.author }
 content={ comment.content }
 key={ comment.id } />
 });
 return (
 <div className="comment-list">
 { commentNodes }
 </div>
 )}});
 
 React.render(<CommentList comments={ data }/>,
 document.getElementById("comments"));
  42. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Isomorphic application
 with Spring and React 42
  43. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Gradle configuration 43 apply plugin: 'java'
 apply plugin: 'spring-boot'
 plugins {
 id 'net.eikehirsch.react' version '0.3.1'
 }
 
 sourceCompatibility = 1.8
 targetCompatibility = 1.8
 
 dependencies {
 compile('org.springframework.boot:spring-boot-starter-web')
 compile('org.webjars:react:0.13.1')
 testCompile('org.springframework.boot:spring-boot-starter-test')
 }
 
 jsx {
 sourcesDir = 'src/main/resources/static/jsx'
 destDir = 'src/main/resources/static/output'
 } processResources.dependsOn('jsx')
  44. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Page composition 44
  45. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Controller 45 @Controller
 public class CommentController {
 
 private CommentRepository commentRepository;
 
 @Autowired
 CommentController(CommentRepository commentRepository) {
 this.commentRepository = commentRepository;
 }
 
 @RequestMapping("/")
 String render(Model model) {
 model.addAttribute("title", "Layout example");
 model.addAttribute("comments", this.commentRepository.findAll());
 return "index";
 }
 }
  46. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ index.ejs 46 <!DOCTYPE html>
 <html lang="en">
 <head><!-- ... --></head>
 <body>
 <nav class="navbar navbar-inverse navbar-fixed-top">
 <div class="container">
 <div id="navbar" class="navbar-collapse collapse">
 <%= React.renderToString(React.createElement(CommentForm)) %>
 </div>
 </div>
 </nav>
 <div class="container">
 <div id="comments" class="row">
 <%= React.renderToString(React.createElement(CommentList, { comments: comments} )) %>
 </div>
 </div>
 <script src="lib/js/jquery.min.js"></script>
 <script src="lib/js/bootstrap.min.js"></script>
 <script src="webjars/react/0.13.1/react.js"></script>
 <script src="output/comment.js"></script>
 <<!-- ... -->
 </body>
 </html>
  47. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Server side rendering 47 <div id="navbar" class="navbar-collapse collapse">
 <%= React.renderToString(React.createElement(CommentForm)) %>
 </div> <div id="navbar" class="navbar-collapse collapse">
 <form class="navbar-form navbar-right" data-reactid=".1ptxdrtnx2v" data-react-checksum="382509970">
 <div class="form-group" data-reactid=".1ptxdrtnx2v.0">
 <input placeholder="Your name" class="form-control" data-reactid=".1ptxdrtnx2v.0.0"></div>
 <div class="form-group" data-reactid=".1ptxdrtnx2v.1">
 <input placeholder="Say something..." class="form-control " data-reactid=".1ptxdrtnx2v.1.0">
 </div>
 <button type="submit" class="btn btn-success" data-reactid=".1ptxdrtnx2v.2">Post comment</button>
 </form>
 </div>
  48. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ client.js (client side rendering) 48 React.render( <CommentForm onCommentSubmit={ function(comment) {
 $.post('/', comment, null, ‘json'); }}/>, document.getElementById("navbar"));
 
 $.getJSON('/', function( data ) {
 React.render(<CommentList comments={ data }/>, document.getElementById("comments"));
 });
  49. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Server and client side = same output 49 React re-render everything BUT: - No flickering thanks to Virtual DOM diff - React just attach the DOM listeners
  50. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ polyfill.js 50 var global = this;
 var console = {};
 console.debug = print;
 console.warn = print;
 console.log = print;
  51. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ render.js 51 function render(template, model) {
 var data = toJsonObject(model);
 return new EJS({text: template}).render(data);
 }
  52. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Issue: script duplication 52 <script src="lib/js/jquery.min.js"></script>
 <script src="lib/js/bootstrap.min.js"></script>
 <script src="webjars/react/0.13.1/react.js"></script>
 <script src="output/comment.js"></script>
 <script src="output/comment-list.js"></script>
 <script src="output/comment-form.js"></script>
 <script src="output/client.js"></script> configurer.setScripts("static/polyfill.js",
 "static/lib/js/ejs.min.js",
 "/META-INF/resources/webjars/react/0.13.1/react.js",
 "static/render.js",
 "static/output/comment.js",
 "static/output/comment-form.js",
 "static/output/comment-list.js");
  53. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 53 Develop a Javascript module loader server extension
 that loads resources from the classpath nashorn.eval(new InputStreamReader(getClass().getResourceAsStream("file.js")));
  54. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ SSE (server) 54 @Controller
 public class CommentController {
 private final List<SseEmitter> sseEmitters = new ArrayList<>();
 
 @RequestMapping(path = "/", method = RequestMethod.POST, produces = "application/json")
 @ResponseBody
 Comment jsonCreate(Comment comment) throws IOException {
 Comment newComment = this.commentRepository.save(comment);
 for (SseEmitter sseEmitter : this.sseEmitters) {
 sseEmitter.send(newComment, MediaType.APPLICATION_JSON);
 }
 return comment;
 }
 
 @RequestMapping("/sse/updates")
 SseEmitter subscribeUpdates() {
 SseEmitter sseEmitter = new SseEmitter();
 this.sseEmitters.add(sseEmitter);
 sseEmitter.onCompletion(() -> {
 this.sseEmitters.remove(sseEmitter);
 });
 return sseEmitter;
 }
 }
  55. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ SSE (client) 55 var CommentList = React.createClass({
 componentDidMount: function() {
 var eventSource = new EventSource("/sse/updates");
 var self = this;
 eventSource.onmessage = function(e) {
 var comment = JSON.parse(e.data);
 var comments = self.state.comments;
 var newComments = comments.concat([comment]);
 self.setState({comments: newComments});
 };
 },
 // ...
 });
  56. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Demo 56
  57. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ What’s next? 57
  58. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 58 EcmaScript 6
  59. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 59 TypeScript TypeScript = EcmaScript 6
 + types + decorators (annotations) + …
  60. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 60 Ember 2
  61. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 61 Angular 2
  62. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 62 Angular 2 @Component({selector: 'my-app'})
 @View({template: '<h1>Hi {{ name }}</h1>'})
 // Component controller
 class MyAppComponent {
 constructor() {
 this.name = 'Ali';
 }
 }
  63. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 63 Routing Need to build a bridge between server side and client side routing …
  64. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 64 Spring 5 draft roadmap for serverside JS • Builtin Java to JSON object conversion • JS logging on server side • Facilities to load content from filesystem/classpath • Script loader extension (classpath instead of Ajax request) • Ember2/Angular2/React support? • Spring beans accessible from Javascript?
  65. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 65 Experiments and contributions welcomed!
  66. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 66 Conclusion • Javascript evolves: ES6 - TypeScript • Javascript frameworks are becoming more mature: React - EmberJS 2 - Angular 2 • Isomorphic applications provide a nice balance between server side rendering and Javascript based RIA • Develop your front-end skills and try by yourself! • The choice of the client side technology/software design is key differentiator for your project/product!
  67. Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software,

    Inc. and licensed under a
 Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Thanks! 67 https://github.com/sdeleuze/spring-boot-sample-web-handlebars https://github.com/sdeleuze/spring-react-isomorphic @sdeleuze