Phillip Webb
twiiter: @phillip_webb
email: pwebb@pivotal.io
Dave Syer
twitter: @david_syer
email: dsyer@pivotal.io
/src/main/webapp
for jar deploymentssrc/main/resources/static
.../public
or .../resources
or .../META-INF/resources
src/main/resources/static/index.html
is mapped to /index.html
& /
src/main/resources/favicon.ico
to replace the Spring LeafFor serious front end developers the best choice is a Javascript toolchain.
<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>
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
src/main/resources/templates
classpath:/templates/
*.html
- Thymeleaf*.tpl
- Groovy*.ftl
- Freemarker*.vm
- Velocityspring.xxx.prefix
and spring.xxx.suffix
spring.freemarker.suffix=fm
ViewResolver
TemplateAvailabilityProvider
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;
}
}
MessageSource
bean is added when src/main/resources/messages.properties
existsmessages_LOCALE.properties
to add additional locales
messages_FR.properties
spring.mvc.locale
propertyspring.mvc.date-format
propertyHttpMessageConverter
beans and Spring Boot will try to do the right thingHttpMessageConverters
bean if you need more control@RestContoller
annotationResponseEntity.
accepted().
contentLength(3).
contentType(MediaType.TEXT_PLAIN).
body("Yo!");
RequestContext
from RequestContextHolder
anywhereHandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE
Converter
, Formatter
, GenericConverter
beans are automatically addedspring.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
# postfix_error_code
customer.name.empty=Customer name is required
ServletContainerInitializer
creates the Spring ApplicationContext
ApplicationContext
creates the ServerEmbeddedServletContainerFactory
beanWebApplicationContext.getServletContext()
and ServletConfigAware
Servlet
Filter
ServletRequestListener
ServletRequestAttributeListener
HttpSessionAttributeListener
HttpSessionListener
ServletContextListener
ServletRegistrationBean
FilterRegistrationBean
ServletListenerRegistrationBean
@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());
}
javax.servlet.ServletContainerInitializer
org.springframework.web.WebApplicationInitializer
o.s.boot.context.embedded.ServletContextInitializer
/**
* 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;
ServerProperties
(e.g. server.port=8080
)EmbeddedServletContainerCustomizer
port
, error-pages
, context-path
)TomcatConnectorCustomizer
TomcatContextCustomizer
JettyServerCustomizer
EmbeddedServletContainerFactory
TomcatEmbeddedServletContainerFactory
JettyEmbeddedServletContainerFactory
@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
}
};
}
server.tomcat.protocol-header=x-forwarded-proto
server.tomcat.remote-ip-header=x-forwarded-for
<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>
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.)
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);
}
}
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:
Registry
), supported natively in Ratpack 0.9.9Trivial example (single Handler
):
@Bean
public Handler handler() {
return (context) -> {
context.render("Hello World");
};
}
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());
};
}
A valid Ratpack Groovy application:
ratpack {
handlers {
get {
render "Hello World"
}
}
}
launched with Spring Boot:
$ spring run app.groovy
/
#