47

I am very new to Spring. I am trying to build a MVC application using Spring Boot which shows a list of products. But i am getting the below error:

javax.servlet.ServletException: Circular view path [products]: would dispatch back to the current handler URL [/products] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)

Here is controller:

package com.springframeworkguru.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.springframeworkguru.services.ProductService;


    @Controller
    public class ProductController {

        private ProductService productService;

        @Autowired
        public void setProductService(ProductService productService) {
            this.productService = productService;
        }

        @RequestMapping("/products")
        public String listProducts(Model model){

            model.addAttribute("products", productService.listAllProducts());

            return "products";
        }

    }

This is the main class:

package com.springframeworkguru;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;

import com.springframeworkguru.controllers.ProductController;

@SpringBootApplication
public class SpringmvcApplication extends SpringBootServletInitializer{

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

and products.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Spring Core Online Tutorial - List Products</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>

    <link href="http://cdn.jsdelivr.net/webjars/bootstrap/3.3.4/css/bootstrap.min.css"
          th:href="@{/webjars/bootstrap/3.3.5/css/bootstrap.min.css}"
          rel="stylesheet" media="screen"/>

    <script src="http://cdn.jsdelivr.net/webjars/jquery/2.1.4/jquery.min.js"
            th:src="@{/webjars/jquery/2.1.4/jquery.min.js}"></script>

    <link href="../css/spring-core.css"
          th:href="@{css/spring-core.css}" rel="stylesheet" media="screen"/>
</head>
<body>
<div class="container">
    <div th:if="${not #lists.isEmpty(products)}">
        <h2>Product List</h2>
        <table class="table table-striped">
            <tr>
                <th>Id</th>
                <th>Description</th>
                <th>Price</th>
                <th>Image URL</th>
                <th>List</th>
            </tr>
            <tr th:each="product : ${products}">
                <td th:text="${product.id}"></td>
                <td th:text="${product.description}"></td>
                <td th:text="${product.price}"></td>
                <td th:text="${product.imageUrl}"></td>
                <td><a th:href="${'/product/' + product.id}">View</a> </td>
            </tr>
        </table>
    </div>
</div>

</body>
</html>

The products.html is in /static folder. Also, I am using Eclipse Kepler.

Ali Dehghani
  • 46,221
  • 15
  • 164
  • 151
sohan
  • 577
  • 1
  • 6
  • 9

12 Answers12

130

Adding spring-boot-starter-thymeleaf dependency solved the problem.

So add this to your pom.xml file:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Update: If you are working with Eclipse and you are using Gradle, this might not work. The reason is if you haven't imported the project as 'gradle project' Eclipse wont detect thymeleaf. So here's the solution:

Step1 : Run "gradle eclipse" on command line.

Step2 : Run "gradle wrapper"

Step3 : In eclipse import as gradle project (before this remove the already imported project)

Step4 : Now run using eclipse

Step5 : Enjoy!

Woodchuck
  • 3,869
  • 2
  • 39
  • 70
user18853
  • 2,771
  • 1
  • 21
  • 17
  • 5
    Wow! This really did solve my problem. It seems so silly to miss a dependency and get a completely different error message. The error message is also very deceiving. – Abhi Nov 21 '19 at 06:48
  • 1
    This worked for me. However, if using IntelliJ IDEA and maven, then just adding this dependency to your pom.xml may not be sufficient. In my case, I needed to also then go to: View > Tool Windows > Maven, then click "Reload all Maven Projects". Only after that did my project find spring-boot-starter-thymeleaf and then the run time "Circular view path..." error was resolved. – Woodchuck Nov 05 '21 at 23:12
  • The same is true for IntelliJ IDEA and Gradle. You may need to also View > Tool Windows > Gradle, then click "Reload all Gradle Projects". – SGT Grumpy Pants Sep 21 '22 at 18:13
40

You can also be here because:

  1. You forgot to put the @RestController of your rest controller over the class

  2. You set @Controller instead of @RestController

S.Daineko
  • 1,790
  • 1
  • 20
  • 29
  • 5
    +^ Thanks! This did the trick. I had put the `@Controller` and that didn't work, but adding `@RestController` made the circular dependency issue go away! – robot_alien Aug 26 '19 at 10:41
  • 3
    Thanks for the tip, for me it was a @ResponseBody. Better watch these annotations. – MaximumLasagna Jan 15 '20 at 16:58
  • 1
    This worked for me. As @robot_alien noted, I, too, was using `@Controller` instead of `@RestController` – shikharraje Mar 31 '20 at 08:03
  • 1
    Can anyone explain why `@RestController` working instead of `@Controller` ?? – Indrajeet Gour May 14 '20 at 19:02
  • 3
    @ RestController = @ Controller + @ ResponseBody. So if you put @Controller, in short, it is assumed that you will use the presentation (jsp, html, thymeleaf) and it should be configured for you. The error occurs due to the lack of settings for the presentation. – S.Daineko May 15 '20 at 07:54
  • 1
    @S.Dayneko I just had the same situation with replacing `@Controller` with `@RestController` and it worked fine, then came across your comment, it was really informative comment. I know I'm a bit late to this discussion. But, would you please tell me if `@RestController` would still work fine with `thymeleaf` because I was following a guide and they were using `@Controller`, especially I don't want to loose the auto mapping feature for the `template` directory that `thymeleaf` provide. Again, sorry for I'm bit late. – IBRAHIM Aug 06 '20 at 10:17
  • Thanks - saved me a bunch of time here – Matt Fellows Oct 02 '20 at 13:59
14

The products.html is /static folder

By default, Spring Boot will look for Thymeleaf templates in templates directory on the classpath. So move your products.html to src/main/resources/templates directory. You can read more about template engines and Spring Boot on the Spring Boot Documentation:

When you’re using thymeleaf templating engine with the default configuration, your templates will be picked up automatically from src/main/resources/templates

Also, static directory is where you should put your Static Contents, not your templates.

Ali Dehghani
  • 46,221
  • 15
  • 164
  • 151
  • i have done that. But the same error - javax.servlet.ServletException: Circular view path [products]: would dispatch back to the current handler URL [/products] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.). 2016-04-19 00:01:35.129 ERROR 3200 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet dispatcherServlet threw exception – sohan Apr 19 '16 at 05:03
  • 17
    Did you add the `spring-boot-starter-thymeleaf` dependency? – Ali Dehghani Apr 19 '16 at 15:39
  • 1
    Thanks a lot. It worked after adding spring-boot-starter-thymeleaf, spring-boot-starter-web dependency. – sohan Apr 20 '16 at 01:09
  • 1
    Thanks, It also worked after adding spring-boot-starter-thymeleaf and spring-boot-starter-web. – Hermandroid Nov 02 '16 at 05:26
