Why does Value in Spring MVC require an asterisk?

8

Why do I need to put * in value when there is nothing left? I mean, before using Spring MVC it worked without problems only as /planilha/ .

getPlanilha works correctly but if it has the same RequestMethod and consumes will it execute create ? Since both will have /planilha/QualquerCoisa ONLY because of the asterisk.

@RequestMapping(value = "/planilha/**", method = RequestMethod.POST, consumes = "application/json")
public String create(HttpServletRequest request, @RequestBody String jsonStr) {...}

@RequestMapping(value = "/planilha/{id}", method = RequestMethod.GET)
public String getPlanilha(@PathVariable("id") String id) {...}

According to the documentation:

  

? matches one character
* matches zero or more characters
** matches zero or more 'directories' in a path.

I understood the functionality but the doubt will occur if the create remains.

    
asked by anonymous 31.03.2015 / 15:23

2 answers

6

Well, let's take a look.

  

Why do I need to put * in value when there is nothing left?

You do not really need to. You can leave only planilha/ OR planilha , for example. A POST call on http://{host}:{porta}/{contexto}/planilha/ OR http://{host}:{porta}/{contexto}/planilha , respectively, and Content-Type equal application/json will work.

  

before using Spring MVC it worked without problems only as /planilha/ .

I think you're probably referring to servlets, @WebServlet("/planilha/") , or mapping in web.xml , right? Well, see example above =)

  

The getPlanilha works correctly but if it has the same RequestMethod and consumes will execute create?

By possuir o mesmo RequestMethod e consumes I believe you are referring to the create method. So yes, if the HTTP method is POST and there is a Content-Type=application/json in the request header, it will be the create method to call. Because? Because there is no other mapping more specific than it meets these requirements. If, on the other hand, I had a mapping like this:

@RequestMapping(value = "/planilha/{id}", method = RequestMethod.POST, consumes = "application/json")
public String newCreate(@PathVariable("id") String id, @RequestBody String jsonStr) {...}

It would be newCreate to be executed, because it is the most specific mapping existing.

A documentation in Spring MVC is very clear about the specificity of URL patterns.

  
  • The default mapping pattern /** is less specific than any other pattern. For example, /api/{a}/{b}/{c} is more specific.
  •   A prefix pattern such as /public/** is less specific than any other pattern that does not contain double wildcards. For example, /public/path3/{a}/{b}/{c} is more specific.   

You can see more about the patterns used in the matcher used by spring, called AntPathMatcher .

Now, for example, let's consider some requests based on the mapping of your controller. Consider this:

@Controller
public class PlanilhaController {

    private static final Logger LOGGER = Logger.getLogger(PlanilhaController.class.getName());

    @RequestMapping(value = "/planilha/**", method = RequestMethod.POST, consumes = "application/json")
    public String create(final HttpServletRequest request, @RequestBody final String json) {
        LOGGER.info(String.format("PlanilhaController#create --> called create with json '%s'", json));
        LOGGER.info(String.format("PlanilhaController#create --> called create on path '%s'", request.getRequestURI()));
        return "page";
    }

    @RequestMapping(value = "/planilha/{id}", method = RequestMethod.GET)
    public String getPlanilha(@PathVariable("id") final String id) {
        LOGGER.info(String.format("PlanilhaController#getPlanilha --> called getPlanilha with id '%s'", id));
        return "page";
    }

}
  • Call GET on http://{host}:{porta}/{contexto}/planilha/bruno will produce this log:

    Apr 14, 2015 9:49:55 PM com.brunocesar.controller.PlanilhaController getPlanilha
    INFORMAÇÕES: PlanilhaController#getPlanilha --> called getPlanilha with id 'bruno'
    
  • GET call on http://{host}:{porta}/{contexto}/planilha/bruno/cesar will produce a HttpRequestMethodNotSupportedException with a log type like this:

    Apr 14, 2015 9:50:09 PM com.brunocesar.controller.ControllerErrorHandler processException
    ADVERTÊNCIA: ControllerErrorHandler#processException --> message: 'Request method 'GET' not supported
    
  • Call POST and Content-Type equal to application/json in http://{host}:{porta}/{contexto}/planilha/ will produce log something like this:

    Apr 14, 2015 9:50:36 PM com.brunocesar.controller.PlanilhaController create
    INFORMAÇÕES: PlanilhaController#create --> called create with json '{"name":"bruno"}'
    Apr 14, 2015 9:50:36 PM com.brunocesar.controller.PlanilhaController create
    INFORMAÇÕES: PlanilhaController#create --> called create on path '/springmvc-sample/planilha/'
    
  • Call POST and Content-Type equal to application/json in http://{host}:{porta}/{contexto}/planilha will produce log something like this:

    Apr 14, 2015 9:51:22 PM com.brunocesar.controller.PlanilhaController create
    INFORMAÇÕES: PlanilhaController#create --> called create with json '{"name":"bruno"}'
    Apr 14, 2015 9:51:22 PM com.brunocesar.controller.PlanilhaController create
    INFORMAÇÕES: PlanilhaController#create --> called create on path '/springmvc-sample/planilha'
    
  • Call POST and Content-Type equal to application/json in http://{host}:{porta}/{contexto}/planilha/bruno will produce log something like this:

    Apr 14, 2015 9:52:10 PM com.brunocesar.controller.PlanilhaController create
    INFORMAÇÕES: PlanilhaController#create --> called create with json '{"name":"bruno"}'
    Apr 14, 2015 9:52:10 PM com.brunocesar.controller.PlanilhaController create
    INFORMAÇÕES: PlanilhaController#create --> called create on path '/springmvc-sample/planilha/bruno'
    
  • Call POST and Content-Type equal to application/xml in http://{host}:{porta}/{contexto}/planilha/bruno will produce a HttpMediaTypeNotSupportedException with a log something like this:

    Apr 14, 2015 9:52:45 PM com.brunocesar.controller.ControllerErrorHandler processException
    ADVERTÊNCIA: ControllerErrorHandler#processException --> message: 'Content type 'application/xml' not supported
    
15.04.2015 / 02:53
-1

I think it's just an MVC Web convention. In my understanding, when doing a /planilha/ in the Web MVC you can assume there must be something after the last / , so the need to specify how the match will be after / .

I think the most appropriate would be to use only /planilha (without the last / ). So by doing only /planilha it will execute create and doing /planilha/QualquerCoisa will get getPlanilha

    
10.04.2015 / 02:36