Mismatch in #PathVariable resolving - spring-mvc

Let's suppose to have this method signature:
#RequestMapping(value = "/verifyusers/{site}/{users}", method = RequestMethod.GET)
#ResponseBody
public List<String> verifyUser(
#PathVariable("site") String site, #PathVariable("users") String[] users) {
...
}
Receving a request like GET /verifyusers/AOUD/farmaci.rain,farmaci.postacuti
we get: site="AOUD" and users = [farmaci.rain, farmaci] that is we lose the second part of second String after dot ("postacuti")
I think it's the fault of org.springframework.util.AntPathMatcher ...

Use below code to prevent truncation of parameter after ' . '
#RequestMapping(value = "/verifyusers/{site}/{users:.+}", method = RequestMethod.GET)
#ResponseBody
public List<String> verifyUser(
#PathVariable("site") String site, #PathVariable("users") String[] users) {
...
}
Note: {users:.+}

Related

How pass POST parameters from controller to another Controller Spring MVC?

I have startController and start view. In this view I input number and amount and validate it. If validation was successful, I want pass this parameters(number and amount) to another controller, and after that make some operations with it, in this controller. I see two way:
make this operations in first controller, in another methods and use second view for it. But my controller will very big and all logic will be this.
create second controller and second view and pass parameters to this controller.
I make this:
#Controller
#RequestMapping("/")
public class StartController {
#Autowired
private ValidateService validateService;
#RequestMapping(method = RequestMethod.GET)
public ModelAndView printWelcome() {
ModelAndView modelAndView = new ModelAndView("start");
return modelAndView;
}
#RequestMapping(value = "process", method = RequestMethod.POST)
public ModelAndView process(HttpServletRequest request) {
ModelAndView modelAndView;
String phoneNumber = request.getParameter("phone_number");
int amount = Integer.parseInt(request.getParameter("amount"));
String result = validateService.validate(phoneNumber, amount);
if (!result.equals("OK")) {
modelAndView = new ModelAndView("start");
modelAndView.addObject("result",result);
}else {
modelAndView = new ModelAndView("redirect:/check/process");
modelAndView.addObject("phone_number", phoneNumber);
modelAndView.addObject("amount",amount);
}
return modelAndView;
}
and if result != OK I redirect to new controller
#Controller
#RequestMapping("/check")
public class CheckController {
#RequestMapping(value = "process", method = RequestMethod.GET)
public ModelAndView process(HttpServletRequest request) {
ModelAndView modelAndView = new ModelAndView("check");
String phoneNumber = request.getParameter("phone_number");
int amount = Integer.parseInt(request.getParameter("amount"));
return modelAndView;
}
}
But I need pass parameters with RequestMethod.POST and it will not work. How do it?
You can return a ModelAndView with parameters as follow:
return new ModelAndView("redirect:/check/process?phone_number="+yourPhoneNumber+"&amount="+amount)
You can use forward to go to a new controller right?
"forward:/test2?param1=foo&param2=bar";
Please see below link for more details.
Spring forward with added parameters?

Can I set a default value for a path variable at RequestMapping in SpringMVC?

Is it possibile to set a default value to a #PathVariable in SpringMVC?
#RequestMapping(value = {"/core/organization/{pageNumber}", "/core/organization"} , method = RequestMethod.GET)
public String list(#PathVariable Integer pageNumber, ModelMap modelMap) {
In this case. If I access the page without pageNumber I want to set a default value to 1.
Is that possible?
There's no way to to set a default value, but you can create two methods:
#RequestMapping(value = {"/core/organization/{pageNumber}", "/core/organization"} , method = RequestMethod.GET)
public String list(#PathVariable Integer pageNumber, ModelMap modelMap){
...
}
#RequestMapping(value = {"/core/organization/", "/core/organization"} , method = RequestMethod.GET)
public String list(#PathVariable Integer pageNumber, ModelMap modelMap){
Integer pageNumber=defaultvalue;
...
}
I'm not sure if this is what you want, but if you want a default showing up in swagger, you can use #ApiImplicitParams/#ApiImplicitParam to annotate the function, with a defaultValue and paramType="path" specified.

Return JSON for ResponseEntity<String>

I have a method in my controller that should returns a String in JSON. It returns JSON for non primitive types:
#RequestMapping(value = "so", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<String> so() {
return new ResponseEntity<String>("This is a String", HttpStatus.OK);
}
The curl response is:
This is a String
The root of the problem is that Spring (via ResponseEntity, RestController, and/or ResponseBody) will use the contents of the string as the raw response value, rather than treating the string as JSON value to be encoded. This is true even when the controller method uses produces = MediaType.APPLICATION_JSON_VALUE, as in the question here.
It's essentially like the difference between the following:
// yields: This is a String
System.out.println("This is a String");
// yields: "This is a String"
System.out.println("\"This is a String\"");
The first output cannot be parsed as JSON, but the second output can.
Something like '"'+myString+'"' is probably not a good idea however, as that won't handle proper escaping of double-quotes within the string and will not produce valid JSON for any such string.
One way to handle this would be to embed your string inside an object or list, so that you're not passing a raw string to Spring. However, that changes the format of your output, and really there's no good reason not to be able to return a properly-encoded JSON string if that's what you want to do. If that's what you want, the best way to handle it is via a JSON formatter such as Json or Google Gson. Here's how it might look with Gson:
import com.google.gson.Gson;
#RestController
public class MyController
private static final Gson gson = new Gson();
#RequestMapping(value = "so", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<String> so() {
return ResponseEntity.ok(gson.toJson("This is a String"));
}
}
#RequestMapping(value = "so", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody String so() {
return "This is a String";
}
import org.springframework.boot.configurationprocessor.json.JSONException;
import org.springframework.boot.configurationprocessor.json.JSONObject;
public ResponseEntity<?> ApiCall(#PathVariable(name = "id") long id) throws JSONException {
JSONObject resp = new JSONObject();
resp.put("status", 0);
resp.put("id", id);
return new ResponseEntity<String>(resp.toString(), HttpStatus.CREATED);
}
An alternative solution is to use a wrapper for the String, for instances this:
public class StringResponse {
private String response;
public StringResponse(String response) {
this.response = response;
}
public String getResponse() {
return response;
}
}
Then return this in your controller's methods:
ResponseEntity<StringResponse>

