Spring MVC Missing URI template variable
Asked Answered
B

4

34

I have a Controller class with a function that saves a record to the Database. I am passing several parameters to the Controller function however i think i may be writing the @RequestMapping incorrectly. Under is the code

Controller

 @RequestMapping(value="createRoadBlock.htm", method = RequestMethod.POST)
 public @ResponseBody Integer createRoadBlock(@RequestParam String purpose, @RequestParam String userName,
                                              @RequestParam  int status, @RequestParam double latAdd,
                                              @RequestParam double longAdd, HttpServletRequest request,  
                                              HttpServletResponse response) {

         int roadBlockId = 0;
        try{

            roadBlockId = roadBlockManager.saveRoadBlock(purpose, userName, status,latAdd,longAdd);
            logger.info("Create Road Block Successful roadBlockId "+ roadBlockId);

            return roadBlockId;

        }catch(Exception e){
            logger.error("Exception Occured In Road Block Controller "+e.getMessage());
            return roadBlockId;

        } 

     }

Ajax Request

$.ajax({
    type:'POST',
    url:'createRoadBlock.htm',
    contentType:"application/json",
    async:false,
    cache:false,
        data:{purpose:f_purpose, userName:f_userName,status: f_status,latAdd: f_latAdd, longAdd:f_lngAdd},
    dataType:'json'

    }).success(function(recordId){ 
                console.log('Road Block created with id ' + recordId);
    });

Error Log

Controller [com.crimetrack.web.RoadBlockController]
Method [public java.lang.Integer com.crimetrack.web.RoadBlockController.createRoadBlock(java.lang.String,java.lang.String,int,double,double,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)]

org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'purpose' is not present
    at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:201)
    at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:90)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:75)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:156)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:117)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
Blear answered 6/11, 2013 at 2:43 Comment(0)
G
84

@PathVariable is used to tell Spring that part of the URI path is a value you want passed to your method. Is this what you want, or are the variables supposed to be form data posted to the URI?

If you want form data, use @RequestParam instead of @PathVariable.

If you want @PathVariable, you need to specify placeholders in the @RequestMapping entry to tell Spring where the path variables fit in the URI. For example, if you want to extract a path variable called contentId, you would use:

@RequestMapping(value = "/whatever/{contentId}", method = RequestMethod.POST)

Edit: Additionally, if your path variable could contain a '.' and you want that part of the data, then you will need to tell Spring to grab everything, not just the stuff before the '.':

@RequestMapping(value = "/whatever/{contentId:.*}", method = RequestMethod.POST)

This is because the default behaviour of Spring is to treat that part of the URL as if it is a file extension, and excludes it from variable extraction.

Geodesy answered 6/11, 2013 at 2:50 Comment(16)
The data is passed via an ajax request as json so i may need to use @RequestMapping? In your example i am seeing you passing one parameter i would like to know how do your write several parameters will it be @RequestMapping(value = "/id/{param1,param2,param3...}". Also is 'whatever' the name of your parameter?Blear
Do you have control over what the ajax is requesting? If so, then using RequestParam with query parameters in the URI is going to be much easier. Personally, I have had hours of pain with @PathVariable and am only using it for one variable at a time.Geodesy
yes i do have control over the ajax request. Thanks however how would i type multiple parameters in the URI?Blear
Oh RequestParam there is no need to include it in the URI?Blear
You could either build a URI with the parameters like this: /createRoadBlock.htm?purpose=abc&userName=def&status=1&latAdd=-33.8675&longAdd=151.2070 or you could post the values as data.Geodesy
RequestParam does not require you to specify any special placeholders in the RequestMapping - your existing one would work.Geodesy
i updated the code however i am getting the same error what i am doing wrong?Blear
I am getting a new error see my error log Required String parameter 'purpose' is not present however i can see in the firebug console the data being posted. However i am getting an HTTP status 400 The request sent by the client was syntactically incorrect from the browserBlear
Is your ajax posting to something like this: /createRoadBlock.htm?purpose=abc&userName=def&status=1&latAdd=-33.8675&longAdd=1‌​51.2070Geodesy
Yes it looks like this purpose=%22sdfsdfsdfsdf%22&userName=%22jeff%22&status=0&latAdd=10.52291894538631&longAdd=-61.3861083984375Blear
i will include the ajax function aboveBlear
Don't specify json as the content type. And only specify it as the data type if that's what your controller is returning.Geodesy
Thanks for a good answer to this question from a couple years later!Seftton
@Geodesy Unrelated - an upvote ... as your answer to that newbie question on "continue" was the only one really answering the question. You shouldnt have deleted it ...Dorrie
FYI: The annotation is case-sensitive! I looked for a while until I noticed a capitalised letter...Downe
Yes. This helped me fixing a mistake where I used @PathVariable instead of @RequestParam. Silly.Triennium
T
36

I got this error for a stupid mistake, the variable name in the @PathVariable wasn't matching the one in the @RequestMapping

For example

@RequestMapping(value = "/whatever/{**contentId**}", method = RequestMethod.POST)
public … method(@PathVariable Integer **contentID**){
}

It may help others

Trustful answered 2/2, 2020 at 14:53 Comment(3)
God... this helped me. I had @PostMapping(value = "/folders/{foldername}") method[...](@PathVariable String folderName) That "N" on uppercase was the trickChondriosome
Same Stupid Mistake here :|Deify
eh, same stupid mistake. thank you very much for posting thisEunuchoidism
T
3

My problem was that the name of the parameter from the method was different from the one passed in @GetMapping. Those should be identical, otherwise there will be this kind of silent error.

@GetMapping("/{formId}") // Must be the same as the PathVariable
    public ResponseEntity<Form> getFormById(@PathVariable Long formId){
        return new ResponseEntity<Form>(this.formsService.getById(formId), HttpStatus.OK);
    }
Translate answered 27/3, 2022 at 8:56 Comment(0)
C
1

This error may happen when mapping variables you defined in REST definition do not match with @PathVariable names.

Example: Suppose you defined in the REST definition

@GetMapping(value = "/{appId}", produces = "application/json", consumes = "application/json")

Then during the definition of the function, it should be

public ResponseEntity<List> getData(@PathVariable String appId)

This error may occur when you use any other variable other than defined in the REST controller definition with @PathVariable. Like, the below code will raise the error as ID is different than appId variable name:

public ResponseEntity<List> getData(@PathVariable String ID)
Crayton answered 25/1, 2021 at 1:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.