I got this error White label Error Page while mapping multiple index into spring boot controller while trying to display more than one page - spring-boot

#Controller
public class HomeController {
#RequestMapping("/")
public String index() {
return "myAccount";
}
#RequestMapping("/myAccount")
public String myAccount() {
return "myAccount";
}
}
Project structure image
The above controller exposes two links which return the same html page.

i got the solution for my question,
mapping error occurred because of creating common header in src/main/resources/static
and in my controller during request mapping i couldn't get the page in static templates which i need to map it within the controller

Related

Spring Boot redirect to another url

In my spring boot project i wanted to do a redirection from http://localhost:8080 to http://localhost:8080/birdspotting. This is the code of the Home controller:
#RestController
public class HomeController {
#GetMapping("/")
public String showHomePage() {
return "redirect:/birdspotting";
}
}
The result of going to http://localhost:8080 is a print of redirect:/birdspotting
Basically RestController = Controller + RequestBody
Which will send json response but we are expecting view resolver to return the page or redirect url.
So use #Controller instead of #RestController to fix the issue.
Update:
If you want to use both in Same controller then use #Controller on class level and then wherever you want to return API call response put #ResponseBody on method and wherever you want to return web browser page don't put #ResponseBody.
You have to create the other endpoint like:
#GetMapping("/")
public String showHomePage() {
return "redirect:/birdspotting";
}
#GetMapping("/birdspotting")
public String birdspottingPage() {
return "birdspotting";
}
It's expect you have birdspotting.html in your templates.

Spring sending user to a view when no view is being requested

