Spring MVC: Get Unnamed Request Parameter - java

What is the simplest way to access an unnamed request parameter in a Spring MVC controller? Is there an annotation for this similar to #RequestParam?
HTTP Delete request with unnamed parameter:
http://localhost/myEndPoint?someUnnamedParam
Controller:
public class MyController {
#RequestMapping(value = {"/myEndPoint"}, method = RequestMethod.DELETE)
public void deleteThing() {
// Do something with unnamed param
}
}
Details: Spring 3.0.7

I think you misunderstand.
In /myEndPoint?someUnnamedParam, you have a parameter named someUnnamedParam with a String value of "", ie. an empty String. It's parsed as an equivalent to /myEndPoint?someUnnamedParam=.
You can get a set of parameter names and use those as values.
#RequestMapping(value = {"/myEndPoint"}, method = RequestMethod.DELETE)
public void deleteThing((#RequestParam Map<String, List<String>> params) {
Set<String> paramNames = params.keySet();
...
}

You can always use
#RequestMapping(value = {"/myEndPoint"}, method = RequestMethod.DELETE)
public void deleteThing(HttpServletRequest request) {
String param = request.getQueryString();
// Do something with request
}
and perform any operations you need on request

Related

RestController with GET + POST on same method?

I'd like to create a single method and configure both GET + POST on it, using spring-mvc:
#RestController
public class MyServlet {
#RequestMapping(value = "test", method = {RequestMethod.GET, RequestMethod.POST})
public void test(#Valid MyReq req) {
//MyReq contains some params
}
}
Problem: with the code above, any POST request leads to an empty MyReq object.
If I change the method signature to #RequestBody #Valid MyReq req, then the post works, but the GET request fails.
So isn't is possible to just use get and post together on the same method, if a bean is used as input parameters?
The best solution to your problem seems to be something like this:
#RestController
public class MyServlet {
#RequestMapping(value = "test", method = {RequestMethod.GET})
public void testGet(#Valid #RequestParam("foo") String foo) {
doStuff(foo)
}
#RequestMapping(value = "test", method = {RequestMethod.POST})
public void testPost(#Valid #RequestBody MyReq req) {
doStuff(req.getFoo());
}
}
You can process the request data in different ways depending on how you receive it and call the same method to do the business logic.
#RequestMapping(value = "/test", method = { RequestMethod.POST, RequestMethod.GET })
public void test(#ModelAttribute("xxxx") POJO pojo) {
//your code
}
This will work for both POST and GET. (make sure the order first POST and then GET)
For GET your POJO has to contain the attribute which you're using in request parameter
like below
public class POJO {
private String parameter1;
private String parameter2;
//getters and setters
URl should be like below
/test?parameter1=blah
Like this way u can use it for both GET and POST
I was unable to get this working on the same method and I'd like to know a solution, but this is my workaround, which differs from luizfzs's in that you take the same request object and not use #RequestParam
#RestController
public class Controller {
#GetMapping("people")
public void getPeople(MyReq req) {
//do it...
}
#PostMapping("people")
public void getPeoplePost(#RequestBody MyReq req) {
getPeople(req);
}
}

Spring Rest Controller, Path Variables on an overriden method's arguement

I have a controller annotated with #RestController and it implements an interface:
public interface ContratEndpoint {
String ROOT = "/api/contrats";
String GET_CONTRAT = "";
String GET_CONTRAT_PER_PK = "/{idContrat}";
#RequestMapping(value = GET_CONTRAT)
Contrat getContrat(#RequestParam(value = "contratId")Long contratId);
#RequestMapping(value = GET_CONTRAT_PER_ID)
ExtContrat getContratById(#PathVariable("idContrat") Long idContrat);
}
The controller:
#RestController
#RequestMapping(value = ContratEndpoint.ROOT)
public class ContratController implements ContratEndpoint {
//Injecting Services....
#Resource
private Mapper mapper;
#Override
public Contrat getContrat(Long contratId) {
return mapper.map(contratService.get(contratId),Contrat.class);
}
#Override
public ExtContrat getContratById(#PathVariable("idContrat") Long idContrat){
Preconditions.checkArgument(idContrat !=null);
return mapper.map(contratService.get(idContrat),ExtContrat.class);
}
.The above Code works just fine.
. But For the first inherited method , I didn't have to annotate arguments with #RequestParam and it worked just fine.
As for the second method I tried at first :
#Override
public ExtContrat getContratById(Long idContrat){
Preconditions.checkArgument(idContrat !=null);
return mapper.map(contratService.get(idContrat),ExtContrat.class);
}
. I expected the same behaviour Like the first Method, But i was wrong and the code ended up firing an IllegalArgumentException because of the check in ligne Preconditions.checkArgument(idContrat!=null).
My question is what is so specific about #PathVariable that i've missed ?
Or is it just something is wrong with my approach?
Thanks.
There is difference between Request param and path variable,seee below post that you can confirm with your uri the cause for the exception :
#PathVariable is to obtain some placeholder from the uri (Spring call it an URI Template) — see Spring Reference Chapter 16.3.2.2 URI Template Patterns
#RequestParam is to obtain an parameter — see Spring Reference Chapter 16.3.3.3 Binding request parameters to method parameters with #RequestParam
Assume this Url http://localhost:8080/SomeApp/user/1234/invoices?date=12-05-2013 (to get the invoices for user 1234 for today)
#RequestMapping(value="/user/{userId}/invoices", method = RequestMethod.GET)
public List<Invoice> listUsersInvoices(
#PathVariable("userId") int user,
#RequestParam(value = "date", required = false) Date dateOrNull) {
...
}

liferay spring portal #ResourceMapping can't trigger different types of http methods

I have created a liferay portlet application using Spring, thymeleaf and AngularJS. For communication between AngularJS and spring I need to create some rest calls which I have created using #ResourceMapping like as shown below. The application is working fine but the problem is that I don't know how to make GET, DELETE, PUT http REST calls since #ResourceMapping is not allowing to specify any methods.
#ResourceMapping(value="getUserDetail")
public void userDetail(#RequestParam long userId, ResourceResponse response) throws Exception {
Users users = new Users(userId);
// some logic
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
JSON_MAPPER.writeValue(response.getPortletOutputStream(), users);
}
When I used #RequestMapping instead of #ResourceMapping like as shown below
#RequestMapping(value="getUserDetail", method=RequestMethod.GET)
#ResponseBody
public void userDetail(#RequestParam long userId, ResourceResponse response) throws Exception {
System.out.println("Got detail request for user with id {} "+ userId);
// UserDetail userDetail = this.userService.getPortalUserDetail(userId);
List<String> users = new ArrayList<String>();
users.add("Manu");
users.add("Lissie");
users.add("John");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
JSON_MAPPER.writeValue(response.getPortletOutputStream(), users);
}
I have got
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping': Initialization of bean failed; nested exception is java.lang.IllegalStateException: Mode mappings conflict between method and type level: [getUserDetail] versus [view]
Can anyone please tell me some solution for this
How to create different types of http calls using #ResourceMapping
Can we use #RequestMapping instead of #ResourceMapping in Liferay Spring portlet for REST calls
How can we create resource based REST urls like getUser/12/mumbai
How can we send REST json as body instead of Request Param
Mode mappings conflict exception
The question doesn't show it, but your controller probably has #RequestMapping("view") annotation. This type level mapping is in conflict with the method level mappings. You should remove #RequestMapping annotation on the controller class.
Request mapping examples
#Controller
public class SampleRESTFullController {
// Simple GET
#RequestMapping(value = "/helloSample", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public #ResponseBody List<HelloSample> helloSample() { ... }
// GET with path variable
#RequestMapping(value = "/helloSample/sampleId/{sampleId}", method = RequestMethod.GET)
public #ResponseBody HelloSample helloSample(#PathVariable("sampleId") Long sampleId) { ... }
// POST with #RequestBody
#RequestMapping(value = "/helloSample", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public #ResponseBody HelloSample createSample(#RequestBody HelloSample helloSample) { ... }
// PUT with path variable and #RequestBody
#RequestMapping(value = "/helloSample/sampleId/{sampleId}", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.NO_CONTENT)
void update(#PathVariable("sampleId") long sampleId, #RequestBody HelloSample helloSample) { ... }
// DELETE
#RequestMapping(value = "/helloSample/sampleId/{sampleId}", method = RequestMethod.DELETE)
#ResponseStatus(HttpStatus.NO_CONTENT)
void delete(#PathVariable("sampleId") long sampleId) { ... }
}
I took the examples from Using RESTFul services with Liferay blog post. It answers all your questions and presents tons of examples. Pay attention to Spring configuration, which makes the RESTful services possible (especially the view resolver and message converter).
1. How to create different types of http calls using #ResourceMapping
If you want to a REST Api with Complete Actions (GET, POST, PUT, DELETE) you need to use #RequestMapping.
2. Can we use #RequestMapping instead of #ResourceMapping in Liferay Spring portlet for REST calls
You should be able to use.
3. How can we create resource based REST urls like getUser/12/mumbai
#RequestMapping(value="getUser/{userId}/mumbai", method=RequestMethod.GET)
#ResponseBody
public List<String> userDetail(#RequestParam("userId") long userId) throws Exception {
System.out.println("Got detail request for user with id {} "+ userId);
//UserDetail userDetail = this.userService.getPortalUserDetail(userId);
List<String> users = new ArrayList<String>();
users.add("Manu");
users.add("Lissie");
users.add("John");
return users;
}
4. How can we send REST json as body instead of Request Param
You can use #RequestBody
#RequestMapping(value="saveUser/{userId}", method=RequestMethod.GET)
#ResponseStatus(HttpStatus.CREATED)
public void userDetail(#RequestParam("userId") long userId, #RequestBody User user) throws Exception {
// Logic
}
How to create different types of http calls using #ResourceMapping
Here are some examples that may help you, that's how i use #RequestMapping:
// GET
#RequestMapping(value = "/api/something", method = RequestMethod.GET)
#ResponseBody
public boolean getSomething() {
return "something";
}
// GET with param
#RequestMapping(value = "/api/something/{id}", method = RequestMethod.GET)
#ResponseBody
public boolean getSomething(#PathVariable("id") Long id) {
return id;
}
Instead of RequestMethod.GET you can use RequestMethod.POST,RequestMethod.PUT,RequestMethod.DELETE and so on...
How can we send REST json as body instead of Request Param
Here is a code snippet that i currently use with an AngularJS FrontEnd for user registration. It works just fine and i use #RequestMapping:
#ResponseBody
#RequestMapping(value = "/auth/register", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<User> register(#RequestBody User user) {
user = userService.initUser(user);
Authentication authentication = securityUserDetailsService.register(user);
if (authentication != null) {
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(authentication);
User authUser = securityUserDetailsService.getAuthenticatedUser();
return new ResponseEntity<>(authUser, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
In order to consume JSON you do:
RequestMapping(value = "/whatever", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
In order to produce (return) JSON you do:
RequestMapping(value = "/whatever", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
Also since you use Spring i think you should take a look at Spring Data and Spring Data Rest. This way you can expose your business models as RESTful endpoints.
How can we create resource based REST urls like getUser/12/mumbai
So in order to expose this endpoint getUser/12/mumbai that's what you should do:
// mumbai hardcoded
#RequestMapping(value = "/getUser/{id}/mumbai", method = RequestMethod.GET)
#ResponseBody
public User getUser(#PathVariable("id") Long id) {
// go get the user ...
return user;
}
// mumbai as a param
#RequestMapping(value = "/getUser/{id}/{prop}", method = RequestMethod.GET)
#ResponseBody
public User getUser(#PathVariable("id") Long id, #PathVariable("prop") String prop) {
// go get the user ...
return user;
}
Lastly can you please try to change
public void userDetail (...
to this
public ResponseEntity<userDetail > (...
There are following methods to use rest app with angular js
#RequestMapping(value = "/saveuser", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
#RequestMapping(value = "/getemployee", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
#RequestMapping(value = "/editCountry", method = RequestMethod.PUT)
#RequestMapping(value = "/deleteCountry", method = RequestMethod.DELETE)
and use following javascript to communicate with spring controller
var formData = {
"userName" : 'Vasim',
"password" : '123456',
"roleName" : 'Admin'
};
var response = $http.post('add', formData);
response.success(function(data, status, headers, config) {
$scope.message = data;
});
var formData = {
"userName" : 'Vasim',
"password" : '123456',
"roleName" : 'Admin'
};
var response = $http.put('edit', formData);
response.success(function(data, status, headers, config) {
$scope.message = data;
});
$scope.delete= function(employeeId) {
$http['delete']('delete', {
params : {
'employeeId' : employeeId
}
}).
success(function(data) {
$scope.msg = data;
});
$http.get('get',{params:{
'id':id
}
}).success(function(data) {
$scope.employees = data;

Spring RequestMapping conflicts

I have a RequestMapping that displays a grid, and another one for loading objects in grid.
#RequestMapping(value = "/grid/{objType}", method = RequestMethod.GET)
public String displayGrid(Model model, #PathVariable("objType") String objType) {
// some code here
}
#RequestMapping(value = "/loadGrid", method = RequestMethod.GET)
public #ResponseBody String loadGrid(Model model) {
// returns a JSON
}
When i display the grid the url is like ../grid/User
The problem is that after the grid is created and a request loadGrid is made, the request is mapped to /grid/loadGrid which is resolved by the first method instead of the second one.
Is there any way to make a request for /grid with nothing after it ?
Or any way to resolve this conflict ?
The collision isn't a problem; spring resolves exact matches first. (see the source code of AbstractHandlerMethodMapping)
Your problem is that you've incorrectly defined your mappings. If you define a #RequestMapping at the class level, all the method #RequestMappings will be prefixed with the defined value.
The following maps three endpoints: /grid, /grid/{objType} and /grid/loadGrid. Note that the #RequestMapping for get() defines no value, only its method because it inherits from the class-level annotation.
#Controller
#RequestMapping(value = "/grid")
public class GridController {
#RequestMapping(method = RequestMethod.GET)
public String get(Model model) {
// ...
}
#RequestMapping(value = "/{objType}", method = RequestMethod.GET)
public String displayGrid(Model model, #PathVariable("objType") String objType) {
// ...
}
#ResponseBody
#RequestMapping(value = "/loadGrid", method = RequestMethod.GET)
public String loadGrid(Model model) {
// ...
}
}

How to read flash attributes after redirection in Spring MVC 3.1?

I would like to know how to read a flash attributes after redirection in Spring MVC 3.1.
I have the following code:
#Controller
#RequestMapping("/foo")
public class FooController {
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(...) {
// I want to see my flash attributes here!
}
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public ModelAndView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttributes("some", "thing");
return new ModelAndView().setViewName("redirect:/foo/bar");
}
}
What I am missing?
Use Model, it should have flash attributes prepopulated:
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(Model model) {
String some = (String) model.asMap().get("some");
// do the job
}
or, alternatively, you can use RequestContextUtils#getInputFlashMap:
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(HttpServletRequest request) {
Map<String, ?> inputFlashMap = RequestContextUtils.getInputFlashMap(request);
if (inputFlashMap != null) {
String some = (String) inputFlashMap.get("some");
// do the job
}
}
P.S. You can do return return new ModelAndView("redirect:/foo/bar"); in handlePost.
EDIT:
JavaDoc says:
A RedirectAttributes model is empty when the method is called and is
never used unless the method returns a redirect view name or a
RedirectView.
It doesn't mention ModelAndView, so maybe change handlePost to return "redirect:/foo/bar" string or RedirectView:
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public RedirectView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttributes("some", "thing");
return new RedirectView("/foo/bar", true);
}
I use RedirectAttributes in my code with RedirectView and model.asMap() method and it works OK.
Try this:
#Controller
public class FooController
{
#RequestMapping(value = "/foo")
public String handleFoo(RedirectAttributes redirectAttrs)
{
redirectAttrs.addFlashAttribute("some", "thing");
return "redirect:/bar";
}
#RequestMapping(value = "/bar")
public void handleBar(#ModelAttribute("some") String some)
{
System.out.println("some=" + some);
}
}
works in Spring MVC 3.2.2
For all those like me who were having problems with seeing the POST url in the browser when a validation would fail.
The POST url is a private url that should not be exposed to users but it was automatically rendered when a validation failed. i.e. if a field was below a minimum length. I was using #Valid. I wanted the original GET url of the form to show at all times even when validation bounced back to the form, so I did the following:
if (validation.hasErrors()) {
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.story", validation);
redirectAttributes.addFlashAttribute("story", story);
return new ModelAndView("redirect:/january/2015");
where story is the form object representation, redirectAttributes are RedirectAttributes you put in the method signature and validation is the BindingResult. /january/2015 is the mapping to the GET controller where the form lives.
After this implementation, in the mapping for /january/2015, story comes in intact as follows:
Story story= (Story) model.asMap().get("story");
//story from the POST method
I had to augment my GET method and check if this was not null. If not null, then send this to the form else I would send a newly initialized Story type to the form as default behaviour before.
In this manner, I am able to return to the form with the bindingresults intact (errors show on form) but have my GET url in place of the post url.

Categories

Resources