Issue
There seems to be problem if using thymeleaf for multiple projects.
Let's say I have a spring application in project 2 & the controller in project 1. With proper @ComponentScan defined, the application able to display the view/html in my template folder. But once I added the thymeleaf-layout-dialect maven dependency, it failed with "There was an unexpected error (type=Not Found, status=404)." error.
My projects:
The prj1 pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>macrohard.org</groupId>
<artifactId>prj1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>
</dependencies>
</project>
The prj2 pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>macrohard.org</groupId>
<artifactId>prj2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>macrohard.org</groupId>
<artifactId>prj1</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
The hello-world.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>HW</title>
</head>
<body>
Hello World!!
</body>
</html>
The App2 in prj2:
package prj2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = { "prj1"} )
public class App2 {
public static void main(String[] args) {
SpringApplication.run(App2.class, args);
}
}
The Controller1 in prj1
package prj1.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
@RestController
@RequestMapping(value="/api")
public class Controller1 {
// this can be run by App2 & App1
@GetMapping(value="/hello")
public String hello() {
return "hello world";
}
// this can be run by App1 only
@GetMapping(value="/hello2")
public ModelAndView hello2() {
ModelAndView mav = new ModelAndView();
mav.setViewName("hello-world");
return mav;
}
}
As in Controller1, The "api/hello" can be requested successfully because it doesn't involve the template. But for the "api/hello2" request, it unable to render the hello-world.html. Here are the error stacks:
2019-07-02 22:21:28.758 INFO 19680 --- [ main] prj2.App2 : Started App2 in 1.89 seconds (JVM running for 2.454)
2019-07-02 22:21:51.807 INFO 19680 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-07-02 22:21:51.807 INFO 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-07-02 22:21:51.807 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Detected org.springframework.web.multipart.support.StandardServletMultipartResolver@2ded92
2019-07-02 22:21:51.810 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : No LocaleResolver 'localeResolver': using default [AcceptHeaderLocaleResolver]
2019-07-02 22:21:51.811 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : No ThemeResolver 'themeResolver': using default [FixedThemeResolver]
2019-07-02 22:21:51.814 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : No RequestToViewNameTranslator 'viewNameTranslator': using default [DefaultRequestToViewNameTranslator]
2019-07-02 22:21:51.817 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : No FlashMapManager 'flashMapManager': using default [SessionFlashMapManager]
2019-07-02 22:21:51.817 DEBUG 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
2019-07-02 22:21:51.817 INFO 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 10 ms
2019-07-02 22:21:51.829 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : GET "/api/hello2", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2019-07-02 22:21:51.834 TRACE 19680 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.web.servlet.ModelAndView prj1.web.Controller1.hello2()
2019-07-02 22:21:51.843 TRACE 19680 --- [nio-8080-exec-1] .w.s.m.m.a.ServletInvocableHandlerMethod : Arguments: []
2019-07-02 22:21:51.851 DEBUG 19680 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, application/xhtml+xml, image/webp, image/apng, application/signed-exchange;v=b3, application/xml;q=0.9, */*;q=0.8]
2019-07-02 22:21:51.851 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Rendering view [org.springframework.web.servlet.view.InternalResourceView: name 'hello-world'; URL [hello-world]]
2019-07-02 22:21:51.851 DEBUG 19680 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView : View name 'hello-world', model {}
2019-07-02 22:21:51.853 DEBUG 19680 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView : Forwarding to [hello-world]
2019-07-02 22:21:51.857 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : "FORWARD" dispatch for GET "/api/hello-world", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2019-07-02 22:21:51.860 TRACE 19680 --- [nio-8080-exec-1] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to HandlerExecutionChain with [ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]] and 3 interceptors
2019-07-02 22:21:51.862 DEBUG 19680 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler : Resource not found
2019-07-02 22:21:51.862 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : No view rendering, null ModelAndView returned.
2019-07-02 22:21:51.862 DEBUG 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Exiting from "FORWARD" dispatch, status 404, headers={}
2019-07-02 22:21:51.864 DEBUG 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed 404 NOT_FOUND, headers={}
2019-07-02 22:21:51.865 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2019-07-02 22:21:51.865 TRACE 19680 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : 2 matching mappings: [{ /error, produces [text/html]}, { /error}]
2019-07-02 22:21:51.866 TRACE 19680 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2019-07-02 22:21:51.875 TRACE 19680 --- [nio-8080-exec-1] .w.s.m.m.a.ServletInvocableHandlerMethod : Arguments: [org.apache.catalina.core.ApplicationHttpRequest@6fdc83, org.apache.catalina.connector.ResponseFacade@119a78b]
2019-07-02 22:21:51.885 DEBUG 19680 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Selected 'text/html' given [text/html, text/html;q=0.8]
2019-07-02 22:21:51.886 TRACE 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Rendering view [org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration$StaticView@216e30]
2019-07-02 22:21:51.908 DEBUG 19680 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 404, headers={}
I am certain that it is due to thymeleaf-layout-dialect, because if I remove it from pom.xml everything work fine. The problem is I need it to layout thymeleaf page. How to display the template in another different project from spring application?
Solution
As you have published an example project, I can't follow the issue :/
Are you sure you did not just confuse the "hello world" messages from the controller with the message from the template?
When I modify: \prj1\src\main\resources\templates\hello-world.html
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>HW</title>
</head>
<body>
Hello World!! (from Template in prj1)!
</body>
</html>
I had to add this into pom.xml of prj1 because of some weird classpath issue: (the thymeleaf-layout-dialect lib you use seems to bring in an additional thymeleaf jar - did not investigate that)
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
When I run prj2 app and call: http://localhost:8080/api/hello3
or http://localhost:8080/api/hello2
I get:
Hello World!! (from Template in prj1)!
Which is what we want?
When I call: http://localhost:8080/api/hello
I get an error because of some not found template ("hello world" is of course not a template file).
So I'm not sure why it does not work for you :/
Answered By - wemu
Answer Checked By - Mary Flores (JavaFixing Volunteer)