I have written a book catalog in Spring.
It collects books (pdf, epub, mobi, ebook) from a directory, collects some metadata from them, stores them in a DB and then puts them in a List that is made available to my views:
#Slf4j
#Controller
public class BookCatalogController {
// == Fields ==
private final BookService bookService;
#Autowired
public BookCatalogController(BookService bookService){this.bookService = bookService; }
// == Model attributes ==
#ModelAttribute
public List<Book> bookData(){ return bookService.getBooksFromMemory(); }
public static final File bookDirectory= new File("D:\\edu_repo\\ebooks_test\\");
.
.
.
// Catalog Simple View
#GetMapping(Mappings.CATALOG_SIMPLE)
public String catalogSimple(Model model){
log.info("catalogSimple method called");
// This is adding the entire BookManager book list into the model.
model.addAttribute(AttributeNames.BOOK_DATA, bookData());
return ViewNames.CATALOG_SIMPLE;
}
// Catalog Detail View
#GetMapping(Mappings.CATALOG_DETAIL)
public String catalogDetail(Model model){
log.info("catalogDetail method called");
// This is adding the entire BookManager book list into the model.
model.addAttribute(AttributeNames.BOOK_DATA, bookData());
return ViewNames.CATALOG_DETAIL;
}
.
.
.
#GetMapping(Mappings.LOAD_BOOKS)
public void loadBooks(Model model) {
bookService.loadBooksFromDirectory(bookDirectory);
}
}
Obviously I'm not using #GetMapping(Mappings.LOAD_BOOKS) properly as you can see in the error below:
The error:
There was an unexpected error (type=Internal Server Error, status=500).
Error resolving template [load-books], template might not exist or might not be accessible by any of the configured Template Resolvers
org.thymeleaf.exceptions.TemplateInputException: Error resolving template [load-books], template might not exist or might not be accessible by any of the configured Template Resolvers
How does one invoke a method like I am doing but without Spring trying to redirect the user to another view?
I'm not expecting the page to update at all since I'm not returning a View!
When you click a link in your browser with a load-books anchor, your browser sends it to the server and waits for result, which causes your page to be reloaded. Once the request to a load-books endpoint reached to the server, Spring MVC handles this and starting to looking up an appropriate controller with its method. It founds public void loadBooks(Model model) in your case. When Spring MVC invokes the method, it expects to obtain a view name to resolve and return back to your browser.
Since you haven't provided a View or String as a return type, Spring MVC used the endpoint's path as a view name (I'm not seeing your Mappings.LOAD_BOOKS constant, but it supposed to be load-books).
If you're not going to return any view back to the browser, you can annotate the method like that:
#GetMapping(Mappings.LOAD_BOOKS)
#ResponseBody
public void loadBooks(Model model) {
which tells Spring to treat void as a response body.
But it's not preventing a page refreshing, you'll just see an empty page after clicking the link. In order to fix this you can redirect a user to another page by returning the following string (without ResponseBody annotation on the method)
return "redirect:/path-to-redirect";
When Spring MVC sees this prefix it redirects you to another controller, but user going to notice that too.
If you really don't want to see a blank page for a moment, you'll have to use some JavaScript to perform AJAX request to the server when button is clicked.
Actually, it seems that you want to preload some files in a service by a given path. If it's all you want to do, you can use Spring's runners like that:
#Component
class Preloader implements ApplicationRunner {
private final BookCatalogService bookService;
#Autowired
public Preloader(BookCatalogService service) {
this.bookService = service;
}
#Override
public void run(ApplicationArguments args) throws Exception {
bookService.loadBooksFromDirectory(BookCatalogController.bookDirectory);
}
}
Spring automatically calls all registered runners when application is ready, so your code will be executed without having a user to visit load-books endpoint.

"Circular view path" with simple spring-boot app using #PathVariable

I have a simple spring-boot application that serves up static content. I have an index.html page and some js/css in /src/main/resources/public. I have a single simple controller as follows:
#Controller
public class PublicController {
#RequestMapping(value="/", method=RequestMethod.GET)
public String index() {
return "index";
}
}
That works as expected. I run curl http://localhost:8080/, and it delivers my html.
Now I want to modify the controller to take a path variable:
// ...
#RequestMapping(value="/{word}", method=RequestMapping.GET)
public String index(#PathVariable("word") String word) {
return "index";
}
But now I get a 500 with a big long "Circular view path" exception.
I presume what's happening is the view resolver is seeing that my controller can handle "/index", and realises that's not going to end well.
Is it possible to tell the view resolver to give the static resources priority?
When you use Thymeleaf and declare declare a ThymeleafViewResolver and a ServletContextTemplateResolver with a specific prefix and suffix, it builds the View differently, giving it a path like
WEB-INF/static/index.html
ThymeleafView instances locate the file relative to the ServletContext path by using a ServletContextResourceResolver
templateInputStream = resourceResolver.getResourceAsStream(templateProcessingParameters, resourceName);
which eventually
return servletContext.getResourceAsStream(resourceName);
This gets a resource that is relative to the ServletContext path. It can then use the TemplateEngine to generate the HTML. There's no way an endless loop can happen here.

spring-boot application displaying html code for view when executed in the browser

I am recently start to work with spring-boot in my spring projects, and right now I am facing this problem:
I have one spring-boot application with this main class:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
and this controller:
#Controller
public class AcessoController {
#RequestMapping(value = "/signin")
public String signin(Model model) {
return "acesso/signin";
}
#RequestMapping(value = "/admin")
public String admin(Model model) {
return "private/admin";
}
#RequestMapping(value = "/index")
public String index(Model model) {
return "public/index";
}
}
when I run the application and try access the url mapping /signin, for example, the browser display the html code for this view, instead of the actual content.
What I am doing wrong here?
Are you trying to render a view using a template engine, or just return a static HTML file?
If you are trying to render a template, then you most likely do not have the right dependency in place to pull in a template engine. (Per your code, I believe this is what you are trying to do.) Even if you don't intend to use the template engine for templates, you will want one to render the HTML for you. Depending on your spring-boot setup, try starting with spring-boot-starter-web, or pull in Thymeleaf (spring-boot-starter-thymeleaf) or Freemarker (spring-boot-starter-freemarker) specifically.
If you want to simply return static content and do not want do custom configuration, you'll need to place the files in a certain location and do not need specific controller request mappings.
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-spring-mvc-static-content

Attribute routing and inheritance

I am playing around with the idea of having a base controller that uses a generic repository to provide the basic CRUD methods for my API controllers so that I don't have to duplicate the same basic code in each new controller. But am running into problems with the routing attribute being recognized when it's in the base controller. To show exactly what the problem I'm having I've created a really simple WebAPI controller.
When I have a Get method in the main Controller and it inherits from the ApiController directly I don't have any problems and this works as expected.
[RoutePrefix("admin/test")]
public class TestController : ApiController
{
[Route("{id:int:min(1)}")]
public string Get(int id)
{
return "Success";
}
}
When I move the Get method into a base controller it is returning the contents of the 404 page.
[RoutePrefix("admin/test")]
public class TestController : TestBaseController
{
}
public class TestBaseController : ApiController
{
[Route("{id:int:min(1)}")]
public string Get(int id)
{
return "Success";
}
}
Some more interesting notes:
I can access the action at GET /Test/1. So it is finding it based on the default route still.
When I try to access POST /admin/test, it returns the following JSON
{
"Message":"No HTTP resource was found that matches the request URI 'http://test.com/admin/test'.",
"MessageDetail":"No type was found that matches the controller named 'admin'."
}
Does anyone know of a way to get the routing to work with attributes from a base controller?
Attribute routes cannot be inherited. This was a deliberate design decision. We didn't feel right and didn't see valid scenarios where it would make sense to inherit them.
Could you give a more realistic scenario as to where you would want to use this?
[Update(3/24/2014)]
In the upcoming 5.2 release of MVC Web API, there is going to be an extensibility point called System.Web.Http.Routing.IDirectRouteProvider through which you can enable the inheritance scenario that you are looking for here. You could try this yourself using the latest night builds(documentation on how to use night builds is here)
[Update(7/31/2014)]
Example of how this can be done in Web API 2.2 release:
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
//---------
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
// inherit route attributes decorated on base class controller's actions
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
Using Web API 2.2, you can:
public class BaseController : ApiController
{
[Route("{id:int}")]
public string Get(int id)
{
return "Success:" + id;
}
}
[RoutePrefix("api/values")]
public class ValuesController : BaseController
{
}
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
as outlined here: http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-22
Got it.
[Route("api/baseuploader/{action}")]
public abstract class BaseUploaderController : ApiController
{
[HttpGet]
public string UploadFile()
{
return "UploadFile";
}
}
[Route("api/values/{action}")]
public class ValuesController : BaseUploaderController
{
[HttpGet]
public string Get(int id)
{
return "value";
}
}
One caveat here is that the route action paramter must be the same as the action name. I could not find a way to get around that. (You cannot rename the route with a RouteAttribute)

Resources