2

I want to map a URL (for example, http://example.com/v1/books:search) containing colons to my Spring MVC controller, but I can't make it work.

@RequestMapping("/v1/books")
public class BooksController {
  @GetMapping(":search")
  public Page<Book> search(@RequestParam String author) {
    // Return books written by the author.
  }

When I test this API, Spring returns 404 NOT_FOUND to me. It seems that Spring doesn't support colons in URL mapping.

Is there any method to make it work? Thanks.

Bourne Xi
  • 111
  • 1
  • 6
  • 1
    This may help :https://stackoverflow.com/questions/3072351/java-spring-restful-url-with-semi-colon – soorapadman May 31 '17 at 03:59
  • Try to put the full path `/v1/books:search` in the `@GetMapping` annotation. I'm not quite sure if Spring concatenates it automatically. (You can see the URL mapping if you start your application. If it's not there, Spring does not concatenate it.) – smsnheck May 31 '17 at 07:47

2 Answers2

3

I hit this attempting to do similar so I thought I'd share my findings.

With using most defaults and your code, the search method will be mapped to /v1/books/:search which is obviously not quite what you want. There are two places that I've found so far that get in the way of changing this. The first is the AntPathMatcher's combine method. This method will attempt to put a path separator (/) between segments. The second place is within the RequestMappingInfo's path parsing code. The former can be replaced easily. The latter not so much.

As the methods that tend to be problematic involve combining multiple @RequestMapping annotations, what I've found to work is to simply side-step combinations. On my controller class, I have a @Controller annotation and any defaults for @RequestMapping, but not a path attribute. On each method, the full path is then added. This isn't great, but it does get collection-level special "methods" to function properly. In your example, this would look like:

@Controller
@RequestMapping
public class BooksController {
  @GetMapping("/v1/books:search")
  public Page<Book> search(@RequestParam String author) {
    // Return books written by the author.
  }
Angus Davis
  • 2,673
  • 13
  • 20
1

Long story short: Do not do this - use / as a separator for the method.

A bit more detail: Have a look at Spring Framework issue #24771 that suggests that the team actually moves away from various ways to handle non-standard URL mappings in favor of simpler logic of URL processing, after entangling in a series of various issues with similar concepts. This "custom method" thing is unlikely to get a first class support in Spring, as a result.

Therefore, despite what Google does, just do this as a normal person and use /v1/books/search path:

@RequestMapping("v1/books")
public class BooksController {

  @GetMapping("search")
  public Page<Book> search(@RequestParam String author) {
    // Return books written by the author.
  }

}
Petr Dvořák
  • 750
  • 1
  • 9
  • 21