Slide 1

Slide 1 text

Spring Boot for the Web Tier Phillip Webb twiiter: @phillip_webb email: pwebb@pivotal.io Dave Syer twitter: @david_syer email: dsyer@pivotal.io http://localhost:4000/decks/spring-boot-for-the-web-tier.html 1 of 43 10/09/14 08:15

Slide 2

Slide 2 text

Presentation Overview Part 1 - Static Content Part 2 - Dynamic Content Part 3 - Embedded Server Part 4 - Other Stacks http://localhost:4000/decks/spring-boot-for-the-web-tier.html 2 of 43 10/09/14 08:15

Slide 3

Slide 3 text

Static Content - Serving Files Can't use /src/main/webapp for jar deployments Put static files from src/main/resources/static or .../public or .../resources or .../META- INF/resources http://localhost:4000/decks/spring-boot-for-the-web-tier.html 3 of 43 10/09/14 08:15

Slide 4

Slide 4 text

Static Content - Conventions src/main/resources/static/index.html is mapped to /index.html & / Add a src/main/resources/favicon.ico to replace the Spring Leaf Imported "webjars" are automatically mapped http://localhost:4000/decks/spring-boot-for-the-web-tier.html 4 of 43 10/09/14 08:15

Slide 5

Slide 5 text

Demo - Static Content http://localhost:4000/decks/spring-boot-for-the-web-tier.html 5 of 43 10/09/14 08:15

Slide 6

Slide 6 text

Static Content: Grunt Toolchain For serious front end developers the best choice is a Javascript toolchain. Good community, lots of tools Package static assets into a jar And/or build them as part of a very thin back end Spring Boot CLI makes a great lightweight back end in production or for Java devs http://localhost:4000/decks/spring-boot-for-the-web-tier.html 6 of 43 10/09/14 08:15

Slide 7

Slide 7 text

Static Content - wro4j Great for Java developers Often good enough JsHint CssLint JsMin Google Closure compressor UglifyJs Less Sass http://localhost:4000/decks/spring-boot-for-the-web-tier.html 7 of 43 10/09/14 08:15

Slide 8

Slide 8 text

Static Content - Wro4j with Maven http://localhost:4000/decks/spring-boot-for-the-web-tier.html 8 of 43 10/09/14 08:15

Slide 9

Slide 9 text

ro.isdc.wro4j wro4j-maven-plugin ${wro4j.version} generate-resources run ro.isdc.wro.maven.plugin.manager.factory.Configu rableWroManagerFactory ${basedir}/target/generated-resources /static/ ${basedir}/src/main/wro/wro.xml ${basedir}/src/main/wro /wro.properties http://localhost:4000/decks/spring-boot-for-the-web-tier.html 9 of 43 10/09/14 08:15

Slide 10

Slide 10 text

Static Content - Wro4j with Maven src/main/wro/wro.xml file:./src/main/wro/main.less src/main/wro/wro.properties postProcessors=less4j http://localhost:4000/decks/spring-boot-for-the-web-tier.html 10 of 43 10/09/14 08:15

Slide 11

Slide 11 text

Dynamic Content - Templating Support Thymeleaf Groovy Template Language Freemarker Velocity JSP (not recommended) http://localhost:4000/decks/spring-boot-for-the-web-tier.html 11 of 43 10/09/14 08:15

Slide 12

Slide 12 text

Dynamic Content - Template Conventions Templates live in src/main/resources/templates and are accessed via classpath:/templates/ Default Extensions are: *.html - Thymeleaf *.tpl - Groovy *.ftl - Freemarker *.vm - Velocity http://localhost:4000/decks/spring-boot-for-the-web-tier.html 12 of 43 10/09/14 08:15

Slide 13

Slide 13 text

Dynamic Content - Template Customization User spring.xxx.prefix and spring.xxx.suffix eg. spring.freemarker.suffix=fm http://localhost:4000/decks/spring-boot-for-the-web-tier.html 13 of 43 10/09/14 08:15

