add custom parameters to spring mvc controller - java

I have a custom dispatcher servlet which extends the default DispatcherServlet to do some validation for all requests.
Since I will get all the parameters from a request(getInputStream()->Map) to do some validation, I want to pass the params to controller or add the params to the context where I can get them again from the cotroller.
Now I just put all the params to a global Map, but I wonder if there are some simple ways.
public class CustomDispatcherServlet extends DispatcherServlet {
private static final long serialVersionUID = 7250693017796274410L;
#Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
doFilter(request, response);
super.doDispatch(request, response);
}
...
private void doFilter(HttpServletRequest request, HttpServletResponse response) {
WLNResponse<String> error = null;
try {
boolean isSignValid = checkSignValidity(request);
...
private boolean checkSignValidity(HttpServletRequest request) throws IOException {
// pass this params to controller or somewhere I can get from controller
Map<String, Object> params = WebUtils.readParams(request);
...

The way I would go at validating params in the controller itself. for instance
#Controller
public ControllerClass
{
#RequestMapping(value = "/someurl", method = RequestMethod.GET, params = {
"requestParam"})
public void someMethod(#RequestParam(value = "requestParam") String requestParam)
{
System.out.println("This is the value of the RequestParam requestParam " + requestParam);
}
}
This way you can do your validation within the controller.
The only thing this doesn't solve for is if the request being made is not resolved to a valid controller. For that I would use the annotation #controllerAdvice.

Currently, I simply use the request.setAttribute() to put params to the attributes and get it from the controller.....

Related

Get original mapping value inside Spring controller method

Since I'm using the CQRS pattern, I'm trying to create a single controller method that accepts every POST call with a command in its request body and send it.
I'm almost there, but I can't get the path variables.
I created a custom HandlerMapping
#Bean
public HandlerMapping requestMappingHandlerMapping() throws NoSuchMethodException {
for (final UrlEnum urlEnumItem : UrlEnum.values()) {
requestMappingHandlerMapping.registerMapping(new RequestMappingInfo(urlEnumItem.getCommandName(),
new PatternsRequestCondition(urlEnumItem.getUrl()),
null,
null,
null,
null,
null,
null),
commandController,
commandController.getClass().getDeclaredMethod("commandHandler", HttpServletRequest.class)
);
}
return requestMappingHandlerMapping;
}
and this is my controller method signature
#RequestMapping(method = {RequestMethod.POST, RequestMethod.PUT}, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<Object> commandHandler(final HttpServletRequest request) throws Exception {
// controller code here
}
If the url path is something like /api/test it works, but with something like /api/test/{idEntity} I don't have any PathVariable available in the request.
I tried everything like
String originalUrl = (String) request.getAttribute(
HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
which returns the valued url (i.e. /api/test/1234), not the template, or adding
#PathVariable Map<String, Object> parameters
as a parameter in the method, which is empty.
Debugging the request object it seems there isn't anything useful to identify the path variables.
Maybe I should interrogate the HandlerMapping, but I can't have access to it in the controller method.
Is there a way to extract the pathVariables in the controller method?
It was an error in the configuration. I shouldn't have added the RequestMapping annotation to the controller method because it overrode my configuration.
Now I have
#RestController
public class CommandController extends AbstractController {
private final MappingJackson2JsonView mappingJackson2JsonView = new MappingJackson2JsonView();
#Override
protected ModelAndView handleRequestInternal(final HttpServletRequest request, final HttpServletResponse response) throws Exception {
// controller code here
return new ModelAndView(mappingJackson2JsonView);
}
}

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

How to handle that can not get form data by using RequestMapping

I implement a controller as the following:
#RequestMapping(value = "/export", method = RequestMethod.POST)
public #ResponseBody ResponseEntity<Object> Export(HttpServletRequest req, HttpServletResponse response, String type,String text) {
........
}
When posting the text(form param) which the length is small(about 20k) from client, the controller works ok and can get form params(data and type).
But 'type' and 'text' are null in service side, when text(form param) is very long(more than 200k) from client.
Who know how to handle it.
Form params can be read from request as req.getParameter("type").
change your method as below since you are already using req and resp in the method signature
public #ResponseBody ResponseEntity<Object> Export(HttpServletRequest req, HttpServletResponse response){
String type = req.getParameter("type");
String text = req.getParameter("text");
}
You could use the Spring MVC annotation as follows.
public #ResponseBody void export(#PathVariable final String whatEver,
#RequestParam("type") final String type, #RequestParam("text") final String text,
final HttpServletRequest request)

