Can't find the static resources with thymeleaf library in spring-boot - spring-boot

I want to have a quick test of how to use Thymeleaf and please see my two screenshots:
The home.html is under my templates/ directory, and it can be displayed correctly when I visit http://localhost:8090/. However, it failed to link to the two static files in the bottom of the home.html file:
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="js/home.js"></script>
<link href="css/home.css" rel="stylesheet" type="text/css"/>
Please see the error message:
I don't have specific thymeleaf configurations except the spring configurations:
## web
server.port=8090
## velocity
spring.velocity.allowRequestOverride=false
spring.velocity.allowSessionOverride=false
spring.velocity.cache=false
spring.velocity.checkTemplateLocation=true
spring.velocity.contentType=text/html
spring.velocity.toolbox-config-location=/WEB-INF/toolbox.xml
spring.velocity.exposeRequestAttributes=false
spring.velocity.exposeSessionAttributes=false
spring.velocity.exposeSpringMacroHelpers=false
spring.velocity.resourceLoaderPath=/WEB-INF/templates/
spring.velocity.suffix=.vm
spring.velocity.templateEncoding=UTF-8
spring.velocity.charset=UTF-8
spring.velocity.properties.input.encoding=UTF-8
spring.velocity.properties.output.encoding=UTF-8
spring.velocity.requestContextAttribute=rc
spring.mvc.favicon.enabled = false
logging.config=classpath:log4j2.xml
And my controller:
#RequestMapping("/")
public String welcome(Model model) {
LOGGER.info("Run Successfully");
return "home";
}
My main class:
#SpringBootApplication
#Import({WebConfigurer.class})
#ComponentScan("com.jdd.jnlu.qe")
#PropertySource({"classpath:boot.properties", "classpath:important.properties", "classpath:jss.properties",
"classpath:system.properties", "classpath:ump.properties"})
#EnableAutoConfiguration
public class JnluQEWebStart extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(JnluQEWebStart.class, args);
}
}

Since you're using Thymeleaf, try this:
<script th:src="#{/js/home.js}"></script>
<link th:href="#{/css/home.css}" rel="stylesheet" type="text/css"/>
Don't forget to register Thymeleaf in your page:
<html xmlns:th="http://www.thymeleaf.org">

Related

Could not resolve view with name 'index' in Spring Boot

Spring boot: 2.3.3.RELEASE
Java: 11
I use webflux + RouterFunction + Thymeleaf and encounter the error "Could not resolve view with name 'index'".
index.html is under "resources/templates".
I put some source code looks important.
Are we not able to use Thymeleaf if we use "RouterFunction"?
Please feel free to put a comment if you need more detail.
######## handler ###########
#Component
public class ItemHandler {
public RouterFunction<ServerResponse> routes = route()
.path("/item", builder -> builder.GET("/", this::index))
.build();
public Mono<ServerResponse> index(ServerRequest request) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("items", "Hello");
return ServerResponse.ok().contentType(MediaType.TEXT_HTML)
.render("index", attributes);
}
}
######## index.html ###########
<!DOCTYPE html>
<html lang="ja"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
</head>
<body>
<h1>FluxTest</h1>
</body>
</html>
######## entry point ###########
#SpringBootApplication
public class DemoWebfluxApplication {
public static void main(String[] args) {
SpringApplication.run(DemoWebfluxApplication.class, args);
}
}
The default property in charge of handling the location of static files is spring.resources.static-locations.
The default values are /META-INF/resources/, /resources/, /static/, /public/. You can either override the default values or put your index.html in one of these locations.

Thymeleaf : relative url - without a webcontext

I get this infamous error:
cannot be context relative (/) or page relative unless you implement
the IWebContext
I have a spring boot application (without the web module) that creates pdf files.
I am planning to use an HTML file as a template, but I could not link the css file nor the image properly due to these url issues.
Html :
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Company Invoice</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" media="all"
href="./css/company.css" th:href="#{./css/company.css}"/>
</head>
<body>
<p th:utext="#{home.welcome}">Welcome !</p>
<img src="/images/gtvglogo.png" th:src="#{/images/gtvglogo.png}"/>
</body>
</html>
folder structure:
src/main/resources/templates/sample.html
src/main/resources/templates/css/sample.css
I googled a bit but I donT want to solve this via IWebContext.
Is there another way?
Thanks in advance.
org.thymeleaf.exceptions.TemplateProcessingException: Link base
"/a/relative/link" cannot be context
relative (/...) unless the context used for executing the engine
implements the org.thymeleaf.context.IWebContext interface (template:
"templates/a-template" - line 6, col 13)
1 at org.thymeleaf.linkbuilder.StandardLinkBuilder.computeContextPath
(StandardLinkBuilder.java:493)
...
The exception is thrown by the org.thymeleaf.linkbuilder.StandardLinkBuilder. By providing a different implementation of org.thymeleaf.linkbuilder.ILinkBuilder to the TemplateEngine we can avoid this expception
TemplateEngine templateEngine = new TemplateEngine();
templateEngine.setLinkBuilder(new ILinkBuilder() {
#Override
public String getName() {
return null;
}
#Override
public Integer getOrder() {
return null;
}
#Override
public String buildLink(IExpressionContext context, String base, Map<String, Object> parameters) {
return null;
}
});

