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

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" ?

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.

Configuring Default Spring Boot app to render HTML pages and CSS JS content

I configured a Basic Spring Boot app containing Hibernate. However, no page is being rendered.
I have places my pages in src/main/resources/templates/ and content(CSS and JS) in src/main/resources/static/
I have added Thymeleaf through Maven and written a basic controller to render my page -
#RestController
#RequestMapping("/testui")
public class GreetingController {
#RequestMapping("/greeting")
public String greeting(#RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
Instead of rendering a page with my name, it is rendering the string - "greeting"
I have placed the greeting.html in templates file. What are the changes in application.properties I need to make to render pages (what keys and values must I give?)
Update - I somehow do not have the webapp folder. Added that. Created a folder called jsp and added a simple page. Referenced it - didnt work
Why is it not working?
Because you are using #RestController. #RestController is used to create API controllers which serve JSON/XML, whereas #Controller is used to create controllers which serve web content such as HTML.
Proposed solution
Replace #RestController with #Controller. For further details, please see the official Getting Started guide of Spring.
You've added #RestController on the Controller class, which means that you want all values returned by the controller methods to be considered as response body (that's the equivalent of annotating all controller methods with #ResponseBody).
Remove that annotation from the class and replace it with #Controller and you should get the expected result.

Configure index.html location in Spring initializr project

I created a Spring boot project using Spring initializr.
The project structure is below. /resources/client is the folder I added manually.
After I ran DemoApplication, I hit localhost:8080 and I saw the home page was pointed to /resources/index.html. I wanted to set the home page to be /resources/client/build/index.html, so I added something in application.properties:
spring.mvc.view.prefix=/resources/client/build/ ### also tried /client/build/
spring.mvc.view.suffix=.html.
However, it did not work and the home page was still pointed to /resources/index.html.
Also, The application is using dispatcherServlet but I did not find a dispatcherServlet file.
Is there any way I can use custom index.html location? Thanks.
Maybe you can try to add a HomeController using java code as following:
#Controller
public class HomeController {
#RequestMapping("/")
public String index() {
return "client/build/index.html";
}
}

How can I tell if Spring has loaded my #Controller?

Is there a way to tell if Spring has loaded my #Controller?
I'm requesting a URL but I'm not hitting my controller and I can't figure out why
I'm loading controllers by doing a component scan
<context:component-scan base-package="com.example.app.web"/>
Other controllers in the same package as my failing controller are working fine.
My controller code is:
#Controller
#RequestMapping(value = "/app/administration/ecosystem")
public class AppEcosystemController {
#Autowired
EcosystemManagerService ecosystemManagerService;
#RequestMapping(value = "/Foo", method = RequestMethod.GET)
public String getEcosystem() {
/* Implementation */
}
The first thing I'd like to do is to be sure that this controller is getting picked up by the component scan.
Any suggestions?
Just enable logging for your application, you can find this information at INFO level
For example in my application I have a controller named UserController.
The following log4j.properties does the trick.
log4j.rootLogger=INFO, FILE
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=../logs/rest-json.log
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
I can see in the log that RequestMappingHandlerMapping mapped my controller (scroll all the way to the right).
07:28:36,255 INFO RequestMappingHandlerMapping:182 - Mapped "{[/rest/**/users/{id}],methods=[GET],params=[],headers=[],consumes=[],produces=[text/xml || application/json],custom=[]}" onto public org..domain.User org.ramanh.controller.UserController.getUser(java.lang.String)
07:28:36,255 INFO RequestMappingHandlerMapping:182 - Mapped "{[/rest/**/users],methods=[POST],params=[],headers=[],consumes=[],produces=[text/xml || application/json],custom=[]}" onto public void org..controller.UserController.addUser(org...domain.User)
If you are still unsure I would suggest adding a method annotated with #PostConstruct.
You could easily look up the message in the log or place a break point in this method.
#PostConstruct
protected void iamAlive(){
log.info(“Hello AppEcosystemController”)
}
If you find that your controller is initialized correctly but still the url is not accessible.I would test the following
You are getting 404 error - maybe you are not pointing to the correct
url (do not forget to add the application as prefix to the url)
You are getting 404 error - Dispatcher servlet mapping in web.xml doesn't meet
the url above
You are getting 403/401 – maybe you are using
spring security and it’s blocking the url
You are getting 406 – your
content type definition is conflicting with your request
You are getting 50x – something is buggy in your code
I made an ApplicationContextDumper. Add it into application context, it will dump all beans and their dependencies in the current context and parent contexts (if any) into log file when the application context initialization finishes. It also lists the beans which aren’t referenced.
It was inspired by this answer.
You could start out with enabling debug logging for Spring as outlined here.
I'd also recommend leveraging the MVC testing support, which you'll find in the spring-test jar. Details on how to use it can be found here and here.

Spring MVC cannot find *.jsp files

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.

Resources