#Validated outside of #RequestMapping

Is it possible to run #Validated after the #RequestMapping method has started? The reason is that I need to modify the #ModelAttribute before actually validating it.
Ideally something like this.
#RequestMapping(value = "/doSomething",
method = RequestMethod.POST)
public final String DoSomething(
#ModelAttribute(value = "myobject") final MyObject myobject) {
//.... do some processing on myobject
//.... now validate
BindingResult bindingResult = validate(myobject);
//...
And a method like this
private final BindingResult validate(
#Validated(value = {Group1.class, Group2.class}) MyObject myobject) {
return bindingResult //somehow return a BindingResult
}
Use your own custom Validator
http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/validation.html#validation-binder

How do i get the requestmapping value in the controller?

In the controller , i have this code,
somehow, i want to get the request Mapping value "search".
How is it possible ?
#RequestMapping("/search/")
public Map searchWithSearchTerm(#RequestParam("name") String name) {
// more code here
}
If you want the pattern, you can try HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE:
#RequestMapping({"/search/{subpath}/other", "/find/other/{subpath}"})
public Map searchWithSearchTerm(#PathVariable("subpath") String subpath,
#RequestParam("name") String name) {
String pattern = (String) request.getAttribute(
HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
// pattern will be either "/search/{subpath}/other" or
// "/find/other/{subpath}", depending on the url requested
System.out.println("Pattern matched: "+pattern);
}
It seems you are looking for the path that this request has matched, then you can directly get it from servlet path
#RequestMapping("/search/")
public Map searchWithSearchTerm(#RequestParam("name") String name, HttpServletRequest request) {
String path = request.getServletPath();
// more code here
}
Having a controller like
#Controller
#RequestMapping(value = "/web/objet")
public class TestController {
#RequestMapping(value = "/save")
public String save(...) {
....
}
}
You cant get the controller base requestMapping using reflection
// Controller requestMapping
String controllerMapping = this.getClass().getAnnotation(RequestMapping.class).value()[0];
or the method requestMapping (from inside a method) with reflection too
//Method requestMapping
String methodMapping = new Object(){}.getClass().getEnclosingMethod().getAnnotation(RequestMapping.class).value()[0];
Obviously works with an in requestMapping single value.
Hope this helps.
#RequestMapping("foo/bar/blub")
public Map searchWithSearchTerm(#RequestParam("name") String name, HttpServletRequest request) {
// delivers the path without context root
// mapping = "/foo/bar/blub"
String mapping = request.getPathInfo();
// more code here
}
For Spring 3.1 and above you can use ServletUriComponentsBuilder
#RequestMapping("/search/")
public ResponseEntity<?> searchWithSearchTerm(#RequestParam("name") String name) {
UriComponentsBuilder builder = ServletUriComponentsBuilder.fromCurrentRequest();
System.out.println(builder.buildAndExpand().getPath());
return new ResponseEntity<String>("OK", HttpStatus.OK);
}

Resources