Spring MVC是一个丰富的“模型视图控制器”Web 框架。Spring MVC 允许您创建特殊的@Controller
或@RestController
bean 来处理传入的 HTTP 请求。控制器中的方法通过使用@RequestMapping
注解映射到 HTTP。
以下代码显示了一个典型@RestController
的提供 JSON 数据的代码:
@RestController
@RequestMapping("/users")
public class MyRestController {
private final UserRepository userRepository;
private final CustomerRepository customerRepository;
public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {
this.userRepository = userRepository;
this.customerRepository = customerRepository;
}
@GetMapping("/{user}")
public User getUser(@PathVariable Long userId) {
return this.userRepository.findById(userId).get();
}
@GetMapping("/{user}/customers")
public List<Customer> getUserCustomers(@PathVariable Long userId) {
return this.userRepository.findById(userId).map(this.customerRepository::findByUser).get();
}
@DeleteMapping("/{user}")
public void deleteUser(@PathVariable Long userId) {
this.userRepository.deleteById(userId);
}
}
Spring Boot 为 Spring MVC 提供了自动配置,适用于大多数应用程序。
自动配置在 Spring 的默认值之上添加了以下特性:
ContentNegotiatingViewResolver
和BeanNameViewResolver
豆类。Converter
、GenericConverter
和Formatter
bean。HttpMessageConverters
。MessageCodesResolver
。index.html
支持。ConfigurableWebBindingInitializer
bean的自动使用。如果您想保留那些 Spring Boot MVC 自定义并进行更多MVC 自定义(拦截器、格式化程序、视图控制器和其他功能),您可以添加自己@Configuration
的类型类WebMvcConfigurer
但不 添加@EnableWebMvc
.
如果您想提供、 或的自定义实例RequestMappingHandlerMapping
,并且仍然保留 Spring Boot MVC 自定义,则可以声明一个类型的 bean并使用它来提供这些组件的自定义实例。``
如果你想完全控制 Spring MVC,你可以添加你自己的@Configuration
注释@EnableWebMvc
,或者添加你自己的@Configuration
-annotated DelegatingWebMvcConfiguration
,如@EnableWebMvc
.
Spring MVC 使用该HttpMessageConverter
接口来转换 HTTP 请求和响应。明智的默认设置是开箱即用的。例如,对象可以自动转换为 JSON(通过使用 Jackson 库)或 XML(通过使用 Jackson XML 扩展,如果可用,或者通过使用 JAXB,如果 Jackson XML 扩展不可用)。默认情况下,字符串以UTF-8
.
如果需要添加或自定义转换器,可以使用 Spring Boot 的HttpMessageConverters
类,如下清单所示:
@Configuration(proxyBeanMethods = false)
public class MyHttpMessageConvertersConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = new AdditionalHttpMessageConverter();
HttpMessageConverter<?> another = new AnotherHttpMessageConverter();
return new HttpMessageConverters(additional, another);
}
}
HttpMessageConverter
上下文中存在的任何bean 都将添加到转换器列表中。您也可以以相同的方式覆盖默认转换器。
如果您使用 Jackson 来序列化和反序列化 JSON 数据,您可能需要编写自己的类JsonSerializer
和JsonDeserializer
类。自定义序列化程序通常通过模块向 Jackson 注册,但 Spring Boot 提供了一个替代@JsonComponent
注解,可以更轻松地直接注册 Spring Bean。
您可以直接在或实现上使用@JsonComponent
注释。您还可以在包含序列化器/反序列化器作为内部类的类上使用它,如以下示例所示:JsonSerializer``JsonDeserializer``KeyDeserializer
@JsonComponent
public class MyJsonComponent {
public static class Serializer extends JsonSerializer<MyObject> {
@Override
public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {
jgen.writeStringField("name", value.getName());
jgen.writeNumberField("age", value.getAge());
}
}
public static class Deserializer extends JsonDeserializer<MyObject> {
@Override
public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectCodec codec = jsonParser.getCodec();
JsonNode tree = codec.readTree(jsonParser);
String name = tree.get("name").textValue();
int age = tree.get("age").intValue();
return new MyObject(name, age);
}
}
}
中的所有@JsonComponent
bean 都会ApplicationContext
自动向 Jackson 注册。因为@JsonComponent
是用 元注释的@Component
,所以通常的组件扫描规则适用。
Spring Boot 还提供了JsonObjectSerializer
基JsonObjectDeserializer
类,它们在序列化对象时提供了标准 Jackson 版本的有用替代方案。
上面的例子可以重写为使用JsonObjectSerializer
/JsonObjectDeserializer
如下:
@JsonComponent
public class MyJsonComponent {
public static class Serializer extends JsonObjectSerializer<MyObject> {
@Override
protected void serializeObject(MyObject value, JsonGenerator jgen, SerializerProvider provider)
throws IOException {
jgen.writeStringField("name", value.getName());
jgen.writeNumberField("age", value.getAge());
}
}
public static class Deserializer extends JsonObjectDeserializer<MyObject> {
@Override
protected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,
JsonNode tree) throws IOException {
String name = nullSafeValue(tree.get("name"), String.class);
int age = nullSafeValue(tree.get("age"), Integer.class);
return new MyObject(name, age);
}
}
}
默认情况下,Spring Boot 从类路径中名为/static
(或/public
或/resources
或/META-INF/resources
)的目录或从ServletContext
. 它使用ResourceHttpRequestHandler
来自 Spring MVC 的方法,因此您可以通过添加自己的方法WebMvcConfigurer
并覆盖该addResourceHandlers
方法来修改该行为。
在独立的 Web 应用程序中,容器中的默认 servlet 也被启用并充当后备,ServletContext
如果 Spring 决定不处理它,则从根目录提供内容。大多数情况下,这不会发生(除非你修改了默认的 MVC 配置),因为 Spring 总是可以通过DispatcherServlet
.
默认情况下,资源映射在 上/**
,但您可以使用该spring.mvc.static-path-pattern
属性对其进行调整。例如,将所有资源重新定位到/resources/**
可以实现如下:
spring:
mvc:
static-path-pattern: "/resources/**"
您还可以使用该spring.web.resources.static-locations
属性自定义静态资源位置(将默认值替换为目录位置列表)。根 servlet 上下文路径"/"
也会自动添加为位置。
除了前面提到的“标准”静态资源位置之外,还为Webjars 内容做了一个特殊情况。/webjars/**
如果以 Webjars 格式打包,则任何具有路径的资源都将从 jar 文件中提供。
Spring Boot 支持静态和模板化的欢迎页面。index.html
它首先在配置的静态内容位置中查找文件。如果没有找到,它会寻找一个index
模板。如果找到其中任何一个,它会自动用作应用程序的欢迎页面。
Spring MVC 可以通过查看请求路径并将其与应用程序中定义的映射匹配(例如,@GetMapping
控制器方法上的注释)将传入的 HTTP 请求映射到处理程序。
Spring Boot 默认选择禁用后缀模式匹配,这意味着 like 的请求"GET /projects/spring-boot.json"
不会匹配到@GetMapping("/projects/spring-boot")
映射。这被认为是Spring MVC 应用程序的最佳实践。过去,此功能主要对未发送正确“Accept”请求标头的 HTTP 客户端有用;我们需要确保向客户端发送正确的内容类型。如今,内容协商更加可靠。
还有其他方法可以处理不能始终发送正确的“接受”请求标头的 HTTP 客户端。我们可以不使用后缀匹配,而是使用查询参数来确保请求 like"GET /projects/spring-boot?format=json"
将被映射到@GetMapping("/projects/spring-boot")
:
spring:
mvc:
contentnegotiation:
favor-parameter: true
或者,如果您更喜欢使用不同的参数名称:
spring:
mvc:
contentnegotiation:
favor-parameter: true
parameter-name: "myparam"
大多数标准媒体类型都支持开箱即用,但您也可以定义新的媒体类型:
spring:
mvc:
contentnegotiation:
media-types:
markdown: "text/markdown"
后缀模式匹配已弃用,并将在未来版本中删除。如果您了解这些警告并且仍然希望您的应用程序使用后缀模式匹配,则需要以下配置:
spring:
mvc:
contentnegotiation:
favor-path-extension: true
pathmatch:
use-suffix-pattern: true
或者,与其打开所有后缀模式,不如只支持已注册的后缀模式更安全:
spring:
mvc:
contentnegotiation:
favor-path-extension: true
pathmatch:
use-registered-suffix-pattern: true
从 Spring Framework 5.3 开始,Spring MVC 支持多种实现策略,用于将请求路径匹配到 Controller 处理程序。它以前只支持该AntPathMatcher
策略,但现在它也提供PathPatternParser
. Spring Boot 现在提供了一个配置属性来选择和选择新策略:
spring:
mvc:
pathmatch:
matching-strategy: "path-pattern-parser"
除了 REST Web 服务,您还可以使用 Spring MVC 来提供动态 HTML 内容。Spring MVC 支持多种模板技术,包括 Thymeleaf、FreeMarker 和 JSP。此外,许多其他模板引擎包括他们自己的 Spring MVC 集成。
默认情况下,Spring Boot 提供了一个/error
以合理方式处理所有错误的映射,并将其注册为 servlet 容器中的“全局”错误页面。对于机器客户端,它会生成一个 JSON 响应,其中包含错误、HTTP 状态和异常消息的详细信息。对于浏览器客户端,有一个“whitelabel”错误视图,它以 HTML 格式呈现相同的数据
它允许您以灵活的方式指定授权哪种跨域请求,而不是使用 IFRAME 或 JSONP 等一些不太安全和不太强大的方法。
从 4.2 版开始,Spring MVC支持 CORS。在 Spring Boot 应用程序中使用带有注释的控制器方法 CORS 配置@CrossOrigin
不需要任何特定配置。 可以通过使用自定义方法注册 bean来定义全局 CORS 配置,如下例所示:
@Configuration(proxyBeanMethods = false)
public class MyCorsConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**");
}
};
}
}