Slide 14

Slide 14 text

Demo - Templatinghttp://localhost:4000/decks/spring-boot-for-the-web-tier.html 14 of 43 10/09/14 08:15

Slide 15

Slide 15 text

Dynamic Content - Custom Support Add a ViewResolver Optionally add a TemplateAvailabilityProvider http://localhost:4000/decks/spring-boot-for-the-web-tier.html 15 of 43 10/09/14 08:15

Slide 16

Slide 16 text

public class GroovyTemplateAvailabilityProvider implements TemplateAvailabilityProvider { @Override public boolean isTemplateAvailable(String view, Environment environment, ClassLoader classLoader, ResourceLoader resourceLoader) { if (ClassUtils.isPresent("groovy.text.TemplateEngine", classLoader)) { String prefix = environment.getProperty("spring.groovy.template.prefix", GroovyTemplateProperties.DEFAULT_PREFIX); String suffix = environment.getProperty("spring.groovy.template.suffix", GroovyTemplateProperties.DEFAULT_SUFFIX); return resourceLoader.getResource(prefix + view + suffix).exists(); } return false; } } http://localhost:4000/decks/spring-boot-for-the-web-tier.html 16 of 43 10/09/14 08:15

Slide 17

Slide 17 text

Dynamic Content - Internationalization A MessageSource bean is added when src/main/resources /messages.properties exists Use messages_LOCALE.properties to add additional locales e.g. messages_FR.properties Choose a specific locale using the spring.mvc.locale property Choose a specific date format using the spring.mvc.date- format property http://localhost:4000/decks/spring-boot-for-the-web-tier.html 17 of 43 10/09/14 08:15

Slide 18

Slide 18 text

Dynamic Content - HttpMessageConverter Add HttpMessageConverter beans and Spring Boot will try to do the right thing It tries to be intelligent about the order Add a HttpMessageConverters bean if you need more control http://localhost:4000/decks/spring-boot-for-the-web-tier.html 18 of 43 10/09/14 08:15

Slide 19

Slide 19 text

Dynamic Content - Rest Use the @RestContoller annotation Use ResponseEntity builder methods with Spring Framework 4.1 ResponseEntity. accepted(). contentLength(3). contentType(MediaType.TEXT_PLAIN). body("Yo!"); http://localhost:4000/decks/spring-boot-for-the-web-tier.html 19 of 43 10/09/14 08:15

Slide 20

Slide 20 text

Demo - HttpMessageConverter http://localhost:4000/decks/spring-boot-for-the-web-tier.html 20 of 43 10/09/14 08:15

Slide 21

Slide 21 text

Dynamic Content - Hidden Gems You can get the RequestContext from RequestContextHolder anywhere The request has some useful things in it (from Spring), e.g. HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE All Converter, Formatter, GenericConverter beans are automatically added Use spring.mvc.message-codes-resolver-format to add a MessageCodesResolver prefix_error_code or postfix_error_code # prefix_error_code empty.customer.name=Customer name is required http://localhost:4000/decks/spring-boot-for-the-web-tier.html 21 of 43 10/09/14 08:15

Slide 22

Slide 22 text

# postfix_error_code customer.name.empty=Customer name is required http://localhost:4000/decks/spring-boot-for-the-web-tier.html 22 of 43 10/09/14 08:15

Slide 23

Slide 23 text

Embedded Server When using WARs a ServletContainerInitializer creates the Spring ApplicationContext When running embedded the ApplicationContext creates the Server Expects a single EmbeddedServletContainerFactory bean Odd dance for WebApplicationContext.getServletContext() and ServletConfigAware http://localhost:4000/decks/spring-boot-for-the-web-tier.html 23 of 43 10/09/14 08:15

Slide 24

Slide 24 text

Embedded Server - Initialization The following beans are used to configure the server: Servlet Filter ServletRequestListener ServletRequestAttributeListener HttpSessionAttributeListener HttpSessionListener ServletContextListener http://localhost:4000/decks/spring-boot-for-the-web-tier.html 24 of 43 10/09/14 08:15