Spring Boot, static resources and mime type configuration

I'm facing a Spring Boot configuration issue I can't deal with...
I'm trying to build an HelloWorld example for HbbTV with Spring Boot, so I need to serve my "index.html" page with mime-type="application/vnd.hbbtv.xhtml+xml"
my index.html will be accessed as a static page, for instance http://myserver.com/index.html?param=value.
with the following code, no matter how hard I try, I get a text/html content type.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//HbbTV//1.1.1//EN" "http://www.hbbtv.org/dtd/HbbTV-1.1.1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>MyApp HBBTV</title>
<meta http-equiv="content-type" content="Content-Type: application/vnd.hbbtv.xhtml+xml; charset=UTF-8" />
</head>
<body>
...
</body>
</html>
So I tried to add a "home()" endpoint into a #Controller to force the correct mime-type, and that works.
#RestController
public class HbbTVController {
#RequestMapping(value = "/hbbtv", produces = "application/vnd.hbbtv.xhtml+xml")
String home() {
return "someText";
}
...
}
"That works" mean the jetty server serves me a html file with the correct content-type containing the test someText.
My next try were to replace the #RestController by #Controller (same produce config), and replace "someText" by index.html
#Controller
public class HbbTVController {
#RequestMapping(value = "/hbbtv", produces = "application/vnd.hbbtv.xhtml+xml")
String home() {
return "index.html";
}
...
}
Well, it serves my index.html correctly, but the Content-Type is wrong : text/html instead of application/vnd.hbbtv.xhtml+xml.
Furthermore, I don't want to access to myserver.com/hbbtv to get index.html, but directly to myserver.com/index.html.
How could I do that ?
Thanks...
Well, finally, I found the "Spring boot compliant solution". It's the same as Jamie Birch suggested, but realized with Spring mechanisms.
Spring Boot 1:
#Configuration
public class HbbtvMimeMapping implements EmbeddedServletContainerCustomizer {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
mappings.add("html", "application/vnd.hbbtv.xhtml+xml; charset=utf-8");
mappings.add("xhtml", "application/vnd.hbbtv.xhtml+xml; charset=utf-8");
container.setMimeMappings(mappings);
}
}
Spring Boot 2:
#Configuration
public class HbbtvMimeMapping implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
#Override
public void customize(ConfigurableServletWebServerFactory factory) {
MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
mappings.add("html", "application/vnd.hbbtv.xhtml+xml; charset=utf-8");
mappings.add("xhtml", "application/vnd.hbbtv.xhtml+xml; charset=utf-8");
factory.setMimeMappings(mappings);
}
}
I'll extend comment providen by #Cheloute
Sping boot have default mime types
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/MimeMappings.java
to override already setted mime type you should remove it first
Here is example what I used to override js and css
#Configuration
public class CustomServletConfiguration implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
#Override
public void customize(ConfigurableServletWebServerFactory factory) {
MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
mappings.remove("js");
mappings.add("js", "application/javascript;charset=utf-8");
mappings.remove("css");
mappings.add("css", "text/css;charset=utf-8");
factory.setMimeMappings(mappings);
factory.setPort(9000);
}
}
Can't help with the Spring Boot side, but if you get no other responses, try these:
Set the file-type as .xhtml rather than .html.
Provide a mapping from .xhtml to MIME type application/vnd.hbbtv.xhtml+xml on your Jetty server's mime.properties file. A few more details on how to do that here.

Thymeleaf Template (Spring MVC) unable to locate static resource

