I'm trying to serve an static resource (css file).
I already register the location and handler
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/resources/");
}
}
so the Tomcat's Logger displays the correct mapping to resource
Mapped URL path [/resources/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
When the browser renders the view, the inspector displays a 404 error trying to get the static resource.
AppInitializer.java
#Configuration
#ComponentScan("com.learning")
#EnableWebMvc
public class ApplicationInitializer extends WebMvcConfigurerAdapter implements WebApplicationInitializer {
private final Logger LOGGER = Logger.getLogger(ApplicationInitializer.class.getName());
public static final String DISPATCHER_SERVLET_NAME = "dispatcher";
#Autowired
private ApplicationContext applicationContext;
public ApplicationInitializer() {
}
//region Context Initialization Area
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext springContext = getSpringApplicationContext();
MyDispatcherServlet dispatcherServlet = new MyDispatcherServlet(springContext);
servletContext.addListener(new ContextLoaderListener(springContext));
servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE));
servletContext.getSessionCookieConfig().setHttpOnly(true);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet(DISPATCHER_SERVLET_NAME, dispatcherServlet);
dispatcher.addMapping("/");
dispatcher.setLoadOnStartup(1);
}
private WebApplicationContext getSpringApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
LOGGER.info(String.format("Registering springApplicationContext: %s", context));
// Loads into container first
context.register(ApplicationInitializer.class);
LOGGER.info(String.format("Registration success of springApplicationContext: %s", context));
return context;
}
//endregion
//region ViewResolver Region
#Bean
public ViewResolver viewResolver() {
//Runs after coontroller ends its execution. It receives the view name to be processed.
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
#Bean
public TemplateEngine templateEngine() {
// Processes the template
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(true);
engine.setTemplateResolver(templateResolver());
return engine;
}
private ITemplateResolver templateResolver() {
//Resolves templates with provided prefix and suffix
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
//endregion
//region ResourceHandler Region
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/resources/");
}
//endregion
}
Hello.html
h1 {
color: red;
text-align: center;
}
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="/resources/css/MyCss.css" th:href="#{/resources/css/MyCss.css}"/>
</head>
<body>
<h1 th:text="'Hello ' + ${name}">Hello World</h1>
</body>
</html>
It supposed to displays as the running snippet... but as I mentioned, the app is not able to find and load the resource.
Log File
Any help?
http://localhost:8080/resources/css/MyCss.css
you are missing the webapp name:
http://localhost:8080/webapp_name/resources/css/MyCss.css
Within your: link rel="stylesheet" ...
Use the Spring URL tag, in order to resolve your URL better.
Here is how i use to import bootstrap.min.css:
<link rel="stylesheet" href='<spring:url value="/resources/bootstrap/bootstrap.min.css"/>' type="text/css" />
Don't forget to add the taglib, like this:
<%# taglib prefix="spring" uri="http://www.springframework.org/tags" %>
Related
I am working on a springboot project that consumes a weather api and shows the data on the browser using react, Anyway, It seems that I am missing some configurations or I might need to move files around in my project, The error in the browser shows that the js/css files are not reachable :
GET http://localhost:8080/demo/resources/css/neo.css
browser.min.js:4 GET http://localhost:8080/demo/resources/js/WeatherManager.js 404 ()
browser.min.js:4 Uncaught Error: Could not load http://localhost:8080/demo/resources/js/WeatherManager.js
at XMLHttpRequest.xhr.onreadystatechange (browser.min.js:4)
* WebConfig *
#Configuration
#ComponentScan
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
/**
* We need to define 3 things to implement
* 1- Define message resource
* 2- Define Local resolver internationalization
* 3- Override interceptor
*/
#Bean
public MessageSource messageSource(){
ResourceBundleMessageSource messageSource=new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
#Bean
public LocaleResolver localeResolver(){
SessionLocaleResolver resolver =new SessionLocaleResolver();
resolver.setDefaultLocale(Locale.ENGLISH);
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
//you can add more resources here
registry.addResourceHandler("/css/**").addResourceLocations("/resources/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/resources/js/");
}
#Override
public void addInterceptors(InterceptorRegistry registry)
{
LocaleChangeInterceptor changeInterceptor=new LocaleChangeInterceptor();
changeInterceptor.setParamName("language");
registry.addInterceptor(changeInterceptor);
}
}
* WebAppInitializer *
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = getContext();
servletContext.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("*.html");
dispatcher.addMapping("*.pdf");
//Enable JSON response
dispatcher.addMapping("*.json");
dispatcher.addMapping("*.jsx");
}
private WebApplicationContext getContext() {
AnnotationConfigWebApplicationContext context =new AnnotationConfigWebApplicationContext();
context.register(WebConfig.class);
return context;
}
* DemoApplication *
#SpringBootApplication
#EnableAutoConfiguration
#EnableAsync
public class DemoApplication extends AsyncConfigurerSupport {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("WeatherService-");
executor.initialize();
return executor;
}
}
JS/CSS files live under /resources/css/ /resources/js/
JSP pages live under WEB-INF/jsp
** weather.jsp page **
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="resources/css/neo.css">
<title>Weather </title>
</head>
<body>
<div id="main" class="container">
</div>
<script type="text/babel" src="resources/js/WeatherManager.js"></script>
</body>
</html>
I have the source code at
github : [https://github.com/saifmasadeh/WeatherBoard][1]
You should add this to your question:
<script type="text/babel" src="resources/js/WeatherManager.js"></script>
<link rel="stylesheet" type="text/css" href="resources/css/neo.css">
This is where the problem is. You're importing via the wrong URL.
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry){
//you can add more resources here
registry.addResourceHandler("/css/**").addResourceLocations("/resources/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/resources/js/");
}
The above method says when a user tries to access a url with the path /js/** look in /resources/js/.
Basically, if the user were to request localhost/context-root/js/script.js
Spring would view this as localhost/context-root/resources/js/script.js
(That is not literally the case, but it explains the idea well enough.)
So when you try to import your script file resources/js/WeatherManager.js the resource handler doesn't know where to look. It doesn't know about anything with the path resources/**
What you want to do is import this way:
<script type="text/babel" src="/js/WeatherManager.js"></script>
This maps to the resource handler's "/js/** and looks up WeatherManager.js in /resources/js/. You need to do the same thing with your CSS file.
For another example of how this works, view my answer here.
(Also, you may need to use classpath:/resources/(js|css) as your resource location if this doesn't work.)
i collided with some problems when i was writing web app.
When i use URL like this http://localhost:8080/user i have no problems and my app work correctly, but when i use URL such as http://localhost:8080/some-intermediate-node/user i have pages without any style and java-script code.
Belong i show my dispatcher servlet config
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "com.excbooks.controller")
public class ServletConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css");
registry.addResourceHandler("/js/**").addResourceLocations("/js");
}
#Bean
public InternalResourceViewResolver setupViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix("");
resolver.setViewClass(JstlView.class);
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
and my controller
#Controller
public class MainController {
{
BasicConfigurator.configure();
}
#RequestMapping(value = "/d/login", method = RequestMethod.GET)
public String login(Model model){
return "log-in.html";
}
#RequestMapping(value = "/d/user", method = RequestMethod.GET)
public String userProfile(Model model){
User user = new User();
user.setId(new BigInteger("1"));
user.setUsername("Sashko");
model.addAttribute("user",user);
return "index.jsp";
}
}
Link to my JSP index https://drive.google.com/file/d/0B42ezhAKqwZlcUEyVkR5amNIaDg/view?usp=sharing
Within your JSP, I suspect the javacsript/css files are pulled in roughly like...
<link rel="stylesheet" href="css/my.css">
<script src="js/my.js"></script>
The issue is that the href and src attributes specify relative URLs. They correctly point to your files when the URL is http://localhost:8080/user, but when the URL is http://localhost:8080/some-intermediate-node/user the browser will look for...
http://localhost:8080/some-intermediate-node/css/my.css
http://localhost:8080/some-intermediate-node/js/my.js
respectively.
Change the href and src attributes so that they start with a forward slash (/) character.
Change CSS and javascript href to /css/** and /js/**
For example :
<link rel="stylesheet" href="/css/bootstrap.min.css">
<script src="/js/jquery-1.12.3.min.js"></script>
Hello I'm new in Thymeleaf and encountered a problem that might be trivial, but thymeleaf don't behave like it supposed to be. Just a little help will be much appreciated
I don't use spring boot for the matters of learning. Additionally, I am also pretty new to Spring. Might miss one or two things.
I have simple index.html like this
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Index 2</title>
</head>
<body>
<div th:replace="~{fragments/fragment1 :: fr1}"></div>
</body>
</html>
and fragment1.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
</head>
<body>
<div th:fragment="fr1"><h1>HERE IS FRAGMENTS 1</h1></div>
</body>
</html>
Supposedly it does resolve the template, but the result doesn't change at all.
here is what i get from the browser page source
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Index 2</title>
</head>
<body>
<div th:replace="~{fragments/fragment1 :: fr1}"></div>
</body>
</html>
and yes it exactly the same as raw index.html.
So I figured it might have something to do with the configuration, but it just looks fine for me. In my other learning project, it just works fine with the exactly same configuration.
Here is the configuration
/* package and imports */
#Configuration
#EnableWebMvc
#ComponentScan("com.eshop")
public class WebConfig extends WebMvcConfigurerAdapter {
private static final String UTF8 = "UTF-8";
private static final String VIEWS = "/WEB-INF/templates/";
private static final String RESOURCES_LOCATION = "/resources/";
private static final String RESOURCES_HANDLER = RESOURCES_LOCATION + "**";
//Thymeleaf Configuration
#Bean
public ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix(VIEWS);
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(false);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine(){
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setDialect(new SpringSecurityDialect());
return templateEngine;
}
#Bean
public ViewResolver viewResolver(){
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setCharacterEncoding(UTF8);
return viewResolver;
}
// tells DispatcherServlet to give static resources and not handle the resources itself
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
// handle various resources like javascript and css
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler( RESOURCES_HANDLER ).addResourceLocations( RESOURCES_LOCATION );
}
}
pom.xml
<!-- thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>3.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.0.RELEASE</version>
</dependency>
here is the project tree
webapp
|__resources
|__WEB-INF
|__i18n
|__templates
|__fragments
|__fragment1.html
|__index.html
What do I miss here and how can I fix this?
Try calling the th:replace without ~{}
<div th:replace="fragments/fragment1 :: fr1"></div>
Also make sure you have separate html file named fragment1.html
This Layouts tutorial should help you get going.
this is my project structure:
these are all classes of my sample to use spring i18n internationalization, but spring only use en_US for application localization:
SpringWebInitializer
public class SpringWebInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(SpringWebConfig.class);
rootContext.setServletContext(servletContext);
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(rootContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
servletContext.addListener(new RequestContextListener());
servletContext.addListener(new ContextLoaderListener(rootContext));
}
}
SpringWebConfig
#EnableWebMvc
#Configuration
#ComponentScan("com.rgh.web")
public class SpringWebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/view/");
viewResolver.setSuffix(".jsp");
viewResolver.setViewClass(JstlView.class);
return viewResolver;
}
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
localeResolver.setDefaultLocale(new Locale("fa"));
localeResolver.setCookieName("lang");
return localeResolver;
}
#Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}
index.jsp
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%# page contentType="text/html;charset=UTF-8" language="java"%>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<spring:message code="app.name" />
${pageContext.response.locale}
</body>
</html>
messages_fa.properties
app.name=MyAppFarsi
messages.properties
app.name=MyApp
I am trying to use layouts/templates with Thymeleaf but I'm getting the following exception.
Exception processing template "user/index": Error resolving template "/layouts/default.html", template might not exist or might not be accessible by any of the configured Template Resolvers
Here is my ThymeleafConfig.java
#Configuration
public class ThymeleafConfig {
#Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setOrder(1);
return resolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
engine.addDialect(new LayoutDialect());
engine.addDialect(new SpringSecurityDialect());
engine.addDialect(new SpringStandardDialect());
return engine;
}
#Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
return resolver;
}
}
I have the following folder structure
webapp/
..WEB-INF/
....views/
......layouts/
........default.html
......user
........index.html
Here is my default.html which is my main layout.
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Default</title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<header>
This is a header from default.html
</header>
<section layout:fragment="content">
<p>Content should go here!</p>
</section>
<footer>
Footer from default
<p layout:fragment="custom-footer">Custom footer here!</p>
</footer>
<!-- scripts -->
<script src="https://code.jquery.com/jquery-2.1.3.min.js" />
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
</body>
</html>
Here is the index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="layouts/default.html">
<head>
<title>Users</title>
</head>
<body>
<section layout:fragment="content">
<p>This is a paragraph from content page 1</p>
</section>
<footer>
<p layout:fragment="custom-footer">This is some footer content from content page 1</p>
</footer>
</body>
</html>
They are in different folders but the pathing should work unless I'm just missing something really silly.
I found my issue. If you specify the suffix in your Thymeleaf config you do not need the .html extension.
#Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".html"); // here
resolver.setTemplateMode("HTML5");
resolver.setOrder(1);
return resolver;
}
It should be:
layout:decorator="layouts/default"
Instead of:
layout:decorator="layouts/default.html"
I'm guessing it was effectively looking for layouts/default.html.html which would be a problem.
I solved this issue by having following code:
#Configuration
public class ThymeleafConfig{
#Bean
public SpringTemplateEngine springTemplateEngine()
{
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver());
return templateEngine;
}
#Bean
public SpringResourceTemplateResolver htmlTemplateResolver()
{
SpringResourceTemplateResolver emailTemplateResolver = new SpringResourceTemplateResolver();
emailTemplateResolver.setPrefix("classpath:/templates/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode(StandardTemplateModeHandlers.HTML5.getTemplateModeName());
emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return emailTemplateResolver;
}
}
The trick was to add: emailTemplateResolver.setPrefix("classpath:/templates/");
You should not give the extension.And you have to provide correct path like this
layout:decorator="../layouts/default"