I want to make page using thymeleaf. But I have some problem with the static files. I've investigated questions(1,2,3) with similar problem, but it didn't help me.
I use Spring Boot framework in the application.
My files look like:
test.html
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<script src="js/test.js" th:src="#{/test.js}"/>
</head>
<body>
<button onclick="testFunction('test value')">Button</button>
</body>
</html>
test.js
function testFunction(test) {
console.log(test);
}
Configuration class
#Configuration
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/js/");
super.addResourceHandlers(registry);
}
}
And problem, when I load test.html file with javascript not loaded.
#GetMapping(value = "web/test")
public String getTestHtmlPage() {
return "test";
}
/api/v1 is a configuration in application.properties => server.servlet-path=/api/v1
What do I do wrong? Can you help me?
Thanks all!
For a better understanding of registry.addResourceHandler("/**").addResourceLocations("classpath:/static/js/");
I wrote a more thorough answer here that discusses invalid resource location mappings. It didn't receive any upvotes, so I hope it's not terrible. :-)
In short, with the way you're mapping classpath:/static/js/, and then accessing, /js/test.js, you're telling Spring to look in /static/js/js/test.js.
What you probably want is classpath:/static/. In that case, when you try to access /js/test.js, it's looking in /static/js/test.js for the file instead.
As for Thymeleaf, I've never used it, but docs indicate you should load scripts with th:src instead of th:href. th:href appears to only be for HTML content.
Related
I am very new to Spring Boot framework and want to clarify why I am facing with this issue.
Issue: .jsp file is not shown at the correct endpoint.
this is my controller class
#Controller
public class HomeController {
#RequestMapping("home")
public String home() {
System.out.println("Hello World");
return "home.jsp";
}
}
This is my application.properties class
spring.mvc.view.prefix = /webapp/
spring.mvc.view.suffix = .jsp
this is what I have inside home.jsp file
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Change Titlte</title>
</head>
<body>
Hello
</body>
</html>
and lastly, the project directory
When I start spring boot app the site looks like this
Why do you think I can't see the content of home.jsp file?
Any help is appreciated.
Best,
PS: I already added Tomcat Jasper libraries in the pom.xml file
Check this simple examle. It seems you should not use .jsp extension in controller's return statement. Don't forget to specify method of your endpoint. Use #GetMapping instead of #RequestMapping
Also you'd better switch to Spring MVC thymeleaf that works good with html files. jsp - is used mostly for Java EE projects.
There are several things to notice here.
Change mapping to /home instead.
View resolver is configured already, return "home" instead of "home.jsp".
Take Model object as an argument it will be useful.
home(ModelMap model)
I'm experience problems loading static resources like images, css styles, etc.... in spring 5
when I add security, without security it load ok
THis is how I done.
First, I create a project using Spring Starter Project in Eclipse Photon
Spring Boot Version: 2.2.6
Add some dependencies:
Spring web
Thymeleaf
Spring Security
Spring Boot DevTools
Spring Boot Actuator
Run the project and I use generated security password and everything ok.
Now I add statics resources
So I create a folder called /assets/imgs
in src/main/resources/static/
I that folder I add a fake image to use in, called fake-image.png
I create a class, with a user and password and patterns to permit my resources.
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/resources/**", "/static/**","/src/main/resources/**").permitAll().and()
.formLogin().loginPage("/login").permitAll()
.usernameParameter("username").passwordParameter("password")
.defaultSuccessUrl("/loginsuccess").permitAll().and()
.logout().permitAll();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder builder) throws Exception {
PasswordEncoder encoder = passwordEncoder();
UserBuilder users = User.builder().passwordEncoder(encoder::encode);
//User to login
builder.inMemoryAuthentication()
.withUser(users.username("admin").password("q").roles("ADMIN"));
}
}
I create a class to add my login form
#EnableWebMvc
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/").setViewName("login");
}
}
Finally I add a login.html page like this, to show a simple image
<!DOCTYPE html>
<html lang="es" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="" />
<meta name="author" content="" />
<meta name="ctx" th:content="#{/}" />
<title>Test Static Files</title>
</head>
<body>
<div class="container">
<div class="row no-gutters mt-3">
<div class="col columna-banner">
<img class="img-fluid rounded login-banner-image"
th:src="#{/assets/imgs/fake-image.png}" />
</div>
</div>
</div>
</body>
</html>
In eclipse console I get this warning message:
WARN 1434 --- [nio-8080-exec-2] o.s.web.servlet.PageNotFound : No mapping for GET /assets/imgs/fake-image.png
UPDATE 1:
Added code to github:
https://github.com/davisoski/stackoverflow-static-files
Am I missing something?
Any suggestion?
Thanks
it seems that you forget to add something like this
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/")
.setCachePeriod(31556926);
}
into your WebConfig class
Do you configure the static location in your properties.
like spring.resources.static-location=classpath:/static/assets/imgs/
Actually 3 things to know/consider:
Build (maven/gradle)
Without further configuration all content of sry/main/resources/ folder will be copied into your "classpath root" (classpath:/).
(Url2Class) Path mapping
Current spring-boot offers/predefines this property:
(key=)spring.resources.static-locations
(value=)classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/
(description=)Locations of static resources. Defaults to classpath:[/META-INF/resources/, /resources/, /static/, /public/].
(Value can be a comma separated list of (classpath) locations.)
If You are using mvc this is also interesting:
spring.mvc.static-path-pattern
/**
Path pattern used for static resources.
(means: everything from spring.resources.static-locations is mapped against /**, experiment with this and your security config...)
..for web-flux rather:
spring.webflux.static-path-pattern
/**
Path pattern used for static resources.
So up to this point, it is important to know "where your file lands", and to what url it will be mapped/exposed.
Your options with this are:
(preferred) Comply with pre-defined locations.
Override spring.resources.static-locations property.
(least preferred) Introduce a "custom mapping/hadler".
Security config
Your security config should align with (what you want to allow and with) what url (pattern)s you want to serve. And it is common practice to permit access to static resources.
Regarding OP:
src/main/resources/static/assets/* is available on the class path and (by default) exposed via the url /static/assets/*.
So, please correct in your html file to: th:src="#{/static/assets/imgs/fake-image.png}". (And the 404 more comprehensible, now.)
And then it should work with: .authorizeRequests().antMatchers("/static/**").permitAll().
So I'm trying to just follow instructions for simple Spring Boot project using devtools+mustache+data-jpa. I'm just copy-pasting the whole thing and it doesn't work, even thought tutorial says "Just press the button and it works". Full source code is here, some listings I will provide in the end.
All I want to do is to redirect to index.html from localhost:8080/ and insert simple value into the template.
But instead:
1. Something redirects me from / to /apex/f?p=4950:1 for some reason
2. If I change mapping to #GetMapping("/home") and try localhost:8080/home I get 404
After enabling logging I found out that PathResourceResolver doesn't scan the /resources/templates directory. And if I add dependency on Thymeleaf, it finds it.
So the question is where is the problem? Should I add some config file? Or Mustache isn't working like that?
IndexController.java
#Controller
public class IndexController {
#GetMapping("/")
public ModelAndView home() {
Map<String, String> model = new HashMap<>();
model.put( "name", "Alex" );
return new ModelAndView( "index", model );
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Welcome to Spring, {{ name }}</h1>
</body>
</html>
Dependencies
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-mustache')
compile('org.springframework.boot:spring-boot-starter-web')
runtime('org.springframework.boot:spring-boot-devtools')
runtime('com.h2database:h2')
testCompile('org.springframework.boot:spring-boot-starter-test')
Structure
Log
In order for given demo app to work, please add following to the main/resources/application.properties
spring.mustache.prefix=classpath:/templates/
spring.mustache.suffix=.html
This will tell Spring where to look for Mustache views and what extension those are supposed to have.
I have created a Spring Boot application with Intellij. It creates a sample web application with a controller and an empty html page.
But problem is this sample application returns "Whitelabel Error Page" when I go to "http://localhost:8080/info/aa". I think It cannot find info.html file. Is there any way to fix this?
Here is sample controller;
#Controller
#RequestMapping("/info")
public class InfoController {
#RequestMapping("/aa")
public String getServerInfo(Map<String, Object> model){
model.put("message", "server info");
return "info";
}
}
My project directory;
EDIT: My html file info.html;
<!DOCTYPE html>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html lang="en">
<head>
</head>
<body>
</body>
</html>
EDIT 2: I update my html directory to templates/info.html
DemoApplication class;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
And application.properties file is empty.
If your info.html is actually a template file then it obviously shouldn't be in a static content, it should be in a templates folder, as its not static.
Here is an example: https://spring.io/guides/gs/serving-web-content/
Under static folder you have all static content, which wouldn't change when you serve it, for example, images, css, js scripts and so on.
Under templates folder you store templates from which spring + its template ending(for example thymeleaf) will generate actual html, using your model, which will be served to a client.
Also if you have a subfolder in templates like templates/info/info.html then you should return info/info as a template name from your controller, not just info.
However if you are using jsp then its something different, and you shouldn't use template folder, you should create webapp/WEB-INF/jsp/ folders and put it there and you should name your template info.jsp then, instead of info.html
Example here:
https://www.mkyong.com/spring-boot/spring-boot-hello-world-example-jsp/
You don't have to put your info.html into static/info folder inside your resources, instead put it into templates.
The #RequestMapping on top of your InfoController class does not tell where to find the requested html files, it is just a mapping for your request.
If you want to have separates folder for different html pages you can have the info folder inside of your templates folder, but you still have to refer is in your controller as info/info:
#RequestMapping("/aa")
public String getServerInfo(Map<String, Object> model){
model.put("message", "server info");
return "info/info";
}
If you want to use JSP (like I see you want) first of all move the html files to the folder:
/src/java/webapp/
and change the extension to .jsp. Then you will have your view file in:
/src/java/webapp/info/info.jsp
Secondly you have to add configuration for view resolving:
#Configuration
#EnableWebMvc
public class WebConfiguration {
#Bean
public ViewResolver getViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/templates/");
resolver.setSuffix(".jsp");
return resolver;
}
}
And in the controller rember to return path of the file - you have configured head to .../templates and you have to return info/info:
#RequestMapping("/info")
public String info() {
return "info/info";
}
I'm going through this Spring tutorial online form springsource.org.
http://static.springsource.org/docs/Spring-MVC-step-by-step/part2.html
In Chapter 2, at the end, it has you add a bean to prefix and suffix /WEB-INF/jsp/ and .jsp to responses.
The code so far should basically load index.jsp when you go to localhost:8080/springapp/ which will redirect to localhost:8080/springapp/hello.htm which creates an instance of the HelloController which should in theory send you over to /WEB-INF/jsp/hello.jsp. When I added the prefix/suffix bean and changed all my references to just "hello" instead of the fully pathed jsp file, I started getting the following error:
message Handler processing failed; nested exception is
java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/fmt/LocalizationContext
I've tried going back through the samples several times and checking for typo's and I still can't find the problem. Any tips or pointers?
index.jsp (in the root of the webapp:
<%# include file="/WEB-INF/jsp/include.jsp" %>
<%-- Redirected because we can't set the welcome page to a virtual URL. --%>
<c:redirect url="/hello.htm" />
HelloController.java (minus the imports and package:
public class HelloController implements Controller {
protected final Log logger = LogFactory.getLog(getClass());
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String now = (new Date()).toString();
logger.info("Returning hello view with " + now);
return new ModelAndView("hello", "now", now);
}
}
My hello.jsp file:
<%# include file="/WEB-INF/jsp/include.jsp" %>
<!DOCTYPE html>
<html>
<head>
<title>Hello :: Spring Application</title>
</head>
<body>
<h1>Hello - Spring Application</h1>
<p>Greetings, it is now <c:out value="${now}" /></p>
</body>
</html>
It seems like you are missing the JSTL jar here. Try downloading it and place it in your classpath to see if it works: Where can I download JSTL jar
It seems certain required jar(s) are missing from classpath.
Make sure you have servlet-api-2.x.jar jsp-api-2.x.jar and jstl-1.x.jar on classpath
Please make sure the jstl.jar file is located in your WEB-INF/lib folder.
As a matter of fact, here is what is stated in the tutorial that you linked. I guess you missed this step:
We will be using the JSP Standard Tag Library (JSTL), so let's start
by copying the JSTL files we need to our 'WEB-INF/lib' directory. Copy
jstl.jar from the 'spring-framework-2.5/lib/j2ee' directory and
standard.jar from the 'spring-framework-2.5/lib/jakarta-taglibs'
directory to the 'springapp/war/WEB-INF/lib' directory.