Issue
I have been working on a spring-boot project initialized with spring initialzr. The generated package has no /webapp
directory, hence had to add /webapp
directory. I have read from spring documentation that spring detects static files from /static
,resources
. I have placed 3 different index.jsp
to test which one gets displayed by my controller. Below are the code snippets.
Directory Tree:
├── HELP.md
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── databasedisplay
│ │ │ └── app
│ │ │ ├── AppApplication.java
│ │ │ ├── config
│ │ │ │ ├── WebAppInitializer.java
│ │ │ │ └── WebConfig.java
│ │ │ ├── controller
│ │ │ │ ├── HomeController.java
│ │ │ │ └── IndexController.java
│ │ │ ├── repository
│ │ │ └── ServletInitializer.java
│ │ ├── resources
│ │ │ ├── application.properties
│ │ │ ├── index.jsp
│ │ │ ├── static
│ │ │ │ └── index.jsp
│ │ │ └── templates
│ │ └── webapp
│ │ └── WEB-INF
│ │ └── views
│ │ └── index.jsp
│ └── test
│ └── java
│ └── com
│ └── databasedisplay
│ └── app
│ └── AppApplicationTests.java
└── target
├── classes
│ ├── application.properties
│ ├── com
│ │ └── databasedisplay
│ │ └── app
│ │ ├── AppApplication.class
│ │ ├── config
│ │ │ ├── WebAppInitializer.class
│ │ │ └── WebConfig.class
│ │ ├── controller
│ │ │ ├── HomeController.class
│ │ │ └── IndexController.class
│ │ └── ServletInitializer.class
│ ├── index.jsp
│ └── static
│ └── index.jsp
├── generated-sources
│ └── annotations
├── generated-test-sources
│ └── test-annotations
├── maven-status
│ └── maven-compiler-plugin
│ ├── compile
│ │ └── default-compile
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── testCompile
│ └── default-testCompile
│ ├── createdFiles.lst
│ └── inputFiles.lst
└── test-classes
└── com
└── databasedisplay
└── app
└── AppApplicationTests.class
index.jsp (in '/resources')
<html>
<head></head>
<body>
<h1>This is the body of the sample view in /resources</h1>
</body>
index.jsp (in '/static')
<html>
<head></head>
<body>
<h1>This is the body of the sample view in /static</h1>
</body>
</html>
index.jsp (in '/WEB-INF/views/')
<html>
<head></head>
<body>
<h1>This is the body of the sample view in WEB-INF/views</h1>
</body>
</html>
Controller
@Controller
public class IndexController {
@RequestMapping(value = "/indexA", method = RequestMethod.GET)
public String index() {
return "index";
}
}
Configuration Classes
WebConfig.java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver
= new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable("testServlet");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/").setCachePeriod(3600)
.resourceChain(true).addResolver(new PathResourceResolver());
}
}
WebInitializer.java
public class WebAppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.scan("com.databasedisplay.app");
container.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = container.addServlet("mvc", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
}
The issue is when I run with mvn spring-boot:run
or mvn clean package spring-boot:run
the \target
directory as shown in the directory tree has no index.jsp
from \WEB-INF\views\
(in fact the target directory doesn't have a WEB-INF
directory at all). But I still get the following output when I curl http://localhost:8080/indexA
:
This is the body of the sample view in WEB-INF/views
Can someone explain how the view resolver even maps the view names to the corresponding views? (I have looked into
InternalResourceViewResolver
and how to set prefixes and suffixes but that still does not explain how it can render a jsp when it is not in target)Can someone point out to the differences between
mvn spring-boot:run
andmvn clean package spring-boot:run
as in the latter there is WEB-INF directory in the target.Why am I getting
index.jsp
corresponding to/WEB-INF
but not other views oncurl
?
Solution
JSP's are part of legacy Java Enterprise applications and are not the core of Spring Boot/MVC and it's more modern Template Engine approach (although Spring is based on Java EE). If you have any good reason to use JSP's, it could work. But with Spring, the MVC approach/implementation is to use the more modern template engines with technologies like Thymeleaf, FreeMarker, Groovy Markup, and Mustache.
Question 1 If you have configured your pom.xml correctly, you can use different starters to configure how your application is deployed/run. JSP's are not a standard solution for Spring and should be configured seperately, it needs to be configured so that it will compile the JSP's into their respective location so that Tomcat reads it from the webapps
folder. To compile and render JSP's your pom.xml needs both spring-boot-starter-web
and tomcat-embed-jasper
including the tag <scope>provided</scope>
.
Question 2 Spring comes with an embedded Tomcat server (spring-boot-starter-web). When you run mvn spring-boot:run
it will start a Tomcat server and deploy your Spring Boot application on the Tomcat localhost:8080
. mvn clean
, before spring-boot:run
, just deletes the output of a build by deleting the build directory.
Question 3 Each .HTML template or .JSP file have their respective location in the project before compiling, so therefore some .JSP's are not compiled in your folders.
A Java Enterprise application and it's corresponding JSP's use a different project structure than Spring: All JSP's will be compiled from the "src/main/webapp/WEB-INF/jsp/" if you have the right dependencies and run spring-boot:run
. If you manually create a project, through compiling by cmd -jar
, you should include your JSP's in the "/webapp/" folder and the Java.classes in WEB-INF/classes/MyServlet.class.
By using, for instance Thymeleaf (spring-boot-starter-thymeleaf), if you build your artifacts the IDE will compile templates from /resources/templates
and work from there on your MVC project, where you can integrate your REST controllers seamlessly.
Tomcat stays pivotal in how your enterprise application is deployed, only that you need to adjust your project in Spring so that it will map and compile the right files into the .WAR before deploying.
My advice would be, for MVC, to use the template engines instead of the legacy JSP's. of course, there will use cases for JSP's inside a Spring project but it requires a differect structure and dependencies.
Answered By - kenneth