spring url mapping when #PathVariable is empty - spring

For the following url mappings (all GET requests):
1. "/book/{book-id}"
2. "/book/publisher/{publisher-id}"
3. "/book/borrower/{borrower-id}"
If 2. or 3. are called with empty string e.g. /book/publisher/ or /book/user/ then the forward slash / is ignored and 1. is invoked with book-id as 'publisher' or 'borrower'. Is this a correct behaviour because a path variable is mandatory rendering 1 as the only valid url in this situation, or is there some config that controls it?
This is a simple rest controller that returns JSON (code simplified):
#RestController
public class BookController {
#Autowired
BookRepository repository; //JPA repository
#RequestMapping(value="/book/{book-id}",method= RequestMethod.GET)
public Book getBook(#PathVariable("book-id") String bookId){
return repository.findOne(bookId);
}
#RequestMapping(value="/book/publisher/{publisher-id}",method=RequestMethod.GET)
public List<Book> getBooksByPublisher(#PathVariable("publisher-id") String publisherId){
return repository.findAll(publisherId);
}
#RequestMapping(value="/book/borrower/{borrower-id}",method= RequestMethod.GET)
public List<Book> getBooksForBorrower(#PathVariable("borrower-id") String borrowerId){
return repository.findAll(borrowerId);
}
}

You can control the flow like this in your getBook() method
if(bookId.equals("publisher") || bookId.equals("borrower")){
model = new ModelAndView("index");
//or do other code to controll the flow
return model;
}

Related

Spring MVC GetMapping does not take effect

I'm trying Spring MVC,I tried #RequestMapping and #GetMampping annotation. There is something wired that #GetMapping doest not take effect.
Below is the code:
#Controller
#RequestMapping(path="/service")
public class ServiceEntry {
#RequestMapping(path="/hello")
#ResponseBody
public String mainPage(){
return "Hello,Information";
}
#RequestMapping(path="/hello2", method = RequestMethod.GET)
#ResponseBody
public String page2(){
return "hello2!";
}
#GetMapping(path="/test1")
#ResponseBody
public String page_test1(){
return "Get method 1";
}
#GetMapping(path="/test2")
#ResponseBody
public String page_test2(){
return "Get method 2";
}
}
While I visit /service/hello or /service/hello2 it works, but /service/test1 or /service/test2 does not work, please help me, thanks!
In RequestMapping you can use parameter path but not in
GetMapping. You can do like this: GetMapping("/test1") or
GetMapping(value="/test1")
Use value instead path. EG: #GetMapping(value="/test2")

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";
}

DTO has only null with GET request params, but not POST #RequestBody

I'm trying to get my query params in a DTO like in this question but my DTO has always null value.
Is there anything wrong in my code ? I made it as simple as possible.
Queries:
GET http://localhost:8080/api/test?a=azaz => null
POST http://localhost:8080/api/test with {"a":"azaz"} => "azaz"
Controller with a GET and a POST:
#RestController
#RequestMapping(path = {"/api"}, produces = APPLICATION_JSON_VALUE)
public class MyController {
// GET: dto NOT populated from query params "?a=azaz"
#RequestMapping(method = GET, path = "test")
public #ResponseBody String test(TestDto testDto){
return testDto.toString(); // null
}
// POST: dto WELL populated from body json {"a"="azaz"}
#RequestMapping(method = POST, path = "test")
public #ResponseBody String postTest(#RequestBody TestDto testDto){
return testDto.toString(); // "azaz"
}
}
DTO:
public class TestDto {
public String a;
#Override
public String toString() {
return a;
}
}
Thanks !
Full Spring boot sample to illustrate it
The problem is that you are missing setter for the field.
public void setA(String a) {
this.a = a;
}
should fix it.
I'm assuming that you have done required configuration like having Jackson mapper in the class path, consume json attribute, getter and setter in DTO classes etc.
One thing missed here is, in RequestMapping use value attribute instead of path attribute as shown below
#RequestMapping(method = POST, value= "/test", consumes="application/json")
public #ResponseBody String postTest(#RequestBody TestDto testDto){
return testDto.toString();
}
And, make sure that you set content-type="application/json" while sending the request
I think what you are trying to do is not possible. To access the query Parameter you have to use #RequestParam("a"). Then you just get the String. To get your object this way you have to pass json as Parameter. a={"a":"azaz"}
Kind regards