Problem with Thymeleaf Template locating the static files placed inside the root directory of the web app (including the CSS File below). I have added the relevant mapping (/resource) via addResourceHandlers() method (see config class below).
Maybe it has something to do with the recent switch to gradle (previously Maven). I may have overlooked something in build.gradle file?
<link rel="stylesheet" th:href="#{'/resources/stylesheets/test.css'}" type="text/css" media="screen" />
Browser console output (on page load)
Resource interpreted as Stylesheet but transferred with MIME type text/html: "http://localhost:8080/resources/stylesheets/test.css".
Thymeleaf
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:tiles="http://www.thymeleaf.org">
<head>
<!--Stylesheets -->
<link rel="stylesheet" th:href="#{'/resources/stylesheets/test.css'}" type="text/css" media="screen" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
</head>
...
</html>
Structure of .war directory
- root/
--stylesheets/
--- test.css
--images/
--META-INF/
--WEB-INF/
--...
Config Class
#Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/")
.setCachePeriod(31556926);
}
...
}
Gradle build file
buildscript {
repositories {
mavenLocal()
jcenter()
}
dependencies {
classpath 'com.bmuschko:gradle-tomcat-plugin:2.2.2'
}
}
plugins {
id "com.bmuschko.tomcat" version "2.2.2"
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'war'
apply plugin: 'com.bmuschko.tomcat-base'
version = '1.0'
group = 'com.project'
sourceCompatibility = 1.8
targetCompatibility = 1.8
war {
baseName = '/'
archiveName = "${project.name}.war"
}
war.doLast {
ant.unzip(src: war.archivePath, dest: "$buildDir/$project.name")
}
sourceSets {
main {
java{
srcDir 'src/main/java'
}
resources {
srcDir 'src/main/resources'
}
}
test {
java {
srcDir 'src/test/java'
}
resources {
srcDir 'src/test/resources'
}
}
}
dependencies {
modules {
module("javassist:javassist") {
replacedBy("org.javassist:javassist")
}
}
tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
"org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}"
tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") {
exclude group: "org.eclipse.jdt.core.compiler", module: "ecj"
}
....
}
repositories {
jcenter()
mavenCentral()
mavenLocal()
}
task wrapper(type: Wrapper) {
gradleVersion = '2.6'
}
jar {
manifest {
attributes 'Implementation-Title': 'App',
'Implementation-Version': version
}
}
test {
systemProperties 'property': 'value'
testLogging {
// Show that tests are run in the command-line output
events 'started', 'passed'
exceptionFormat "full"
showStandardStreams = true
showCauses = true
showExceptions = true
}
}
It turns out the class level RequestMapping inside the Controller was the cause. Had to Change it to method level (see below).
Wrong
#Controller("/register")
public class RegistrationController {
#RequestMapping(method = RequestMethod.GET)
public String showRegistrationForm(WebRequest request, Model model) {
return "...";
}
Correct
#Controller
public class RegistrationController {
#RequestMapping(value="/register",method = RequestMethod.GET)
public String showRegistrationForm(WebRequest request, Model model) {
return "...";
}
You must locate your static resources into "src/main/webapp/resources/static" folder(not in "Java Resources/src/main/resources" ). (If you work on Eclipse, you may see "src" folder several times).
At MvcConfig.java you should add the static resource' link and accepted pattern as belove.
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/","/resources/");
}
In your html page use the static resource link with thymleaf presentation.
<link th:href="#{./resources/static/css/bootstrap.min.css}" type="text/css" rel="stylesheet" media="screen"></link>
Why don't you try appending the context path (~) like below.
The symbol "~" will be considered to be relative to the server root.
<link rel="stylesheet" th:href="#{'~/resources/stylesheets/test.css'}" type="text/css" media="screen" />
I hope this helps.
You may locate the resource to the classpath like this:
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/")
.setCachePeriod(31556926);
And I suggest you should add the directory name:
registry.addResourceHandler("/resources/stylesheets/**").addResourceLocations("classpath:/stylesheets/")
.setCachePeriod(31556926);
You do not need to modify other files any more.
<link rel="stylesheet" th:href="#{/resources/stylesheets/test.css}" type="text/css" media="screen" />
Try without ' ' because you are making reference to a resource not a string. Also for making even better and just in case that not all your code is Thymeleaf you should do something like:
<link rel="stylesheet" href="../resources/stylesheets/test.css" th:href="#{/resources/stylesheets/test.css}" type="text/css" media="screen" />

org.thymeleaf.exceptions.TemplateInputException

I am having some serious issues with my Spring 4 / Thymeleaf setup. This is the error message:
Error resolving template "public/bootstrap/js/bootstrap.min", template might not exist or might not be accessible by any of the configured Template Resolvers
For some reason, Spring or Thymeleaf is treating css and js as if they are not static and trying to process them as if they were a request. I have 3 template resolvers:
#Bean()
public TemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
resolver.setOrder(0);
return resolver;
}
#Bean()
public TemplateResolver publicTemplateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/templates/default/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
resolver.setOrder(1);
return resolver;
}
#Bean()
public TemplateResolver customPublicTemplateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/templates/custom/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(false);
resolver.setOrder(2);
return resolver;
}
The pages are being served, the only issue is that the css and js is not. I am getting an error for each and every css and js that is included in the .html file. I literally moved a test css file to every possible directory trying to access it, but I am out of ideas at this point. Please let me know what I am doing wrong and if I need to further configure something.
EDIT 03/31/2015
src/main/webapp/templates/default/page99.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" media="all" href="resources/css/main.css"/>
</head>
<body>
<h1 th:text="${content.title}"> PAGE 99 (/templates/default/page99.html)</h1>
<p th:text="${content.body}">This is dummy content</p>
</body>
</html>
The css is a simple file that only sets the background color, just so I can see it working.
when you reference items on your server you should use the thymeleaf # method for this in the corresponding thymeleaf attributes.
Like:
<link th:href="#{/css/style.css}" href="style.css" rel="stylesheet" type="text/css"/>
This generates correct URLs for you.
The css is in my case in src/main/resources/static/css/style.css

Resources