14

Add the following dependency in pom.xml

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    <version>1.4.0.RELEASE</version>
</dependency>

The latest version could be found on mvnrepository

Mehraj Malik
  • 14,872
  • 15
  • 58
  • 85
  • 2
    When you specify a version for Thymeleaf be careful not to override the managed version for SpringBoot! This can sometimes cause problems. – Felix Apr 16 '18 at 17:32
7

Well I had the same problem using SpringBoot and all I did was replacing @Controller with @RestController and it worked fine.

kamau wairegi
  • 428
  • 4
  • 6
4

Convert @Controller to @RestController, this will fix the circular path problem.

Randomize
  • 8,651
  • 18
  • 78
  • 133
Mohini
  • 87
  • 6
3

By default, Spring Boot uses the InternalResourceView class as the view resolver. If the @GetMapping value is the same as the view name, the request fails with the circular view path error.

So one solution is to not to use the same name for a URL path and view name.

If we choose a Thymeleaf processor, the error is not there.

I had an example with Freemarker and had the circular view path error (Spring Boot 2.2.4). I had to rename the URL path.

Jan Bodnar
  • 10,969
  • 6
  • 68
  • 77
2

Problems can be caused by using an embedded servlet container (embedded tomcat). @mirmdasif answer

To resolve this use external tomcat server.

Configure tomcat server in STS/Eclipse:
1. from top menu: Window > Show View > Servers
2. in servers tab window context menu: New > Server
3. do project config to deploy WAR file to Tomcat.
4. run project as Spring Boot App

deploy WAR file to Tomcat
Main class should exteneds SpringBootServletInitializer and override SpringApplicationBuilder method...

package package_with_your_main_class;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class YourStartWebApplication extends SpringBootServletInitializer {

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

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(YourStartWebApplication.class);
    }
}

pom.xml should contains

<!-- Parent pom providing dependency and plugin management for applications -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <!-- this version works with tomcat 8.5, change to newest if you are using newer tomcat -->
    <version>2.0.9.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <java.version>1.8</java.version>
    <!-- The main class to start by executing java -jar -->
    <start-class>package_with_your_main_class.SpringBootWebApplication</start-class>
</properties>

<dependencies>
    <!-- springframework web starter module -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- templating language -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId> 
    </dependency>

    <!-- marked the embedded servlet container as provided -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

<packaging>war</packaging>
Adam Silenko
  • 3,025
  • 1
  • 14
  • 30
2

make sure you have enabled thymeleaf with spring in application.properties :

spring.thymeleaf.enabled=true

SAAD BELEFQIH
  • 352
  • 3
  • 8
2

For springboot 2.6.0, try @RestController to the class or @ResponseBody to the method.

e.g.

import org.springframework.web.bind.annotation.RestController;

...

@RestController
public class ProductController {

   private ProductService productService;

   @Autowired
   public void setProductService(ProductService productService) {
       this.productService = productService;
   }

   @RequestMapping("/products")
   public String listProducts(Model model){

       model.addAttribute("products", productService.listAllProducts());

       return "products";
   }
}    

or

import org.springframework.web.bind.annotation.ResponseBody;

...

@Controller
public class ProductController {

   private ProductService productService;

   @Autowired
   public void setProductService(ProductService productService) {
       this.productService = productService;
   }

   @RequestMapping("/products")
   @ResponseBody
   public String listProducts(Model model){

       model.addAttribute("products", productService.listAllProducts());

       return "products";
   }
}    


**********EDIT**********

The @RestController or @ResponseBody only render string or JSON string.

For Template, do not need @RestController or @ResponseBody.

First, try:

application.properties

spring.thymeleaf.enabled=true
spring.thymeleaf.check-template-location=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.mode=HTML
spring.thymeleaf.cache=false
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.suffix=.html

And put your templates file into resources/templates.

Second, adding a dependency to pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

And do not forget to reload all maven projects to download the new dependency.

Third, you should add <html lang="en" xmlns:th="http://www.thymeleaf.org"> to template file.

Forth, the template file name should be the same as the return clause in the controller. When you have return "products" in the controller, you should have the products.html template file in the templates folder.

Nick Dong
  • 3,638
  • 8
  • 47
  • 84
1

Rename "product.ftl" to "products.ftl".

Kilazur
  • 3,089
  • 1
  • 22
  • 48
1

In my case circular view path in spring boot 2 and jdk 11 was fixed by redirecting to index.html:

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            }
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("redirect:/index.html");
            }
        };
sermyro
  • 21
  • 2