26

I started a Spring Boot MVC project and realized that there are two folder within resources. One is called templates and the other static. I really like this folder setup.

The problem is that I use JSP Templates for my views. I could not place a .jsp template inside the templates folder and got it to work. What I needed to do is to create a webapp folder on the same level as src and resources. Placing my JSP templates in there and then my views can be found.

What do I need to reconfigure to actually use my JSP templates within the templates folder which lies within resources?

xetra11
  • 7,671
  • 14
  • 84
  • 159
  • 1
    If you want to use Thymeleaf for the template then you can check example at https://www.mkyong.com/spring-boot/spring-boot-hello-world-example-thymeleaf/ – Amit K Bist Sep 12 '17 at 19:19
  • As I said - JSP only. The `templates` stuff does work for TL I know that – xetra11 Sep 12 '17 at 19:20
  • Actually you mentioned JSP template so I assumed you mean TL, I dont think you can have jsp inside the resources folder. JSPs should be inside the webapp. – Amit K Bist Sep 12 '17 at 19:22
  • If you are starting a new project don't use JSP. Use something like Thymeleaf. JSP will only work in the web app locations and other resource locations specified by the servlet spec. – M. Deinum Sep 12 '17 at 19:25
  • I have no option to use something else because JSP is company standard – xetra11 Sep 12 '17 at 19:26
  • I'm facing the same issue. Moreover thymeleaf is not compatible with several client sided templating engines, even simple mustache. Since it tries to parse everything, it simply reports errors for those. In other words, it sucks. JSP is old as hell, but it can do everything TL does and more. – dagnelies Jan 11 '18 at 13:42
  • No, it doesn't. You can't drop a JSP into a browser to view the page, whereas TL allows you to do just that. – Sync Jan 12 '18 at 12:44

5 Answers5

28

According to the Maven documentation src/main/resources will end up in WEB-INF/classes in the WAR.

This does the trick for Spring Boot in your application.properties:

spring.mvc.view.prefix = /WEB-INF/classes/templates
spring.mvc.view.suffix = .jsp

If you prefer Java configuration this is the way to go:

@EnableWebMvc
@Configuration
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {

    @Bean
    public ViewResolver jspViewResolver() {
        InternalResourceViewResolver bean = new InternalResourceViewResolver();
        bean.setPrefix("/WEB-INF/classes/templates/");
        bean.setSuffix(".jsp");
        return bean;
    }
}

Update with a full example

This example was based on Spring's initializer (Gradle project with "Web" dependency). I just added apply plugin: 'war' to the build.gradle, added/changed the files below, built teh project with gradle war and deployed it to my application server (Tomcat 8).

This is the directory tree of this sample project:

\---src
    +---main
        +---java
        |   \---com
        |       \---example
        |           \---demo
        |                   ApplicationConfiguration.java
        |                   DemoApplication.java
        |                   DemoController.java
        |
        \---resources
            +---static
            \---templates
                    index.jsp

ApplicationConfiguration.java: see above

DemoApplication.java:

@SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(DemoApplication.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(DemoApplication.class, args);
    }

}

DemoController.java:

@Controller
public class DemoController {

    @RequestMapping("/")
    public String index() {
        return "index";
    }
}

index.jsp:

<html>
    <body>
        <h1>Hello World</h1>
    </body>
</html>
Franz Fellner
  • 563
  • 1
  • 5
  • 13
  • All I get is a 500 / unexpected error: "Circular view path [/WEB-INF/classes/templates/some.jsp]: would dispatch back to the current handler URL [/WEB-INF/classes/templates/some.jsp] again.". I used a fresh blank project with a single JSP file and both your suggestions. – dagnelies Jan 18 '18 at 09:51
  • Here you go, one free bounty for an answer that doesn't work. However, it's closer to it than the accepted answer IMHO. – dagnelies Jan 18 '18 at 13:22
  • 1
    @dagnelies Thanks for the bounty. I edited my post with my running sample project. Are you building a WAR and deploying it to an app server? Executable JAR and WAR don't play well with Spring Boot and JSP due to [limitations](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-jsp-limitations). It might work for JSP if you put them in `/src/main/resources/META-INF/resources/WEB-INF/jsp` according to this [article](https://dzone.com/articles/spring-boot-with-jsps-in-executable-jars-1) but that is not what the OP wanted – Franz Fellner Jan 18 '18 at 16:02
  • 1
    worked for me thank you. In my case added my jsp in WEB-INF/jsp and all the HTML, CSS, JS in main/resources/public. referred to them by /WEB-INF/classes/public – Kiran Kumar May 16 '18 at 13:59
  • I used `spring.mvc.view.prefix = /WEB-INF/classes/templates/` and it doens't work. I don't understand why because when I look into the war file, the directory exists but I still receive a 404 – Olivier Boissé Dec 01 '19 at 15:07
9

