Spring MVC cannot find *.jsp files - spring

I am an absolute noob when it comes to web development. But I got some background in C/C++/Java so I don't have a problem with MVC controllers. It's the configuration that is giving me the headache.
I am using Spring Boot. And according to the tutorials it can magically resolve everything without even opening an editor and typing a single character. Apparently not.
I have a view resolver configure as such:
#Configuration
#ComponentScan (basePackages = {"my.test.controller"})
#EnableAutoConfiguration
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public InternalResourceViewResolver getViewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
public static void main(String[] args) throws Exception {
SpringApplication.run(WebConfig.class, args);
}
}
I have a controller like this:
#Controller
public class PageController {
#RequestMapping(value = "/index")
public String doSomething() {
//.. do Something
return "/index";
}
My main problem is it cannot find the file if there is a jsp extension in the address.
If I type the url without an extension like localhost:8080/index the page is displayed properly.
If I type the url with an extension like localhost:8080/index.jsp the page returns a 404 error. This is the same for all pages declared in the controller.
Any help will be greatly appreciated. Thanks thanks.

There's a JSP sample in Spring Boot that you can crib from. If I were you I wouldn't define a ViewResolver since Boot already does that for you (but if you want to use prefix and suffix resolution you need to set spring.view.prefix and spring.view.suffix).
Your #Controller should return view names (not paths), so "index" is going to be resolved as "/WEB-INF/views/index.jsp" with your existing setup. I also wouldn't bother with the "/resources" mapping since one is already provided by Spring Boot, albeit a different one than you defined (normally people put static resources in "classpath:/static" but "classpath:/resources" works as well and there is no prefix for the path to the resource in the HTTP endpoints).
JSP is inferior to other view technologies in so many ways, so it is unfortunate that it is so ubiquitous. There are many limitations, including restrictions on the way you can package and run a Boot application (see here for details). It would be worth your effort to unlearn JSP if you can spare the time.

I remember having the same problem when I started with spring, the "url" that you use needs to correspond to a particular Request Mapping, not necessarily a particular page
for example
#RequestMapping(value = "/home")
public String doSomething() {
//.. do Something
return "/index";
}
will expose an endpoint at localhost:8080/home not localhost:8080/index or localhost:8080/index.jsp
A great example project is located at:
https://github.com/mariuszs/spring-boot-web-jsp-example

Well, I am not sure this answer will help you, as the question was posted in 2014. In order to help people resolve this question, I provide some of my resolutions. Hope this will help.
make sure your #Controller 's configuration #RequestMapping("/xx") cannot be the same as your view (jsp or templates)
For example, you have a view named home.html. You cannot let the #RequestMapping() be the same as the view's name. This will cause a circular error (--> Circular view path, added below).
How to fix this error, The path cannot be the name. (That's the JSP files mostly happen)
When you input the same name, you will get this:
Circular view path [preference]: would dispatch back to the current handler URL [/preference] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
Here is a link that explains why this error would happen.
This kind of error is only for the HTML5 file. When you get some wite page error and you are using the HTML5 file and cannot find other errors, that might be this one below
When you create an HTML file, the basic file will be the below code.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
</html>
The <meta charset="UTF-8"> didn't end with /> or </meta>.
When in the HTML5 file, that would be right. But Thymeleaf uses XHTML to load the file, so the <meta> should be closed.

If you mapped all of your requests to dispatcher servlet from web.xml,then it will check for the appropriate controller mappings.
You have mapped the request to /index so it can't process a /index.jsp
then internal view resolver will return the view just like you configured.
you can try
#RequestMapping(value = {"/index","/index.jsp"})
It is better to avoid .jsp extension in a web app.

Related

Automatically finding Thymeleaf templates with Spring Boot

How can I get Spring Boot and Thymeleaf to automatically find and map template files to be processed when accessed by the browser?
src/main/resources/templates/index.xhtml
src/main/resources/templates/bar.xhtml
src/main/resources/application.properties contains spring.thymeleaf.suffix=.xhtml
FooController.java contains #RequestMapping("/foo") and a #PostMapping method that returns bar
If I enter http://localhost:8080/ in the browser, Thymeleaf processes and displays the index.xhtml page with no extra configuration needed. But http://localhost:8080/index, http://localhost:8080/index.xhtml, and http://localhost:8080/index.html all result in 404 Not Found.
My index view does a POST to foo; FooController is activated and returns bar; and Thymeleaf processes and shows bar.xhtml, even though bar.xhtml isn't mapped anywhere in the configuration. Yet accessing http://localhost:8080/bar, http://localhost:8080/bar.xhtml, and http://localhost:8080/bar.html in a browser all result in 404 Not Found.
Why does GET http://localhost:8080/ process the index.xhtml template, but GET http://localhost:8080/index does not?
How can Thymleaf use bar as a view, but I cannot access http://localhost:8080/bar directly?
How can I configure Thymeleaf so that I can add src/main/resources/templates/example.xhtml and have it processed automatically as a template that I can access via http://localhost:8080/example in the browser, with no explicit configuration specifically for the example.xhtml file?
If I absolutely have to configure controllers (see my answer below), is there a way that I can at least do this in some declarative file, outside of my code?
As noted in Spring in Action, Fifth Edition, I can do something like this in a #Configuration class that implements WebMvcConfigurer
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
registry.addViewController("/bar");
}
That will allow me to process bar.xhtml automatically. (I presume there is some default configuration registry.addViewController("/").setViewName("index"), which is why my index.xhtml file is getting processed by accessing the root path.
And I can even use the following to automatically pick up any template:
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
registry.addViewController("/**");
}
Unfortunately this removes the mapping from / to /index, and also prevents accessing any static resources from src/main/resources. I'm not sure how to tell Thymeleaf to use a template if it can, and fall back to a static file if not.

Spring MVC Cannot configure views' path

I have a project that uses Spring Boot 2.2.5 (Spring version 5) - here is a link to a bare minimum project demonstrating my problem. In all the tutorials I followed they claim views' path can either be configured inside application.properties like this:
spring.mvc.view.prefix=/WEB-INF/jsp
spring.mvc.view.suffix=.jsp
or inside WebMvcConfigurationSupport derived class like this:
#Override
public void configureViewResolvers(final ViewResolverRegistry registry) {
registry.jsp("classpath:/", ".jsp");
}
or like this:
#Override
public void configureViewResolvers(final ViewResolverRegistry registry) {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
registry.viewResolver(resolver);
}
None of which work in my case. Spring will always serve .jsp files from src/main/webapp and from nowhere else in spite of my configuration or lack of it. No other file types will be served from that directory, not even HTML.
Some tutorials claim that when not configured Spring will serve anywhere from
src/main/resources/static
src/main/resources/public
src/main/resources/resources
src/main/java/META-INF/resources
I am yet to see this.
CSS and Javascript files will be served from src/main/resources but only if I have this in my MVC configuration:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/");
}
Configuring this from application.properties doesn't work
spring.resources.static-locations=classpath:/
In relation to this are there other special folder names like classpath: that can be used? I tried webapp: but it doesn't seem to be expanded
UPDATE: I thought for a moment that maybe subclassing WebMvcConfigurationSupport is to blame since it acts like #EnableWebMvc. Subclassing WebMvcConfigurer brought the following error. Placing #EnableWebMvc solves it.
An attempt was made to call a method that does not exist. The attempt was made from the following location:
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration.requestMappingHandlerAdapter(WebMvcAutoConfiguration.java:369)
The following method did not exist:
'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration.requestMappingHandlerAdapter(org.springframework.web.accept.ContentNegotiationManager, org.springframework.format.support.FormattingConversionService, org.springframework.validation.Validator)'
I read somewhere that JSP view are not supported inside embedded servlets. What a nice feature! Anyway I don't thing this is related to my problem.
I would like to stick to JSP and avoid Thymeleaf as my project is based on React. I will create MVC pages in order to be Search engine friendly, though but I will figure this out along the way.
Here is a screenshot of my project's layout

