1、简介
在本教程中,我们将考虑Spring MVC的一个新特性,它允许我们使用通常的Java接口指定web请求。
2、概述
通常在Spring MVC中定义一个控制器时,我们用指定请求的各种注解来修饰它的方法:端点URL、HTTP请求方法、路径变量等等。
例如我们在端点/save/{id}的普通方法上添加注解:
@PostMapping("/save/{id}")
@ResponseBody
public Book save(@RequestBody Book book, @PathVariable int id) {
// implementation
}
当我们只有一个控制器处理请求时这根本不是问题。当我们有多个具有相同方法签名的控制器时,情况会有所不同。
举例来说,我们可能有两个不同版本的控制器,由于方法迁移或类似方法而具有相同的方法签名。 在这种情况下,我们会在方法定义中添加大量重复的注解。 这显然违反了DRY(不要重复自己)原则。
如果纯Java类会出现这种情况,我们只需定义一个接口并使类实现此接口。 在控制器中方法的主要职责是由方法注解实现的,而非方法签名。
不过在Spring 5.1引入了一项新功能:
在接口上也可以检测到控制器参数注释:允许在控制器接口中完成映射约定。
我们来研究一下如何使用这个功能。
3、控制器的接口
3.1、 上下文设置
我们通过使用一个管理书籍的非常简单的REST应用程序的示例来说明新功能。 它只包含一个控制器,其方法允许我们检索和修改书籍。
在本教程中,我们只关注与该功能相关的问题。 可以在我们的GitHub仓库中找到该应用程序的所有实现问题。
3.2、接口
让我们定义一个普通的Java接口,我们不仅在其中定义方法的签名,还定义它们应该处理的Web请求的类型:
@RequestMapping("/default")
public interface BookOperations {
@GetMapping("/")
List<Book> getAll();
@GetMapping("/{id}")
Optional<Book> getById(@PathVariable int id);
@PostMapping("/save/{id}")
public void save(@RequestBody Book book, @PathVariable int id);
}
请注意,我们可能有一个类级别的注解以及方法级别的注解。 现在我们可以创建一个实现此接口的控制器:
@RestController
@RequestMapping("/book")
public class BookController implements BookOperations {
@Override
public List<Book> getAll() {...}
@Override
public Optional<Book> getById(int id) {...}
@Override
public void save(Book book, int id) {...}
}
我们仍然应该将类级注解@RestController或@Controller添加到控制器中。 以这种方式定义,控制器继承与Web请求的映射相关的所有注释。
为了检查控制器现在是否按预期工作,让我们运行应用程序并通过发出相应的请求来点击getAll()方法:
$ curl http://localhost:8081/book/
即使控制器实现了接口,我们也可以通过添加Web请求注解来进一步微调它。 我们可以像我们为接口做的那样:在类级别或方法级别添加注解。 事实上我们在定义控制器时使用了这种可能性:
@RequestMapping("/book")
public class BookController implements BookOperations {...}
如果我们将Web请求注解添加到控制器,它们将优先于接口的注解。 换句话说,Spring以类似于Java处理继承的方式解释控制器接口。
我们在界面中定义所有常见的Web请求属性,但在控制器中,我们可能总是对它们进行微调。
3.3、注意事项
当我们有一个接口和实现它的各种控制器时,我们可能会遇到Web请求由多个方法处理的情况。 这种情况Spring会抛出异常(模糊映射):
Caused by: java.lang.IllegalStateException: Ambiguous mapping.
如果我们用@RequestMapping装饰控制器,我们可以降低模糊映射的风险。
4、结论
在本教程中,我们考虑了Spring 5.1中引入的新功能。 现在,当Spring MVC控制器实现一个接口时,它们不仅以标准Java方式执行此操作,而且还继承了接口中定义的所有Web请求相关功能。
同样我们可以在GitHub仓库中找到相应的代码片段。
原文链接:https://www.baeldung.com/spring-interface-driven-controllers
作 者:Andrew Shcherbakov
译 者:ruyin_zh