diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml index 2615b09a9a4..b21ebc6c57c 100644 --- a/spring-boot-samples/pom.xml +++ b/spring-boot-samples/pom.xml @@ -25,6 +25,7 @@ spring-boot-sample-tomcat spring-boot-sample-traditional spring-boot-sample-web-static + spring-boot-sample-web-jsp spring-boot-sample-web-ui spring-boot-sample-websocket spring-boot-sample-xml diff --git a/spring-boot-samples/spring-boot-sample-web-jsp/pom.xml b/spring-boot-samples/spring-boot-sample-web-jsp/pom.xml new file mode 100644 index 00000000000..d53b42d0090 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-web-jsp/pom.xml @@ -0,0 +1,41 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 0.5.0.BUILD-SNAPSHOT + ../../spring-boot-starters/spring-boot-starter-parent + + spring-boot-sample-web-jsp + war + + ${basedir}/../.. + + + + ${project.groupId} + spring-boot-starter-web + + + org.apache.tomcat.embed + tomcat-embed-jasper + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + + + ${project.groupId} + spring-boot-maven-plugin + + + + diff --git a/spring-boot-samples/spring-boot-sample-web-jsp/src/main/java/org/springframework/boot/sample/jsp/SampleWebJspApplication.java b/spring-boot-samples/spring-boot-sample-web-jsp/src/main/java/org/springframework/boot/sample/jsp/SampleWebJspApplication.java new file mode 100644 index 00000000000..e9c16f0ed37 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-web-jsp/src/main/java/org/springframework/boot/sample/jsp/SampleWebJspApplication.java @@ -0,0 +1,43 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.sample.jsp; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.view.InternalResourceViewResolver; + +@Configuration +@EnableAutoConfiguration +@ComponentScan +public class SampleWebJspApplication { + + @Bean + public InternalResourceViewResolver defaultViewResolver() { + InternalResourceViewResolver resolver = new InternalResourceViewResolver(); + resolver.setPrefix("/WEB-INF/jsp/"); + resolver.setSuffix(".jsp"); + return resolver; + } + + public static void main(String[] args) throws Exception { + SpringApplication.run(SampleWebJspApplication.class, args); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-web-jsp/src/main/java/org/springframework/boot/sample/jsp/WelcomeController.java b/spring-boot-samples/spring-boot-sample-web-jsp/src/main/java/org/springframework/boot/sample/jsp/WelcomeController.java new file mode 100644 index 00000000000..9554156fb30 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-web-jsp/src/main/java/org/springframework/boot/sample/jsp/WelcomeController.java @@ -0,0 +1,14 @@ +package org.springframework.boot.sample.jsp; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class WelcomeController { + + @RequestMapping("/") + public String welcome() { + return "welcome"; + } + +} diff --git a/spring-boot-samples/spring-boot-sample-web-jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp b/spring-boot-samples/spring-boot-sample-web-jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp new file mode 100644 index 00000000000..eaf9903ddc6 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-web-jsp/src/main/webapp/WEB-INF/jsp/welcome.jsp @@ -0,0 +1,12 @@ + + +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> + + + + + + ${springUrl} + + + diff --git a/spring-boot-samples/spring-boot-sample-web-jsp/src/test/java/org/springframework/boot/sample/jsp/SampleWebJspApplicationTests.java b/spring-boot-samples/spring-boot-sample-web-jsp/src/test/java/org/springframework/boot/sample/jsp/SampleWebJspApplicationTests.java new file mode 100644 index 00000000000..3eda54cd91e --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-web-jsp/src/test/java/org/springframework/boot/sample/jsp/SampleWebJspApplicationTests.java @@ -0,0 +1,72 @@ +package org.springframework.boot.sample.jsp; + +import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.RestTemplate; + +import static org.junit.Assert.*; + +/** + * Basic integration tests for JSP application. + * + * @author Phillip Webb + */ +public class SampleWebJspApplicationTests { + + private static ConfigurableApplicationContext context; + + @BeforeClass + public static void start() throws Exception { + Future future = Executors + .newSingleThreadExecutor().submit( + new Callable() { + @Override + public ConfigurableApplicationContext call() throws Exception { + return (ConfigurableApplicationContext) SpringApplication + .run(SampleWebJspApplication.class); + } + }); + context = future.get(60, TimeUnit.SECONDS); + } + + @AfterClass + public static void stop() { + if (context != null) { + context.close(); + } + } + + @Test + public void testJspWithEl() throws Exception { + ResponseEntity entity = getRestTemplate().getForEntity( + "http://localhost:8080", String.class); + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertTrue("Wrong body:\n" + entity.getBody(), entity + .getBody().contains("/resources/text.txt")); + } + + private RestTemplate getRestTemplate() { + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { + @Override + public void handleError(ClientHttpResponse response) throws IOException { + } + }); + return restTemplate; + + } + +} diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java index b93207efc57..55f1f790cc5 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java @@ -18,14 +18,20 @@ package org.springframework.boot.context.embedded.tomcat; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Method; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; +import javax.servlet.ServletContext; + import org.apache.catalina.Context; import org.apache.catalina.Host; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Valve; import org.apache.catalina.Wrapper; @@ -48,6 +54,7 @@ import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; +import org.springframework.util.StreamUtils; /** * {@link EmbeddedServletContainerFactory} that can be used to create @@ -161,6 +168,7 @@ public class TomcatEmbeddedServletContainerFactory extends && ClassUtils.isPresent(getJspServletClassName(), getClass() .getClassLoader())) { addJspServlet(context); + context.addLifecycleListener(new StoreMergedWebXmlListener()); } ServletContextInitializer[] initializersToUse = mergeInitializers(initializers); configureContext(context, initializersToUse); @@ -443,4 +451,45 @@ public class TomcatEmbeddedServletContainerFactory extends } + /** + * {@link LifecycleListener} that stores an empty merged web.xml. This is critical for + * Jasper to prevent warnings about missing web.xml files and to enable EL. + */ + private static class StoreMergedWebXmlListener implements LifecycleListener { + + private String MERGED_WEB_XML = org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML; + + @Override + public void lifecycleEvent(LifecycleEvent event) { + if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { + onStart((Context) event.getLifecycle()); + } + } + + private void onStart(Context context) { + ServletContext servletContext = context.getServletContext(); + if (servletContext.getAttribute(this.MERGED_WEB_XML) == null) { + servletContext.setAttribute(this.MERGED_WEB_XML, getEmptyWebXml()); + } + } + + private String getEmptyWebXml() { + InputStream stream = TomcatEmbeddedServletContainerFactory.class + .getResourceAsStream("empty-web.xml"); + Assert.state(stream != null, "Unable to read empty web.xml"); + try { + try { + return StreamUtils.copyToString(stream, Charset.forName("UTF-8")); + } + finally { + stream.close(); + } + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + } + } diff --git a/spring-boot/src/main/resources/org/springframework/boot/context/embedded/tomcat/empty-web.xml b/spring-boot/src/main/resources/org/springframework/boot/context/embedded/tomcat/empty-web.xml new file mode 100644 index 00000000000..14c04a59579 --- /dev/null +++ b/spring-boot/src/main/resources/org/springframework/boot/context/embedded/tomcat/empty-web.xml @@ -0,0 +1,6 @@ + + +