Spring: How can I keep routes in sync with URLs on the page?

How can I keep links in my UI templates (e.g. Thymeleaf templates) in sync with the corresponding request mappings in my Spring application?
I've seen that e.g. the Play framework uses the #router-Object within its templates. How is it solved by Spring?
One example:
Spring Controller - simple
#Controller
public class UserController {
#GetMapping("/users/{username}")
public String getUser(#PathParam String username) {
// do some stuff....
return "user";
}
}
HTML-Page
<body>
User details
</body>
Now I want to change "/users" to "/accounts". I'm pretty sure that I've got to update every html page by hand to update the link. Is there an easier solution for this?
As far as I know, there is no simple way to do this with built-in tools from Spring. However, I don't think that this would be too hard to build. You would need the following:
A YAML file with all of your URL templates defined
A Properties Spring bean that contains your URL mappings (read from the YAML file)
All of your #RequestMapping annotations would have to be prop values; i.e.
#GetMapping("${urls.users.byUsername}")
A custom tag that knows about the Properties bean and can create URLs from the templates that were defined in your YAML file.

Spring Boot: How to serve two different HTML files to two different mappings?

I am pretty new to Spring Boot, and I saw that if I start a Spring Boot project and put an index.html file in the folder src/main/resources/static, then when I open my browser and go to address "localhost:8080", I'll see this file displayed in the browser.
Now, I have another html file (let's call it 'hello.html'), and I also placed it in src/main/resources/static. I wrote the following code:
#Configuration
#Controller
#EnableAutoConfiguration
#ComponentScan
public class TopicController {
#RequestMapping("/hello")
public String hello() {
return "hello.html";
}
}
As you can understand, I want that when I go to localhost:8000/hello, I'll see the display of 'hello.html' file.
However, I get the following error in the console:
javax.servlet.ServletException: Circular view path [hello.html]: would
dispatch back to the current handler URL [/hello.html] again. Check your
ViewResolver setup! (Hint: This may be the result of an unspecified
view, due to default view name generation.)
Do you know what I can do so I can get the hello.html file in the browser for accessing "localhost:8080/hello" ?

Why does Spring Boot replace all of my favicons with Spring's leaf icon?

(I examined similar questions, but none of them explain the odd behavior I illustrate at the end of this question.)
I have a Spring Boot 1.3.5 application that insists on replacing my favicon with Boot's default favicon (the green leaf). To resolve the problem, I have tried the following:
Install my own favicon at my application's static root.
The word on the street is that this is just supposed to work. Unfortunately, it does not.
Set property spring​.​mvc​.​favicon​.​enabled to false.
This is supposed to disable org​.​springframework​.​boot​.​autoconfigure​.​web​.​WebMvcAutoConfiguration​.​WebMvcAutoConfigurationAdapter​.​FaviconConfiguration, which appears to responsible for serving Boot's default favicon. By setting a breakpoint in that class, I was able to confirm that the beans defined in that class indeed do not get created when the property is set to false.
Unfortunately, this didn't solve the problem, either.
Implement my own favicon handler:
#Configuration
public class FaviconConfiguration {
#Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Integer.MIN_VALUE);
mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", faviconRequestHandler()));
return mapping;
}
#Bean
protected ResourceHttpRequestHandler faviconRequestHandler() {
ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler();
ClassPathResource classPathResource = new ClassPathResource("static/");
List<Resource> locations = Arrays.asList(classPathResource);
requestHandler.setLocations(locations);
return requestHandler;
}
}
Sadly, no luck here, too.
Rename my favicon from favicon.ico to logo.ico, and just point all my pages' favicon links to that, instead.
Now, with this potential fix, I discovered a surprising result. When I curled my newly named icon.ico resource, I was served Spring's leaf icon. However, when I deleted the resource, I got 404. But then, when I put it back, I got the leaf again! In other words, Spring Boot was happy to answer 404 when my static resource was missing, but when it was there, it would always answer with the leaf instead!
Incidentally, other static resources (PNGs, JPGs, etc.) in the same folder serve up just fine.
It was easy to imagine that there was some evil Spring Boot contributor laughing himself silly over this, as I pulled my hair out. :-)
I'm out of ideas. Anyone?
As a last resort, I may just abandon using an ICO file for my site icon, and use a PNG instead, but that comes at a cost (losing multi-resolution support), so I'd rather avoid that.
This is a spring boot feature:
Spring MVC auto-configuration
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
The auto-configuration adds the following features on top of Spring’s defaults:
Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver
beans.
Support for serving static resources, including support for
WebJars (see below).
Automatic registration of Converter,
GenericConverter, Formatter beans.
Support for HttpMessageConverters
(see below).
Automatic registration of MessageCodesResolver (see
below).
Static index.html support.
Custom Favicon support.
Automatic use of a ConfigurableWebBindingInitializer bean (see below).
You can find this document at: http://docs.spring.io/spring-boot/docs/1.4.1.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-auto-configuration
And, If you want to disable spring boot favicon, you can add this config to you yml or perperties files
spring.mvc.favicon.enabled=true # Enable resolution of favicon.ico.
Or, If you want change favicon to you own. try this:
#Configuration
public static class FaviconConfiguration {
#Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Integer.MIN_VALUE);
mapping.setUrlMap(Collections.singletonMap("mylocation/favicon.ico",
faviconRequestHandler()));
return mapping;
}
}
And you can find more detail at: Spring Boot: Overriding favicon
UPDATE:
put favicon.ico to resources folder.
And, try it:
Why choose the hard way, when u can get the easy one?
just create a new link into ur <head> with:
<link rel="icon" type="image/png" href="images/fav.png" />
Copy and paste ur icon in src/main/resources/static/images/
Rename the file to whatever you want, just remember to change the link in the html too.

Resources