How can I check if the user have correctly submitted the previous form into a Spring MVC application that contemplate some steps?

I am pretty new in Spring MVC and I have the following situation.
I am working on a Spring MVC application that implement a user registration process. The prcess is divided into 4 steps. In each step the user insert some information into a form that is submitted and that is handled by the related method into the controller class. Each of these controller method take the related command object that contains the information of the submitted form.
So I have something like this:
#Controller
public class RegistrazioneController {
// This is the first step and show a view that contain the first form:
#RequestMapping(value = "/registrationStep1")
public String registrationStep1(Model model) {
return "/registrazione/registration-step1";
}
#RequestMapping(value = "/registrationStep2", method = RequestMethod.POST)
public String registrationStep2(#ModelAttribute RegistrationStep1 registrationStep1, Model model) throws APIException {
.......................................................
.......................................................
.......................................................
return "/registrazione/registration-step2";
}
#RequestMapping(value = "/registrationStep3", method = RequestMethod.POST)
public String registrationStep3(#ModelAttribute RegistrationStep3 registrationStep3, Model model) throws APIException {
.......................................................
.......................................................
.......................................................
return "/registrazione/registration-step3";
}
// This method return the final view after the completation of the user registration:
#RequestMapping(value = "/registrationStep4", method = RequestMethod.POST)
public String registrationStep2(#ModelAttribute RegistrationStep4 registrationStep4, Model model) throws APIException {
.......................................................
PERFORM THE USER REGISTRATION
.......................................................
return "/registrazione/registration-step4";
}
}
So it works pretty fine. My problem is that the application have tho check that, when enter into a registration step, the previous steps are completed (the previous form was compiled and submitted).
So I think that I have to do something like this, for example: ** when enter into the registrationStep3() have to check if the command object of the previous registrationStep2() step method was correctly setted (it is valid), so it means that the user have completed the previous registration step.
The application have to prevent that the user try to acces the registration starting from a step without having complete the previous steps of the registration process.
What is the best way to implement this behavior?
I have worked in some Sap Hybris projects and this platform suggest to use the following process :
Step1Form, Step2Form and Step3Form, if you have first name and last name in your 1 step form you ll have the same in Step1Form class as attributes.
and for each class create a validator, in the next step controller u have to validate the previous step if it is not valid redirect the user to the previous step.
you already have RegistrationStep1, and RegistrationStep2 and RegistrationStep3
lets create a validator for RegistrationStep1 :
import org.apache.commons.validator.routines.EmailValidator;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
#Component(value = "registrationStep1Validator")
public class RegistrationStep1Validator implements Validator
{
#Override
public boolean supports(final Class<?> aClass)
{
return RegistrationStep1.class.equals(aClass);
}
#Override
public void validate(final Object object, final Errors errors)
{
final RegistrationStep1 step1= (RegistrationStep1) object;
final String name = step1.getName();
final String email = step1.getEmail();
if (email.isEmpty or email == null)
{
errors.reject("email", "Email must not be blank or null");
}
if (name.isEmpty or name== null)
{
errors.reject("name", "Name must not be blank");
}
if (!EmailValidator.getInstance().isValid(email))
{
errors.reject("email", "Email must be valid");
}
}
}
//later in your controller
#RequestMapping(value = "/registrationStep2", method = RequestMethod.POST)
public String registrationStep2(#ModelAttribute RegistrationStep1 registrationStep1,final BindingResult bindingResult, Model model) {
registrationStep1Validator.validate(registrationStep1,bindingResult);
if (bindingResult.hasErrors())
{
return "/registrazione/registration-step1";
}
return "/registrazione/registration-step2";
}

Bind map and list in spring mvc

Controller:
#ResponseBody
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(StressTest stressTest) {
//dosomething
return "ok";
}
Bind Class:
Class StressTest {
private Map<String,List<String>> methods;
private String serviceName;
...
}
Question is:
How to write html form,my http post package :
methods['GetSome'].[0].value=ds&methods['GetSome'].[1].value=asaaaaa&serviceName=aa
But bind fail in springmvc,List in methods always empty
Posted data are not correct. Get rid of the .value part
Try to produce this:
methods['GetSome'].[0]=ds&methods['GetSome'].[1]=asaaaaa&serviceName=aa
Use methods['GetSome'][0]=ds. If use List ,use methods['GetSome'][0].someMember.

Resources