Redirect with GET needs relative path, why? - model-view-controller

I am very new to Spring MVC and am seeing a rather trivial behavior I don't understand.
Bellow you can find snippets to my Controller (consider I have feed.jsp and feedList.jsp). What I don't understand is why I need the "../list" in one redirect, when the other works without it
#Controller
#RequestMapping("/feed/*")
public class FeedController {
#RequestMapping(value = "delete/{feedId}", method = RequestMethod.GET)
public String deleteFeed(#PathVariable("feedId") Integer feedId) {
feedService.delete(feedId);
return "redirect:../list";
}
#RequestMapping(value = "save", method = RequestMethod.POST)
public String saveFeed(#ModelAttribute("feed") Feed feed, BindingResult result) {
feedService.create(feed);
return "redirect:list";
}
}

Perhaps the UrlBasedViewResolver is handling view names as relative to the current request mapping url (citation needed).
Anyway, I always use context-relative absolute paths (starting with a slash): redirect:/list. Actually, if your jsp is called "feedList", then your should return redirect:/feedList

Related

Error 400 when receiving data from URL parameters en Spring MVC

I am trying to receive data from an URL with two parameters like this one:
http://localhost:80000/xxx/xxx/tickets/search?codprovincia=28&municipio=110000
No matter the approach, I am always getting a 400 error, but if I access the URL without the two parameters, the controller returns the view correctly (without the parameters, naturally)
This is the code of my controller:
#Controller
#RequestMapping(value = "/xxx" )
public class BuscadorIncidenciasController extends BaseControllerWeb {
#RequestMapping("tickets")
public String tickets(Model model, #RequestParam ("codprovincia") String codprovincia, #RequestParam ("municipio") String municipio, HttpServletRequest request) throws NoAjaxException {
//...
return CONST.JSP_VIEW;
}
...}
Extra info: if I use this URL:
http://localhost:9081/xxx/xxx/tickets/search/28/790000
And this code:
#Controller
#RequestMapping(value = "/xxx" )
public class BuscadorIncidenciasController extends BaseControllerWeb {
#RequestMapping(value = "buscar/{codprovincia}/{municipio}", method = RequestMethod.GET)
public String buscar(#PathVariable Integer codprovincia, #PathVariable Integer municipio ,Model model, HttpServletRequest request) throws NoAjaxException {
//...
return CONST.JSP_VIEW;
}
...}
It gets the parameters correctly. The problem is that I have to use the first URL. I have reviewed similar questions about similar issues, and I have implemented the solutions to those issues, but I get the 400 error regardless what I try (add value="xxx=, required=false, and other suggestions.)
For RequestParam, you need to explicitly add 'name' attribute
#RequestParam(name = "codprovincia"), #RequestParam (name = "municipio")
No need to for HttpServletRequest, unless you have reason
Also, in your 'tickets' method, RequestMapping is not conforming to your URL path.
I think it should be
#RequestMapping("/xxx/tickets/search")
Cheers!

Problems implementing an easy REST service - Spring MVC

I have a Springboot application (a videoclub application). I do not think it is necessary to show you all the code as it would be very verbose. But it works fine.
A class Film, and FilmRepository with some methods, a controller, database JPA, and the HTML files. Everything works fine. I am not looking for a code solution, but more for a "conceptual" solution, just to know if I am implementing properly the REST service.
I want to add now a really easy REST service (adding a class "MyRestController") that will search for a film just by adding the name of it in the URL.
So apart from my Controller, I want to add this RestController just to do this simple thing: If I add the name of a film in the URL, it will search for it with the normal MVC methods.
But adding what I think is the solution gives me this error:
There was an unexpected error (type=Not Found, status=404).
No message available
So when going through the HTML content to the page to search for the film, and adding to that /buscar the film name (which I have in the db) /buscar/Interstellar, it shows the before error.
#CrossOrigin
#RestController
public class MyRestController {
#Autowired
private FilmRepository filmRepo;
#RequestMapping(value = "/buscar", method = RequestMethod.GET)
public ResponseEntity<List<Film>> getFilms(#RequestParam String Title) {
List<Film> pelis = (List<Film>) filmRepo.findByTitle(Title);
HttpStatus status = HttpStatus.OK;
ResponseEntity<List<Film>> response = new ResponseEntity<>(pelis, status);
return response;
}
}
Getting this error makes me think the page knows it has to do something, but might be having trouble getting it (due to strings, iterable things, lists, or that sort of problem, JSON maybe). But I do not know if the "theory" behind the rest service is alright in MyRestController.
Film repository:
public interface FilmRepository extends CrudRepository<Film, Long>{
Iterable<Film> findByTitle(String Title);
}
(The MVC method in the normal controller)
#RequestMapping("/buscar")
public ModelAndView processSearch(#RequestParam(value = "title", required = false) String title) {
if (title == null || title == "") {
Iterable<Film> films = filmRepo.findAll();
return new ModelAndView("buscar").addObject("films", films);
}
Iterable<Film> films = filmRepo.findByTitle(title);
return new ModelAndView("buscar").addObject("films", films);
}
What you're talking about is a #PathVariable
#RequestMapping(path={"/buscar","/buscar/{title}"})
public ModelAndView processSearch(#PathVariable(value = "title", required=false) String title) {
In the end, the problem was with the #RequestParam, which makes you search in the URL with a query like: /buscar?Title=Interstellar
#RequestMapping(value = "/buscar/{title}", method = RequestMethod.GET)
public ResponseEntity<List<Film>> getFilms(#PathVariable String title) {
List<Film> pelis = (List<Film>) filmRepo.findByTitle(title);
HttpStatus status = HttpStatus.OK;
ResponseEntity<List<Film>> response = new ResponseEntity<>(pelis, status);
return response;
}
With this REST service, you can search by URL like "/buscar/Interstellar".
The result is going to give you JSON content with all the information of the Object Film.

Spring - Inconsistent context path

Spring seems to resolve links in an inconsistent way.
For example, if the current URL is
http://localhost/roles
the following anchor
roleA1
goes to http://localhost/roleA1 instead of http://localhost/roles/roleA1
On the other hand, if the current URL is
http://localhost/roles/ (note the '/' at the end)
the previous link will resolve to http://localhost/roles/roleA1
Both http://localhost/roles and http://localhost/roles/ go to the same page, so Spring treats them equally. Now I would like to avoid using absolute paths but if I leave it as it is now, users navigating to http://localhost/roles will get the wrong behaviour.
Is there a way to fix it?
This is my Controller's configuration:
#RequestMapping("/roles")
public class RoleController {
#RequestMapping(method = RequestMethod.GET)
public String roles(final Map<String, Object> model) {
...
return "roles";
}
#RequestMapping(path = "/{roleId}", method = RequestMethod.GET)
public String role(#PathVariable String roleId, final Map<String, Object> model) {
...
return "role";
}

Spring MVC RequestMapping PathVariable in the first place

I would like to set for each user's own profile link.
Like this:
#RequestMapping(value = "/{userlogin}", method = RequestMethod.GET)
public String page(#PathVariable("userlogin") String userlogin, ModelMap model) {
System.out.println(userlogin);
return "user";
}
But static pages get this expression too..
Like this:
#RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
System.out.println("hello mapping");
return "hello";
}
That is when I request GET request "hello" that calls both controllers.
I would like to do that, user controller calls only if other methods not called.
Console, when I calls localhost:8080/123:
123
Console, when I calls localhost:8080/hello:
hello
hello mapping
or
hello mapping
hello
I want to get only
hello mapping
when calls localhost:8080/hello
Who knows how it can be implemented?
Spring MVC can use URI Template Patterns with Regular Expressions. Provided :
userlogin only contain digits
others URL immediately under root contains at least one non digit character
you can use that in your #RequestMapping :
#RequestMapping(value = "/{userlogin:\\d+}", method = RequestMethod.GET)
public String page(#PathVariable("userlogin") String userlogin, ModelMap model) {
//...
}
If the separation between userlogin and other URL is different from what I imagined, it can be easy to adapt.

What is the difference between return ModelAndView and return String in Spring MVC?

I want to know the different between ModelAndView and String.
#RequestMapping(value="/")
public ModelAndView mainPage() {
return new ModelAndView("home");
}
and the second piece of code is about returning String:
#RequestMapping(value="/")
public String mainPage() {
return "home";
}
You can return many things from a controller, and Spring will automatically try to deduce what to do from there.
When you return a ModelAndView all information that needs to be passed from the controller is embedded inside it. No suprise there.
If you return a String, it will assume that this is the name of the view to use. It will wrap this in a ModelAndView object with the string as the view and the existing model embedded as well.
Spring does a lot of 'magic' on the return types, but also on the parameter types.
This allows you to write code in a style that is more intuitive for you, i.e. the following two examples are the same:
#RequestMapping(value="/")
public ModelAndView mainPage() {
Model m = new Model();
m.put("key", "value");
return new ModelAndView(m,"main");
}
and
#RequestMapping(value="/")
public String mainPage(Model m) {
m.put("key", "value");
return "main";
}
This second variant is a little less verbose and easier to test separately. The model passed in will be an empty model (unless forwarded from some other controller).

Resources