How to get access HttpServletRequest in constructor of resource-parentclass?

I filter the BasicAuth of my REST-services and store the username in the HttpServletRequest
Related Code of the AuthFilter
public class AuthFilter implements ContainerRequestFilter {
#Context
public transient HttpServletRequest servletRequest;
#Override
public ContainerRequest filter(ContainerRequest containerRequest) throws WebApplicationException {
// all the auth filter actions...
// Set data
servletRequest.setAttribute("auth_username", username);
return containerRequest;
}
}
I then have a resource parent class (called BaseResource with only some general attributes) and specific classes which extends it
example specific class
#Path("/Plant")
public class PlantResource extends BaseResource {
private List<Plant> plantlist = new LinkedList<Plant>();
#GET
#Path("/GetPlantById/plantid/{plantid}")
#Produces("application/json")
public String getPlantById(#PathParam("plantid") String plantid, #Context HttpServletRequest hsr) {
String username = (String)hsr.getAttribute("auth_username");
// do something
}
}
As you can see I handle the HttpServletRequest via "#Context HttpServletRequest hsr" to the function (as described in there: Get HttpServletRequest in Jax Rs / Appfuse application?) . This works fine and I can access the data correctly!
What I want now to do is to access this Data in the constructor of the parent class, so I don't have to do it in every function of my specified resources, but in a single place
My try:
public class BaseResource {
#Context protected HttpServletRequest hsr; // Also tried private and public:
/* ... */
public BaseResource() {
String username = (String)hsr.getAttribute("auth_username"); // line 96
System.out.println("constructur of BaseResource" + username);
}
}
But this ends up in:
Aug 05, 2013 3:40:18 PM com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException
Schwerwiegend: The RuntimeException could not be mapped to a response, re-throwing to the HTTP container
java.lang.NullPointerException
at de.unibonn.sdb.mobilehelper.resources.BaseResource.<init>(BaseResource.java:96)
It looks like the HttpServletRequest isn't set there. So how can I access it in the constructor of my parent class?
Fields of BaseResource are injected after an instance is created, so you can't refer to them in the constructor itself. Either create a property method in your BaseResource:
public class BaseResource {
#Context
protected HttpServletRequest hsr;
/* ... */
protected String getUsername() {
return (String)hsr.getAttribute("auth_username");
}
}
or create a hierarchy like:
public class BaseResource {
protected HttpServletRequest hsr;
/* ... */
public BaseResource(HttpServletRequest hsr) {
this.hsr = hsr;
String username = (String)hsr.getAttribute("auth_username");
System.out.println("constructur of BaseResource" + username);
}
}
and
#Path("/Plant")
public class PlantResource extends BaseResource {
private List<Plant> plantlist = new LinkedList<Plant>();
public PlantResource(#Context HttpServletRequest hsr) {
super(hsr);
}
#GET
#Path("/GetPlantById/plantid/{plantid}")
#Produces("application/json")
public String getPlantById(#PathParam("plantid") String plantid) {
String username = (String)hsr.getAttribute("auth_username");
// do something
}
}
You will have to pass it up via a function. The JAX-RS annotations like #Context aren't available in the parent, as you noted. They are also not inherited down. Additionally, you cannot do it at construction time since #Context references are not guaranteed to be available during construction (depends on how container creates the resources).

Spring MVC referencing params variable from RequestMapping

I have the method below:
#RequestMapping(value = "/path/to/{iconId}", params="size={iconSize}", method = RequestMethod.GET)
public void webletIconData(#PathVariable String iconId, #PathVariable String iconSize, HttpServletResponse response) throws IOException {
// Implementation here
}
I know how to pass the variable "webletId" from the RequestMapping using the #PathVariable, but how do I reference the variable "iconSize" from params?
Thanks a lot.
Use #RequestParam:
#RequestMapping(value = "/path/to/{iconId}", method = RequestMethod.GET)
public void webletIconData(#PathVariable String iconId,
#RequestParam("size") String iconSize,
HttpServletResponse response) throws IOException { ... }
See also:
15.3.2.3 Supported handler method arguments and return types
axtavt is right
I only want to explain what your mistake is:
The #RequestMapping params parameter is a filter to make sure that the annotated handler method is only invoked if there is a parameter with the requested value.
So a handler method annotated with #RequestMapping(params="action=doSomething") will be only invoked if there is an request parameter actionwith the content doSomething.

Categories

Resources