Slide 25

Slide 25 text

Embedded Server - Initialization For more control use ServletRegistrationBean FilterRegistrationBean ServletListenerRegistrationBean http://localhost:4000/decks/spring-boot-for-the-web-tier.html 25 of 43 10/09/14 08:15

Slide 26

Slide 26 text

@Bean public ServletRegistrationBean myServlet() { ServletRegistrationBean bean = new ServletRegistrationBean(new MyServlet(), "/mine"); bean.setAsyncSupported(false); bean.setInitParameters(Collections.singletonMap("debug", "true")); return bean; } @Bean public FilterRegistrationBean myFilter() { return new FilterRegistrationBean(new MyFilter(), myServlet()); } http://localhost:4000/decks/spring-boot-for-the-web-tier.html 26 of 43 10/09/14 08:15

Slide 27

Slide 27 text

Embedded Server - Initialization By design the following are not called with embedded servers: javax.servlet.ServletContainerInitializer org.springframework.web.WebApplicationInitializer Use o.s.boot.context.embedded.ServletContextInitializer http://localhost:4000/decks/spring-boot-for-the-web-tier.html 27 of 43 10/09/14 08:15

Slide 28

Slide 28 text

/** * Configure the given {@link ServletContext} with any servlets, filters, listeners * context-params and attributes necessary for initialization. * @param servletContext the {@code ServletContext} to initialize * @throws ServletException if any call against the given {@code ServletContext} * throws a {@code ServletException} */ void onStartup(ServletContext servletContext) throws ServletException; http://localhost:4000/decks/spring-boot-for-the-web-tier.html 28 of 43 10/09/14 08:15

Slide 29

Slide 29 text

Embedded Server - Customization Use ServerProperties (e.g. server.port=8080) EmbeddedServletContainerCustomizer Customize common things (e.g. the port, error-pages, context-path) Tomcat Specific TomcatConnectorCustomizer TomcatContextCustomizer Jetty Specific JettyServerCustomizer http://localhost:4000/decks/spring-boot-for-the-web-tier.html 29 of 43 10/09/14 08:15

Slide 30

Slide 30 text

Embedded Server - Customization If all else fails subclass EmbeddedServletContainerFactory Lots of protected methods to override TomcatEmbeddedServletContainerFactory JettyEmbeddedServletContainerFactory http://localhost:4000/decks/spring-boot-for-the-web-tier.html 30 of 43 10/09/14 08:15

Slide 31

Slide 31 text

