Spring Boot for the Web Tier

Phillip Webb
twiiter: @phillip_webb
email: pwebb@pivotal.io

Dave Syer
twitter: @david_syer
email: dsyer@pivotal.io

Presentation Overview

Static Content - Serving Files

Static Content - Conventions

Demo - Static Content

Static Content: Grunt Toolchain

For serious front end developers the best choice is a Javascript toolchain.

Static Content - wro4j

Static Content - Wro4j with Maven

<plugin>
    <groupId>ro.isdc.wro4j</groupId>
    <artifactId>wro4j-maven-plugin</artifactId>
    <version>${wro4j.version}</version>
    <executions><execution>
      <phase>generate-resources</phase>
      <goals><goal>run</goal></goals>
    </execution></executions>
    <configuration>
        <wroManagerFactory>ro.isdc.wro.maven.plugin.manager.factory.ConfigurableWroManagerFactory</wroManagerFactory>
        <destinationFolder>${basedir}/target/generated-resources/static/</destinationFolder>
        <wroFile>${basedir}/src/main/wro/wro.xml</wroFile>
        <extraConfigFile>${basedir}/src/main/wro/wro.properties</extraConfigFile>
    </configuration>
</plugin>

Static Content - Wro4j with Maven

src/main/wro/wro.xml

<groups xmlns="http://www.isdc.ro/wro">
  <group name="wro">
    <css>file:./src/main/wro/main.less</css>
  </group>
</groups>

src/main/wro/wro.properties

postProcessors=less4j

Dynamic Content - Templating Support

Dynamic Content - Template Conventions

Dynamic Content - Template Customization

Demo - Templating

Dynamic Content - Custom Support

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;
  }

}

Dynamic Content - Internationalization

Dynamic Content - HttpMessageConverter

Dynamic Content - Rest

ResponseEntity.
    accepted().
    contentLength(3).
    contentType(MediaType.TEXT_PLAIN).
    body("Yo!");

Demo - HttpMessageConverter

Dynamic Content - Hidden Gems

# prefix_error_code
empty.customer.name=Customer name is required


# postfix_error_code
customer.name.empty=Customer name is required

Embedded Server

Embedded Server - Initialization

Embedded Server - Initialization

@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());
}

Embedded Server - Initialization

  /**
   * 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;

Embedded Server - Customization

Embedded Server - Customization

@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
        }
    };
}

Embedded Server - Tomcat Behind HTTPD

server.tomcat.protocol-header=x-forwarded-proto
server.tomcat.remote-ip-header=x-forwarded-for

Embedded Server - Tomcat Behind HTTPD

<VirtualHost *:80>
  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/
</VirtualHost>

<VirtualHost *:443>
  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"
</VirtualHost>

Demo - Running Behind HTTPS

Other Stacks

Jersey 1.x

Easy to integrate with Spring Boot using Filter (or Servlet), e.g.

@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.)

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);
    }

}

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:

Spring Boot embedding Ratpack

Trivial example (single Handler):

@Bean
public Handler handler() {
    return (context) -> {
        context.render("Hello World");
    };
}

Spring Boot embedding Ratpack

More interesting example (Action<Chain> registers Handlers):

@Bean
public Handler hello() {
    return (context) -> {
        context.render("Hello World");
    };
}

@Bean
public Action<Chain> handlers() {
    return (chain) -> {
        chain.get(hello());
    };
}

Spring Boot Ratpack DSL

A valid Ratpack Groovy application:

ratpack {
  handlers {
    get {
      render "Hello World"
    }
  }
}

launched with Spring Boot:

$ spring run app.groovy

Questions?

#