Official information:

Resource handling:

Links to resources are rewritten at runtime in template, thanks to a ResourceUrlEncodingFilter, auto-configured for Thymeleaf and FreeMarker. You should manually declare this filter when using JSPs. source

Supported template engine

As well as REST web services, you can also use Spring MVC to serve dynamic HTML content. Spring MVC supports a variety of templating technologies including Thymeleaf, FreeMarker and JSPs.

[...]

JSPs should be avoided if possible, there are several known limitations when using them with embedded servlet containers.

[..]

When you’re using one of these templating engines with the default configuration, your templates will be picked up automatically from src/main/resources/templates.

source

Spring boot JSP limitations

  • With Tomcat it should work if you use war packaging, i.e. an executable war will work, and will also be deployable to a standard
    container (not limited to, but including Tomcat).
  • An executable jar will not work because of a hard coded file pattern in Tomcat.
  • With Jetty it should work if you use war packaging, i.e. an executable war will work, and will also be deployable to any standard container.
  • Undertow does not support JSPs.
  • Creating a custom error.jsp page won’t override the default view for error handling, custom error pages should be used instead.

source

Technical change

Tell spring boot to from where to load the JSP files. In application.properties set

spring.mvc.view.prefix: /WEB-INF/views/
spring.mvc.view.suffix: .jsp

source

Sample spring boot with JSP

In case you do want to use JSP with spring boot here are two examples:

https://github.com/spring-projects/spring-boot/tree/v1.5.9.RELEASE/spring-boot-samples/spring-boot-sample-web-jsp

https://github.com/joakime/spring-boot-jsp-demo

oak
  • 2,898
  • 2
  • 32
  • 65
  • 4
    I think this answer beats around the bush. The issue is not to use/display JSPs. The OP clearly stated he can already do that. It is to configure Spring to use the standard `templates` folder to lookup the JSPs instead of "bypassing" the lookup mechanism by using the `webapp/WEB-INF`. From your answer, it is still not clear to me how to do so. The first example fetches them from the `webapp` directory, the second uses the special `META-INF`/`WEB-INF` combo. It's similar to what the OP already did. How get them directly from `templates` is still unanswered. – dagnelies Jan 12 '18 at 16:19
2

To summarize it, none of the suggested answers worked for me so far. Using a blank Spring boot starter project.

Somehow, something looks hardwired inside Spring or servlets so that JSP must be in /webapp (or a subfolder). Unlike default thymeleaf templates which are looked up in /resources/templates.

I tried all kind of changes, really a lot of different configurations, but wasn't able to modify that behavior. It just produced complexity and was unable to serve the JSPs anymore. So, bottom line, if you're using JSPs, just put them in /webapp. It also works by addding zero configuration using a controller like:

@GetMapping("/foo") public String serveFoo() { return "relative-path-inside-webapp/foo.jsp"; }

On another note, by default, the /webapp folder will also be hidden in the Spring Toolsuite, so you'll have to manually configure it as a "source folder".

dagnelies
  • 5,203
  • 5
  • 38
  • 56
0

suppose you have welcome.jsp file in src\main\webapp\WEB-INF\jsp\welcome.jsp and you have these config: spring.mvc.view.prefix: /WEB-INF/jsp/ and spring.mvc.view.suffix: .jsp

it works with mvn spring-boot:run if you want that you run your jar file with java -jar java -jar spring-boot-web-jsp.jar command just copy src\main\webapp\WEB-INF to src\main\resources\META-INF\resources

file welcome.jsp should be in src\main\resources\META-INF\resources\WEB-INF\jsp\welcome.jsp

also according to this answer he found that since 1.4.3 version and above stops supporting the embedded JSPs

Amir
  • 1,638
  • 19
  • 26
0

I was able to get JSP Resolved from templates folder with this in my Application Config...

    @Bean
@Description("Thymeleaf template resolver serving HTML 5")
public ClassLoaderTemplateResolver templateResolver() {

    var templateResolver = new ClassLoaderTemplateResolver();

    templateResolver.setPrefix("/templates/");
    templateResolver.setCacheable(false);
    templateResolver.setSuffix(".jsp");
    templateResolver.setTemplateMode("JAVASCRIPT");
    templateResolver.setCharacterEncoding("UTF-8");

    return templateResolver;
}

@Bean
@Description("Thymeleaf template engine with Spring integration")
public SpringTemplateEngine templateEngine() {

    var templateEngine = new SpringTemplateEngine();
    templateEngine.setTemplateResolver(templateResolver());

    return templateEngine;
}

@Bean
@Description("Thymeleaf view resolver")
public ViewResolver viewResolver() {

    var viewResolver = new ThymeleafViewResolver();

    viewResolver.setTemplateEngine(templateEngine());
    viewResolver.setCharacterEncoding("UTF-8");

    return viewResolver;
}

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("index");
}