@Bean public TomcatEmbeddedServletContainerFactory tomcatFactory() { return new TomcatEmbeddedServletContainerFactory(7070) { @Override protected void customizeConnector(Connector connector) { // Something with the connector } @Override protected void configureSsl(AbstractHttp11JsseProtocol> protocol, Ssl ssl) { // Something with ssl } }; } http://localhost:4000/decks/spring-boot-for-the-web-tier.html 31 of 43 10/09/14 08:15

Slide 32

Slide 32 text

Embedded Server - Tomcat Behind HTTPD Running behind Apache HTTPD is a common option Especially useful with SSL termination Real IP and SSL information is passed in headers server.tomcat.protocol-header=x-forwarded-proto server.tomcat.remote-ip-header=x-forwarded-for http://localhost:4000/decks/spring-boot-for-the-web-tier.html 32 of 43 10/09/14 08:15

Slide 33

Slide 33 text

Embedded Server - Tomcat Behind HTTPD ServerName example.spring.io ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined ProxyPass / http://${TOMCAT_IP}:8080/ ProxyPassReverse / http://${TOMCAT_IP}:8080/ SSLEngine on SSLCertificateFile /etc/apache2/ssl/apache.crt SSLCertificateKeyFile /etc/apache2/ssl/apache.key ProxyPass / http://${TOMCAT_IP}:8080/ ProxyPassReverse / http://${TOMCAT_IP}:8080/ RequestHeader set X-Forwarded-Proto "https" RequestHeader set X-Forwarded-Port "443" http://localhost:4000/decks/spring-boot-for-the-web-tier.html 33 of 43 10/09/14 08:15

Slide 34

Slide 34 text

Demo - Running Behind HTTPS http://localhost:4000/decks/spring-boot-for-the-web-tier.html 34 of 43 10/09/14 08:15

Slide 35

Slide 35 text

Other Stacks JAX-RS: Jersey 1.x, Jersey 2.x dsyer/spring-boot-jersey, CXF (allegedly works) Netty and NIO: Ratpack dsyer/spring-boot-ratpack Servlet 2.5 scratches/spring-boot-legacy Vaadin peholmst/vaadin4spring http://localhost:4000/decks/spring-boot-for-the-web-tier.html 35 of 43 10/09/14 08:15

Slide 36

Slide 36 text

Jersey 1.x Easy to integrate with Spring Boot using Filter (or Servlet), e.g. http://localhost:4000/decks/spring-boot-for-the-web-tier.html 36 of 43 10/09/14 08:15

Slide 37

Slide 37 text

@Configuration @EnableAutoConfiguration @Path("/") public class Application { @GET @Produces("text/plain") public String hello() { return "Hello World"; } @Bean public FilterRegistrationBean jersey() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new ServletContainer()); bean.addInitParameter("com.sun.jersey.config.property.packages", "com.mycompany.myapp"); return bean; } } (N.B. with fat jar you need to explicitly list the nested jars that have JAX-RS resources in them.) http://localhost:4000/decks/spring-boot-for-the-web-tier.html 37 of 43 10/09/14 08:15

Slide 38

Slide 38 text

Jersey 2.x Spring integration is provided out of the box, but a little bit tricky to use with Spring Boot, so some autoconfiguration is useful. Example app: @Configuration @Path("/") public class Application extends ResourceConfig { @GET public String message() { return "Hello"; } public Application() { register(Application.class); } } http://localhost:4000/decks/spring-boot-for-the-web-tier.html 38 of 43 10/09/14 08:15

Slide 39

Slide 39 text

Ratpack Originally inspired by Sinatra, but now pretty much diverged. Provides a nice programming model on top of Netty (potentially taking advantage of non-blocking IO). 2 approaches: Ratpack embeds Spring (and uses it as a Registry), supported natively in Ratpack 0.9.9 Spring embeds Ratpack (and uses it as an HTTP listener) = spring- boot-ratpack http://localhost:4000/decks/spring-boot-for-the-web-tier.html 39 of 43 10/09/14 08:15

Slide 40

Slide 40 text

Spring Boot embedding Ratpack Trivial example (single Handler): @Bean public Handler handler() { return (context) -> { context.render("Hello World"); }; } http://localhost:4000/decks/spring-boot-for-the-web-tier.html 40 of 43 10/09/14 08:15

Slide 41

Slide 41 text

Spring Boot embedding Ratpack More interesting example (Action registers Handlers): @Bean public Handler hello() { return (context) -> { context.render("Hello World"); }; } @Bean public Action handlers() { return (chain) -> { chain.get(hello()); }; } http://localhost:4000/decks/spring-boot-for-the-web-tier.html 41 of 43 10/09/14 08:15

Slide 42

Slide 42 text

Spring Boot Ratpack DSL A valid Ratpack Groovy application: ratpack { handlers { get { render "Hello World" } } } launched with Spring Boot: $ spring run app.groovy http://localhost:4000/decks/spring-boot-for-the-web-tier.html 42 of 43 10/09/14 08:15

Slide 43

Slide 43 text

Questions? http://projects.spring.io/spring-boot/ https://github.com/SpringOne2GX-2014/spring-boot-for-the-web-tier http://localhost:4000/decks/spring-boot-for-the-web-tier.html 43 of 43 10/09/14 08:15