I m actually creating a simple application and I need to have routing pattern identical in multiple case :
/*
* Returns a list of all the root directories accepting query string on name
*/
#RequestMapping(value = "/directories", method = RequestMethod.GET)
public List<DirectoryEntity> find() {
return directoryService.findAll();
}
/*
* Returns a list of all the root directories accepting query string on name
* #param name Name of the ressources to search. Query string at format : *name*
*/
#RequestMapping(value = "/directories", method = RequestMethod.GET)
public List<DirectoryEntity> findByCriteria(#RequestParam(value = "name", required = true) String name) {
return directoryService.findByName(name);
}
In fact, I dont want to manage criteria request in the same function as findAll one. Is there anyway to handle this case without be forced to manage everything inside the same function ?
Thanks for advance
Try changing the second method #RequestMapping annotation adding params:
#RequestMapping(value = "/directories", method = RequestMethod.GET, params = "name")
public List<DirectoryEntity> findByCriteria(#RequestParam(value = "name", required = true) String name) {
return directoryService.findByName(name);
}
See also the Spring Documentation for more details.
I'm not quite sure what you are asking, but assuming the decision as to which method to call is based on request parameters (it must be since they're both the same URL and HTTP method), then something like this might help:
#RequestMapping(method=RequestMethod.GET, params={"name"})
public #ResponseBody List<DirectoryEntity> findByCriteria(#RequestParam(value = "name", required = true) String name) {
//do your stuff
}
The inclusion of the params attribute in the #RequestMapping annotation removes the ambiguity in which method to call.
I've also added #ResponseBody to the return type, just in case you want Spring to return the list in the HTTP response.
Related
Here is my requirement:
Step Five: Add searching by title
This method's purpose is to enable searching by title. You'll pass in an optional query string parameter that returns all auctions with the search term in the title.
In AuctionController.java, return to the list() action method. Add a String request parameter with the name title_like. You'll need to make this parameter optional, which means you set a default value for it in the parameter declaration. In this case, you want to set the default value to an empty string "".
Look in MemoryAuctionDao.java for a method that returns auctions that have titles containing a search term. Return that result in the controller method if title_like contains a value, otherwise return the full list like before.
My code that is NOT passing is this:
#RequestMapping(value = "title_like = ", method = RequestMethod.GET)
public List<Auction> searchByTitle(#RequestBody String title_like) {
if (!title_like.isEmpty()) {
for (Auction auction : auctions) {
if (dao.searchByTitle(title_like).contains(title_like)) {
auctions.add(auction);
return auctions;
}
}
}
return null;
}
}
Refactor the code like below
#RequestMapping(value = "search", method = RequestMethod.GET)
public ResponseEntity<List<Auction>> searchByTitle(#RequestParam(name="title_like", required=false) String title_like) {
...
return ResponseEntity.ok().body(<body>).build();
}
You are using GET method. With Get, it contain no body.
That why your signature don't work.
#RequestMapping(value = "title_like = ", method = RequestMethod.GET)
public List<Auction> searchByTitle(#RequestBody String title_like)
So you have to change #RequestBody to #RequestParam with GET method.
#RequestParam(name="title_like", required=false) String title_like
Other ways, you can change to different method to support body like (RequestMethod.POST, PUT...).
#RequestMapping(value = "title_like = ", method = RequestMethod.POST)
public List<Auction> searchByTitle(#RequestBody String title_like)
I have a web service written in Spring MVC. It can be used by 3rd party developers.
Our methods have a lot of optional parameters (passed in the query string).
I want to make sure that all the query string parameters are spelled correctly and there is no typos.
Is there an easy way to do it? Method signature example:
#RequestMapping(value = {"/filter"}, method = RequestMethod.GET)
#ResponseBody
public List<MetricType> getMetricTypes(
#RequestParam(value = "subject", required = false) Long subjectId,
#RequestParam(value = "area", required = false) Long areaId,
#RequestParam(value = "onlyImmediateChildren", required = false) Boolean onlyImmediateChildren,
#RequestParam(value = "componentGroup", required = false) Long componentGroupId
) throws Exception
{
//Some code
}
If somebody calls this method with "onlyImediateChildren=true" parameter (a typo) instead of "onlyImmediateChildren=true", Spring MVC will ignore the typoed parameter and will assume "onlyImmediateChildren" is null. Developer will get slightly incorrect list of results and will not notice the error. Such issues could be widespread and difficult to diagnose. I want to check there is no typoed params in query string to prevent such issues.
UPDATE
It is possible to extract the list of actual parameters from the query string. Then it could be compared with the list of the allowed parameters. If I hardcode the allowed parameter list, it will duplicate the method signature. I wonder if it is easy to extract a list of allowed parameters from the method signature (e.g. by #RequestParam annotation)?
Many thanks
Maxim
You could implement your own HandlerInterceptor. In preHandle method you can obtain all HandlerMethod's parameters annotated with #RequestParameter. These will be all allowed parameters in request.
Here is my implementation of an HandlerInterceptor which will only accept the parameters which are explicitely defined by a parameter annotation:
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.method.HandlerMethod
import org.springframework.web.servlet.HandlerInterceptor
/**
* Interceptor which assures that only expected [RequestParam]s are send.
*/
#Component
class UnexpectedParameterHandler : HandlerInterceptor {
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
if (handler is HandlerMethod) {
val queryParams = request.parameterNames.toList()
val expectedParams = handler.methodParameters
.map { methodParameter ->
val requestParamName = methodParameter.getParameterAnnotation(RequestParam::class.java)?.name
val parameterName = methodParameter.parameter.name
requestParamName ?: parameterName
}
val unknownParameters = queryParams.minus(expectedParams)
if (unknownParameters.isNotEmpty()) {
response.writer.write("unexpected parameter $unknownParameters")
response.status = HttpStatus.BAD_REQUEST.value()
return false
}
}
return super.preHandle(request, response, handler)
}
}
You could use the getParameterMap method of the request to get a Map of all the submitted parameters, and validate the keys against a list of all allowed parameters. You should be able to get the request object by simply adding it to the method signature, e.g.:
public List<MetricType> getMetricTypes(
HttpServletRequest request,
#RequestParam(value = "subject", required = false) Long subjectId,
...
) throws Exception {
Spring will inject all the query parameters present in the url string through the argument of type
#RequestParam Map<String,String> in your controller method, if present.
#RequestMapping(value = "", method = RequestMethod.GET, produces = {"application/json"})
public HttpEntity<PagedResources<WebProductResource>> findAll(#RequestParam Map<String, String> allRequestParams){
...
}
You can then validate the keys of the map yourself. For an "enterprisey" way to do that generically, see my answer here: How to check spring RestController for unknown query params?
What is the difference between #RequestParam and #PathVariable while handling special characters?
+ was accepted by #RequestParam as space.
In the case of #PathVariable, + was accepted as +.
#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 a parameter from the URI as well — see Spring Reference Chapter 16.3.3.3 Binding request parameters to method parameters with #RequestParam
If the URL http://localhost:8080/MyApp/user/1234/invoices?date=12-05-2013 gets the invoices for user 1234 on December 5th, 2013, the controller method would look like:
#RequestMapping(value="/user/{userId}/invoices", method = RequestMethod.GET)
public List<Invoice> listUsersInvoices(
#PathVariable("userId") int user,
#RequestParam(value = "date", required = false) Date dateOrNull) {
...
}
Also, request parameters can be optional, and as of Spring 4.3.3 path variables can be optional as well. Beware though, this might change the URL path hierarchy and introduce request mapping conflicts. For example, would /user/invoices provide the invoices for user null or details about a user with ID "invoices"?
#RequestParam annotation used for accessing the query parameter values from the request. Look at the following request URL:
http://localhost:8080/springmvc/hello/101?param1=10¶m2=20
In the above URL request, the values for param1 and param2 can be accessed as below:
public String getDetails(
#RequestParam(value="param1", required=true) String param1,
#RequestParam(value="param2", required=false) String param2){
...
}
The following are the list of parameters supported by the #RequestParam annotation:
defaultValue – This is the default value as a fallback mechanism if request is not having the value or it is empty.
name – Name of the parameter to bind
required – Whether the parameter is mandatory or not. If it is true, failing to send that parameter will fail.
value – This is an alias for the name attribute
#PathVariable
#PathVariable identifies the pattern that is used in the URI for the incoming request. Let’s look at the below request URL:
http://localhost:8080/springmvc/hello/101?param1=10¶m2=20
The above URL request can be written in your Spring MVC as below:
#RequestMapping("/hello/{id}") public String getDetails(#PathVariable(value="id") String id,
#RequestParam(value="param1", required=true) String param1,
#RequestParam(value="param2", required=false) String param2){
.......
}
The #PathVariable annotation has only one attribute value for binding the request URI template. It is allowed to use the multiple #PathVariable annotation in the single method. But, ensure that no more than one method has the same pattern.
Also there is one more interesting annotation:
#MatrixVariable
http://localhost:8080/spring_3_2/matrixvars/stocks;BT.A=276.70,+10.40,+3.91;AZN=236.00,+103.00,+3.29;SBRY=375.50,+7.60,+2.07
And the Controller method for it
#RequestMapping(value = "/{stocks}", method = RequestMethod.GET)
public String showPortfolioValues(#MatrixVariable Map<String, List<String>> matrixVars, Model model) {
logger.info("Storing {} Values which are: {}", new Object[] { matrixVars.size(), matrixVars });
List<List<String>> outlist = map2List(matrixVars);
model.addAttribute("stocks", outlist);
return "stocks";
}
But you must enable:
<mvc:annotation-driven enableMatrixVariables="true" >
#RequestParam is use for query parameter(static values) like: http://localhost:8080/calculation/pow?base=2&ext=4
#PathVariable is use for dynamic values like : http://localhost:8080/calculation/sqrt/8
#RequestMapping(value="/pow", method=RequestMethod.GET)
public int pow(#RequestParam(value="base") int base1, #RequestParam(value="ext") int ext1){
int pow = (int) Math.pow(base1, ext1);
return pow;
}
#RequestMapping("/sqrt/{num}")
public double sqrt(#PathVariable(value="num") int num1){
double sqrtnum=Math.sqrt(num1);
return sqrtnum;
}
1) #RequestParam is used to extract query parameters
http://localhost:3000/api/group/test?id=4
#GetMapping("/group/test")
public ResponseEntity<?> test(#RequestParam Long id) {
System.out.println("This is test");
return ResponseEntity.ok().body(id);
}
while #PathVariable is used to extract data right from the URI:
http://localhost:3000/api/group/test/4
#GetMapping("/group/test/{id}")
public ResponseEntity<?> test(#PathVariable Long id) {
System.out.println("This is test");
return ResponseEntity.ok().body(id);
}
2) #RequestParam is more useful on a traditional web application where data is mostly passed in the query parameters while #PathVariable is more suitable for RESTful web services where URL contains values.
3) #RequestParam annotation can specify default values if a query parameter is not present or empty by using a defaultValue attribute, provided the required attribute is false:
#RestController
#RequestMapping("/home")
public class IndexController {
#RequestMapping(value = "/name")
String getName(#RequestParam(value = "person", defaultValue = "John") String personName) {
return "Required element of request param";
}
}
it may be that the application/x-www-form-urlencoded midia type convert space to +, and the reciever will decode the data by converting the + to space.check the url for more info.http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
#PathVariable - must be placed in the endpoint uri and access the query parameter value from the request
#RequestParam - must be passed as method parameter (optional based on the required property)
http://localhost:8080/employee/call/7865467
#RequestMapping(value=“/call/{callId}", method = RequestMethod.GET)
public List<Calls> getAgentCallById(
#PathVariable(“callId") int callId,
#RequestParam(value = “status", required = false) String callStatus) {
}
http://localhost:8080/app/call/7865467?status=Cancelled
#RequestMapping(value=“/call/{callId}", method = RequestMethod.GET)
public List<Calls> getAgentCallById(
#PathVariable(“callId") int callId,
#RequestParam(value = “status", required = true) String callStatus) {
}
Both the annotations behave exactly in same manner.
Only 2 special characters '!' and '#' are accepted by the annotations #PathVariable and #RequestParam.
To check and confirm the behavior I have created a spring boot application that contains only 1 controller.
#RestController
public class Controller
{
#GetMapping("/pvar/{pdata}")
public #ResponseBody String testPathVariable(#PathVariable(name="pdata") String pathdata)
{
return pathdata;
}
#GetMapping("/rpvar")
public #ResponseBody String testRequestParam(#RequestParam("param") String paramdata)
{
return paramdata;
}
}
Hitting following Requests I got the same response:
localhost:7000/pvar/!##$%^&*()_+-=[]{}|;':",./<>?
localhost:7000/rpvar?param=!##$%^&*()_+-=[]{}|;':",./<>?
!# was received as response in both the requests
#RequestParam:We can say it is query param like a key value pair
#PathVariable:-It is came from URI
I am new to java. Trying to develop a application to schedule http api calls in a cron job. Only the method name will be the input. All the apis are configured with swagger annotations. Can I use these annotations to determine whether the api is post or get or delete etc. For example
public class ABC {
#ApiOperation(
httpMethod = "GET",
value = "value",
notes = "notes",
response = ABC.class)
ABC getValue()
{
}
}
only getValue is the input to my application. Can I get the #ApiOperation values to determine the http method type.
You can, but it is in the RequestMapping annotation (the one where you specify which URL should be linked to the method):
For example, this method will be called when someone navigates to myBaseURl/persons in GET. It will return JSON.
#ApiOperation( value = "List of persons",
notes = "List all my base's persons. ",
response = Person.class,
responseContainer = "List",
tags = { "Persons", })
#RequestMapping(value = "/persons",
produces = { "application/json" },
method = RequestMethod.GET)
public PagedResources<PersonResource> persons(...) {}
I have a web service written in Spring MVC. It can be used by 3rd party developers.
Our methods have a lot of optional parameters (passed in the query string).
I want to make sure that all the query string parameters are spelled correctly and there is no typos.
Is there an easy way to do it? Method signature example:
#RequestMapping(value = {"/filter"}, method = RequestMethod.GET)
#ResponseBody
public List<MetricType> getMetricTypes(
#RequestParam(value = "subject", required = false) Long subjectId,
#RequestParam(value = "area", required = false) Long areaId,
#RequestParam(value = "onlyImmediateChildren", required = false) Boolean onlyImmediateChildren,
#RequestParam(value = "componentGroup", required = false) Long componentGroupId
) throws Exception
{
//Some code
}
If somebody calls this method with "onlyImediateChildren=true" parameter (a typo) instead of "onlyImmediateChildren=true", Spring MVC will ignore the typoed parameter and will assume "onlyImmediateChildren" is null. Developer will get slightly incorrect list of results and will not notice the error. Such issues could be widespread and difficult to diagnose. I want to check there is no typoed params in query string to prevent such issues.
UPDATE
It is possible to extract the list of actual parameters from the query string. Then it could be compared with the list of the allowed parameters. If I hardcode the allowed parameter list, it will duplicate the method signature. I wonder if it is easy to extract a list of allowed parameters from the method signature (e.g. by #RequestParam annotation)?
Many thanks
Maxim
You could implement your own HandlerInterceptor. In preHandle method you can obtain all HandlerMethod's parameters annotated with #RequestParameter. These will be all allowed parameters in request.
Here is my implementation of an HandlerInterceptor which will only accept the parameters which are explicitely defined by a parameter annotation:
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.method.HandlerMethod
import org.springframework.web.servlet.HandlerInterceptor
/**
* Interceptor which assures that only expected [RequestParam]s are send.
*/
#Component
class UnexpectedParameterHandler : HandlerInterceptor {
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
if (handler is HandlerMethod) {
val queryParams = request.parameterNames.toList()
val expectedParams = handler.methodParameters
.map { methodParameter ->
val requestParamName = methodParameter.getParameterAnnotation(RequestParam::class.java)?.name
val parameterName = methodParameter.parameter.name
requestParamName ?: parameterName
}
val unknownParameters = queryParams.minus(expectedParams)
if (unknownParameters.isNotEmpty()) {
response.writer.write("unexpected parameter $unknownParameters")
response.status = HttpStatus.BAD_REQUEST.value()
return false
}
}
return super.preHandle(request, response, handler)
}
}
You could use the getParameterMap method of the request to get a Map of all the submitted parameters, and validate the keys against a list of all allowed parameters. You should be able to get the request object by simply adding it to the method signature, e.g.:
public List<MetricType> getMetricTypes(
HttpServletRequest request,
#RequestParam(value = "subject", required = false) Long subjectId,
...
) throws Exception {
Spring will inject all the query parameters present in the url string through the argument of type
#RequestParam Map<String,String> in your controller method, if present.
#RequestMapping(value = "", method = RequestMethod.GET, produces = {"application/json"})
public HttpEntity<PagedResources<WebProductResource>> findAll(#RequestParam Map<String, String> allRequestParams){
...
}
You can then validate the keys of the map yourself. For an "enterprisey" way to do that generically, see my answer here: How to check spring RestController for unknown query params?