2

If I want to create a basic controller with RequestMapping = "/{content}" to handle the general case. But for some specific contents, I want to create a concrete controller for this special case, and inherit from that basic controller.

For example:

@RequestMapping(value = "/{content}")
class ContentController {

    public ContentController(@PathVariable String content) { ... }

}


@RequestMapping(value = "/specialContent")
class SpecialContentController extends ContentController {

    public SpecialContentController() { super("specialContent"); }

    // overwrite sth
    ....

} 

Is this legal? Or some other better implementation?

Raniz
  • 10,882
  • 1
  • 32
  • 64
cxlove
  • 71
  • 1
  • 1
  • 3

2 Answers2

0

@PathVariable should not be used in constructor.

  • 1
    You should flesh out your answer with more information and an explanation of _why_ you shouldn't use `@PathVariable` in a constructor – Raniz Feb 01 '18 at 08:10
0

You seem confused about how controllers in spring work.

A controller is a singleton which is created on application upstart and whose methods are invoked to handle incoming requests.

Because your controller isn't created for each request but created before any requests are handled you can't use path variables in the constructor - both because there's no information about it's value when the instance is created but also because you'll want it to reflect the current request being handled and since controllers can handle many multiple requests simultaneously you can't store it as a class attribute or multiple requests would interfere with each other.

To achieve what you want you should use methods and compose them, something like this:

@RestController
public class ContentController {

    @GetMapping("/specialContent")
    public Map<String, String> handleSpecialContent() {
        Map<String, String> map = handleContent("specialContent");
        map.put("special", "true");
        return map;
    }

    @GetMapping("/{content}")
    public Map<String, String> handleContent(@PathVariable String content) {
        HashMap<String, String> map = new HashMap<>();
        map.put("content", content);
        return map;
    }

}

Note the regular expression in {content:^(?!specialContent$).*$} to ensure that Spring never routes specialContent there. You can get an explanation of the regular expression here and toy around with it here.

You can see that it works if we put it to the test:

$ http localhost:8080/test
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Date: Thu, 01 Feb 2018 08:18:11 GMT
Transfer-Encoding: chunked

{
    "content": "test"
}

$ http localhost:8080/specialContent
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Date: Thu, 01 Feb 2018 08:18:15 GMT
Transfer-Encoding: chunked

{
    "content": "specialContent",
    "special": "true"
}
Raniz
  • 10,882
  • 1
  • 32
  • 64