Spring Boot非常适合Web应用程序开发。您可以使用Embedded Tomcat、Jetty、Undertow或Netty创建自包含的HTTP服务器。大多数Web应用程序使用SpringBoot-starter-web
模块来快速启动和运行。您还可以选择使用Spring-boot-starter-webflow
模块来构建反应式Web应用程序。
如果您还没有开发Spring Boot Web应用程序,您可以使用“Hello World!”入门部分中的示例。
1. Servlet Web Applications
如果你想构建基于Servlet的Web应用程序,你可以利用Spring Boot对Spring MVC或Jersey的自动配置。
1.1. The “Spring Web MVC Framework”
Spring Web MVC框架(通常称为“Spring MVC”)是一个丰富的“模型-视图-控制器”Web框架。Spring MVC允许您创建特殊的@Controller
或@RestController
Bean来处理传入的HTTP请求。控制器中的方法通过使用@Requestmap
注释映射到HTTP。
下面的代码显示了一个典型的服务JSON数据的@RestController
:
@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("/{userId}") public User getUser(@PathVariable Long userId) { return this.userRepository.findById(userId).get(); } @GetMapping("/{userId}/customers") public List<Customer> getUserCustomers(@PathVariable Long userId) { return this.userRepository.findById(userId).map(this.customerRepository::findByUser).get(); } @DeleteMapping("/{userId}") public void deleteUser(@PathVariable Long userId) { this.userRepository.deleteById(userId); } }
WebMvc.fn是一个功能变体,它将路由配置与请求的实际处理分开,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyRoutingConfiguration { private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON); @Bean public RouterFunction<ServerResponse> routerFunction(MyUserHandler userHandler) { return route() .GET("/{user}", ACCEPT_JSON, userHandler::getUser) .GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers) .DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser) .build(); } }
@Component public class MyUserHandler { public ServerResponse getUser(ServerRequest request) { ... return ServerResponse.ok().build(); } public ServerResponse getUserCustomers(ServerRequest request) { ... return ServerResponse.ok().build(); } public ServerResponse deleteUser(ServerRequest request) { ... return ServerResponse.ok().build(); } }
Spring MVC是核心Spring框架的一部分,有关详细信息,请参阅参考文档。在spring.io/gueses上也有几个介绍Spring MVC的指南。
You can define as many RouterFunction beans as you like to modularize the definition of the router. Beans can be ordered if you need to apply a precedence. |
1.1.1. Spring MVC Auto-configuration
Spring Boot为Spring MVC提供了自动配置,可以很好地与大多数应用程序配合使用。
自动配置在Spring默认设置的基础上添加了以下功能:
如果您想保留这些Spring Boot MVC定制,并进行更多的MVC定制(拦截器、格式化程序、视图控制器和其他功能),您可以添加您自己的@Configurant
类,其类型为WebMvcConfigurer
但没有@EnableWebMvc
。
如果您想要提供RequestMappingHandlerAdapter
、RequestMappingHandlerAdapter
或ExceptionHandlerExceptionResolver
,的定制实例,并且仍然保留Spring Boot MVC定制,那么您可以声明一个WebMvcRegistrations
类型的Bean,并使用它来提供这些组件的定制实例。
如果您想要完全控制Spring MVC,您可以添加您自己的@Configuration
,或者添加您自己的@Configuration
-注释的DelegatingWebMvcConfiguration
,如@EnableWebMvc
的Javadoc中所述。
Spring MVC使用的 如果您想要定制Spring MVC使用的 |
1.1.2. HttpMessageConverters
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都会添加到转换器列表中。您也可以用同样的方式覆盖默认转换器。
1.1.3. MessageCodesResolver
Spring MVC有一种生成错误代码的策略,用于从绑定错误中呈现错误消息:MessageCodesResolver
。如果设置spring.mvc.message-codes-resolver-format
属性PREFIX_ERROR_CODE
或POSTFIX_ERROR_CODE
,则Spring Boot会为您创建一个(请参见DefaultMessageCodesResolver.Format
).
1.1.4. Static Content
默认情况下,Spring Boot提供来自类路径中名为/静态
(或/public
或/resource
或/META-INF/resource
)目录或ServletContext
根目录的静态内容。它使用来自Spring MVC的ResourceHttpRequestHandler
,因此您可以通过添加您自己的WebMvcConfigurer
并覆盖addResourceHandler
方法来修改该行为。
在独立的Web应用程序中,容器中的默认Servlet未启用。可以使用server.servlet.register-default-servlet
属性启用它。
默认的Servlet充当后备,如果Spring决定不处理它,它将从ServletContext
的根提供内容。大多数情况下,这种情况不会发生(除非您修改了默认的MVC配置),因为Spring总是可以通过DispatcherServlet
处理请求。
默认情况下,资源被映射到/**
上,但是您可以使用spring.mvc.static-Path-Pattern
属性对其进行调优。例如,将所有资源重定位到/resource/**
的方法如下:
spring.mvc.static-path-pattern=/resources/**
您还可以使用spring.web.resources.static-locations
属性(用目录位置列表替换默认值)来自定义静态资源位置。根Servlet上下文路径“/”
也会自动添加为一个位置。
除了前面提到的“标准”静态资源位置之外,还为Webjars内容设置了一个特例。默认情况下,路径在/webjars/**
中的任何资源都由JAR文件提供,如果它们以Webjars格式打包的话。路径可以使用spring.mvc.webjars-Path-Pattern
属性进行定制。
Do not use the src/main/webapp directory if your application is packaged as a jar. Although this directory is a common standard, it works only with war packaging, and it is silently ignored by most build tools if you generate a jar. |
Spring Boot还支持由Spring MVC提供的高级资源处理功能,允许使用缓存破坏静态资源或使用Webjars的版本无关URL等用例。
要对Webjar使用与版本无关的URL,请添加webjars-Locator-core
依赖项。然后声明您的Webjar。以jQuery为例,添加“/webjars/jquery/jquery.min.js”
将生成“/webjars/jquery/x.y.z/jquery.min.js”
,其中x.y.z
是Webjar的版本。
If you use JBoss, you need to declare the webjars-locator-jboss-vfs dependency instead of the webjars-locator-core . Otherwise, all Webjars resolve as a 404 . |
要使用缓存破坏,以下配置为所有静态资源配置了缓存破坏方案,有效地添加了内容哈希,如URL中的
spring.web.resources.chain.strategy.content.enabled=true
spring.web.resources.chain.strategy.content.paths=/**
Links to resources are rewritten in templates at runtime, thanks to a ResourceUrlEncodingFilter that is auto-configured for Thymeleaf and FreeMarker. You should manually declare this filter when using JSPs. Other template engines are currently not automatically supported but can be with custom template macros/helpers and the use of the ResourceUrlProvider . |
例如,当使用JavaScript模块加载器动态加载资源时,不能重命名文件。这就是为什么其他战略也得到支持并可以结合在一起的原因。FIXED策略在URL中添加静态版本字符串,而不更改文件名,如下例所示:
spring.web.resources.chain.strategy.content.enabled=true
spring.web.resources.chain.strategy.content.paths=/**
spring.web.resources.chain.strategy.fixed.enabled=true
spring.web.resources.chain.strategy.fixed.paths=/js/lib/
spring.web.resources.chain.strategy.fixed.version=v12
在这种配置下,位于<代码>“/js/lib/” 下的JAVASCRIPT模块使用固定的版本控制策略(<代码>“/v12/js/lib/mymode.js” ),而其他资源仍然使用内容资源(<代码><;链接href=“/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css”/>;).
有关更多支持的选项,请参阅WebProperties.Resources
。
1.1.5. Welcome Page
Spring Boot支持静态和模板化欢迎页面。它首先在配置的静态内容位置中查找index.html
文件。如果没有找到,则查找索引
模板。如果找到其中一个,它将自动用作应用程序的欢迎页面。
1.1.7. Path Matching and Content Negotiation
Spring MVC可以通过查看请求路径并将其与应用程序中定义的映射(例如,控制器方法上的@Getmap
注释)进行匹配,将传入的HTTP请求映射到处理程序。
默认情况下,Spring Boot选择禁用后缀模式匹配,这意味着像“Get/Projects/Spring-boot.json”
@GetMapping(“/projects/spring-boot”)
>这样的请求将不会与Spring映射匹配。这被认为是Spring MVC应用程序的最佳实践。过去,该功能主要用于没有发送正确的“Accept”请求头的HTTP客户端;我们需要确保向客户端发送正确的Content Type。如今,内容协商要可靠得多。
还有其他方法可以处理不一致地发送正确的“Accept”请求标头的HTTP客户端。我们可以不使用后缀匹配,而是使用查询参数来确保像“Get/Projects/Spring-Boot?Format=json”
这样的请求将被映射到@GetMapping(“/projects/spring-boot”)
:
spring.mvc.contentnegotiation.favor-parameter=true
或者,如果您希望使用其他参数名称:
spring.mvc.contentnegotiation.favor-parameter=true
spring.mvc.contentnegotiation.parameter-name=myparam
开箱即可支持大多数标准媒体类型,但您也可以定义新的媒体类型:
spring.mvc.contentnegotiation.media-types.markdown=text/markdown
从Spring Framework5.3开始,Spring MVC支持几种将请求路径匹配到控制器处理程序的实现策略。它以前只支持AntPathMatcher
策略,但现在它还提供PathPatternParser
。Spring Boot现在提供了一个配置属性来选择和选择新策略:
spring.mvc.pathmatch.matching-strategy=path-pattern-parser
有关为什么应该考虑这个新实现的更多详细信息,请参阅专门的博客文章。
PathPatternParser is an optimized implementation but restricts usage of some path patterns variants. It is incompatible with suffix pattern matching or mapping the DispatcherServlet with a servlet prefix (spring.mvc.servlet.path ). |
1.1.8. ConfigurableWebBindingInitializer
Spring MVC使用WebBindingInitializer
为特定请求初始化WebDataBinder
。如果您创建自己的代码<ConfigurableWebBindingInitializer
>@Bean,Spring Boot会自动配置Spring MVC以使用它。
1.1.9. Template Engines
除了REST Web服务,您还可以使用Spring MVC来提供动态的HTML内容。Spring MVC支持多种模板技术,包括Thymeleaf、FreeMarker和JSPs。此外,许多其他模板引擎都包含它们自己的Spring MVC集成。
Spring Boot包括对以下模板引擎的自动配置支持:
If possible, JSPs should be avoided. There are several known limitations when using them with embedded servlet containers. |
当您以默认配置使用这些模板引擎之一时,您的模板将自动从src/main/Resources/Templates
中选取。
Depending on how you run your application, your IDE may order the classpath differently. Running your application in the IDE from its main method results in a different ordering than when you run your application by using Maven or Gradle or from its packaged jar. This can cause Spring Boot to fail to find the expected template. If you have this problem, you can reorder the classpath in the IDE to place the module’s classes and resources first. |
1.1.10. Error Handling
默认情况下,Spring Boot提供一个/error
映射,以合理的方式处理所有错误,并在Servlet容器中注册为“全局”错误页面。对于机器客户端,它生成一个JSON响应,其中包含错误、HTTP状态和异常消息的详细信息。对于浏览器客户端,有一个“白色标签”错误视图,它以HTML格式呈现相同的数据(要定制它,请添加一个视图
,它可以解析为错误
)。
如果要自定义默认错误处理行为,可以设置许多server.error
属性。请参阅附录的“服务器属性”部分。
要完全替换默认行为,您可以实现ErrorController
并注册该类型的Bean定义,或者添加类型为ErrorAttributes
的Bean以使用现有机制但替换内容。
The BasicErrorController can be used as a base class for a custom ErrorController . This is particularly useful if you want to add a handler for a new content type (the default is to handle text/html specifically and provide a fallback for everything else). To do so, extend BasicErrorController , add a public method with a @RequestMapping that has a produces attribute, and create a bean of your new type. |
从Spring Framework6.0开始,支持RFC 7807问题详情。Spring MVC可以生成应用程序/问题+json
媒体类型的自定义错误消息,例如:
{
"type": "https://example.org/problems/unknown-project",
"title": "Unknown project",
"status": 404,
"detail": "No project found for id 'spring-unknown'",
"instance": "/projects/spring-unknown"
}
可以通过将spring.mvc.problemdetails.enabled
设置为TRUE
来启用此支持。
您还可以定义一个用@ControllerAdance
注释的类,以自定义为特定控制器和/或异常类型返回的JSON文档,如下例所示:
@ControllerAdvice(basePackageClasses = SomeController.class) public class MyControllerAdvice extends ResponseEntityExceptionHandler { @ResponseBody @ExceptionHandler(MyException.class) public ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) { HttpStatus status = getStatus(request); return new ResponseEntity<>(new MyErrorBody(status.value(), ex.getMessage()), status); } private HttpStatus getStatus(HttpServletRequest request) { Integer code = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); HttpStatus status = HttpStatus.resolve(code); return (status != null) ? status : HttpStatus.INTERNAL_SERVER_ERROR; } }
在前面的示例中,如果MyException
是由与SomeController
相同的包中定义的控制器引发的,则使用MyErrorBody
POJO的JSON表示而不是ErrorAttributes
表示。
在某些情况下,指标基础结构不会记录在控制器级别处理的错误。通过将已处理的异常设置为请求属性,应用程序可以确保使用请求指标记录此类异常:
@Controller public class MyController { @ExceptionHandler(CustomException.class) String handleCustomException(HttpServletRequest request, CustomException ex) { request.setAttribute(ErrorAttributes.ERROR_ATTRIBUTE, ex); return "errorView"; } }
Custom Error Pages
如果要显示给定状态代码的自定义HTML错误页,可以将文件添加到/error
目录。错误页可以是静态的HTML(即,添加到任何静态资源目录下),也可以使用模板构建。文件的名称应该是确切的状态代码或系列掩码。
例如,要将404
映射到静态HTML文件,您的目录结构如下所示:
src/ +- main/ +- java/ | + <source code> +- resources/ +- public/ +- error/ | +- 404.html +- <other public assets>
要使用FreeMarker模板映射所有5xx
错误,您的目录结构如下所示:
src/ +- main/ +- java/ | + <source code> +- resources/ +- templates/ +- error/ | +- 5xx.ftlh +- <other templates>
对于更复杂的映射,您还可以添加实现ErrorViewResolver
接口的Bean,如下例所示:
public class MyErrorViewResolver implements ErrorViewResolver { @Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) { // Use the request or status to optionally return a ModelAndView if (status == HttpStatus.INSUFFICIENT_STORAGE) { // We could add custom model values here new ModelAndView("myview"); } return null; } }
您还可以使用常规的Spring MVC特性,如@ExceptionHandler
方法和@ControllerAdacy
。然后,Error控制器
拾取任何未处理的异常。
Mapping Error Pages Outside of Spring MVC
对于不使用Spring MVC的应用程序,可以使用ErrorPageRegister
接口直接注册ErrorPages
。这种抽象直接与底层嵌入的Servlet容器一起工作,即使您没有Spring MVCDispatcherServlet
也可以工作。
@Configuration(proxyBeanMethods = false) public class MyErrorPagesConfiguration { @Bean public ErrorPageRegistrar errorPageRegistrar() { return this::registerErrorPages; } private void registerErrorPages(ErrorPageRegistry registry) { registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400")); } }
If you register an ErrorPage with a path that ends up being handled by a Filter (as is common with some non-Spring web frameworks, like Jersey and Wicket), then the Filter has to be explicitly registered as an ERROR dispatcher, as shown in the following example: |
@Configuration(proxyBeanMethods = false) public class MyFilterConfiguration { @Bean public FilterRegistrationBean<MyFilter> myFilter() { FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(new MyFilter()); // ... registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class)); return registration; } }
请注意,默认的FilterRegistrationBean
不包括错误
调度程序类型。
Error Handling in a WAR Deployment
当部署到Servlet容器时,Spring Boot使用其错误页过滤器将具有错误状态的请求转发到适当的错误页。这是必要的,因为Servlet规范不提供用于注册错误页面的API。根据您要将WAR文件部署到的容器和应用程序使用的技术,可能需要一些额外的配置。
如果尚未提交响应,则错误页筛选器只能将请求转发到正确的错误页。默认情况下,WebSphereApplicationServer8.0及更高版本在成功完成Servlet的服务方法后提交响应。应该通过将com.ibm.ws.webcontainer.invokeFlushAfterService
设置为FALSE
来禁用此行为。
1.1.11. CORS Support
从4.2版开始,Spring MVC支持CORS。在您的Spring Boot应用程序中使用带有@CrossOrigin
注释的控制器方法CORS配置不需要任何特定的配置。全局CORS配置可以通过注册WebMvcConfigurer
Bean和自定义的addCorsMappings(CorsRegistry)
方法来定义,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyCorsConfiguration { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**"); } }; } }
1.2. JAX-RS and Jersey
如果您更喜欢REST端点的JAX-RS编程模型,您可以使用一种可用的实现来代替Spring MVC。Jersey和ApacheCXF开箱即用。CXF要求您在应用程序上下文中将其Servlet
或过滤器
注册为@Bean
。Jersey有一些原生的Spring支持,所以我们还在Spring Boot中提供了对它的自动配置支持,以及一个启动器。
要开始使用Jersey,请包括作为依赖项的Spring-Boot-starter-Jersey
,然后您需要一个@Bean
类型的资源配置
,您可以在其中注册所有端点,如下例所示:
@Component public class MyJerseyConfig extends ResourceConfig { public MyJerseyConfig() { register(MyEndpoint.class); } }
Jersey’s support for scanning executable archives is rather limited. For example, it cannot scan for endpoints in a package found in a fully executable jar file or in WEB-INF/classes when running an executable war file. To avoid this limitation, the packages method should not be used, and endpoints should be registered individually by using the register method, as shown in the preceding example. |
对于更高级的定制,您还可以注册实现ResourceConfigCustomizer
的任意数量的Bean。
所有注册的端点都应该是带有HTTP资源注释的@Components
(@get
等),如下例所示:
@Component @Path("/hello") public class MyEndpoint { @GET public String message() { return "Hello"; } }
因为Endpoint
是一个Spring@Component
,所以它的生命周期由Spring管理,您可以使用@AuTower
注释注入依赖项,使用@Value
注释注入外部配置。默认情况下,Jersey Servlet被注册并映射到/*
。您可以通过将@ApplicationPath
添加到您的ResourceConfig
来更改映射。
默认情况下,Jersey被设置为ServletRegistrationBean
类型的@Bean
中的一个Servlet,名为JerseyServletRegister
。缺省情况下,Servlet是延迟初始化的,但您可以通过设置spring.jersey.servlet.load-on-startup
.来自定义该行为您可以通过使用相同的名称创建自己的Bean来禁用或覆盖该Bean。您还可以通过设置spring.Jersey.type=Filter
来使用过滤器而不是Servlet(在这种情况下,要替换或覆盖的@Bean
是JerseyFilterRegister
)。过滤器有一个@order
,您可以使用spring.Jersey.filter.order
设置它。当使用Jersey作为过滤器时,必须存在一个Servlet,该Servlet将处理任何未被Jersey拦截的请求。如果您的应用程序不包含这样的Servlet,您可能希望通过将server.servlet.register-default-servlet
设置为TRUE
来启用默认的Servlet。通过使用spring.Jersey.init.*
指定属性映射,可以为Servlet和过滤器注册提供init参数。
1.3. Embedded Servlet Container Support
对于Servlet应用程序,Spring Boot支持嵌入式Tomcat、Jetty和Undertow服务器。大多数开发人员使用适当的“启动器”来获得完全配置的实例。默认情况下,嵌入式服务器侦听端口8080
上的HTTP请求。
1.3.1. Servlets, Filters, and Listeners
在使用嵌入式Servlet容器时,您可以通过使用SpringBeans或扫描Servlet组件来注册Servlet、过滤器和来自Servlet规范的所有侦听器(如HttpSessionListener
)。
Registering Servlets, Filters, and Listeners as Spring Beans
任何作为Spring Bean的Servlet
、过滤器
或Servlet*Listener
实例都注册到嵌入的容器中。如果您想在配置期间引用应用程序的值
,这会特别方便。
默认情况下,如果上下文仅包含单个Servlet,则将其映射到/
。在多个Servlet Bean的情况下,Bean名称用作路径前缀。筛选器映射到/*
。
如果基于约定的映射不够灵活,可以使用ServletRegistrationBean
、FilterRegistrationBean
和ServletListenerRegistrationBean
类进行完全控制。
通常情况下,将滤豆放在没有订购的地方是安全的。如果需要特定的订单,您应该用@Order
来注释筛选器
,或者让它实现Order
。您不能通过使用@Order
注释其Bean方法来配置筛选器
的顺序。如果无法将Filter
类更改为Add@Order
或实现Order
,则必须为FilterRegistrationBean
定义FilterRegistrationBean
,并使用setOrder(Int)
方法设置注册Bean的顺序。避免配置以Ordered.HIGHEST_PRORCESS
读取请求正文的过滤器,因为这可能与应用程序的字符编码配置相冲突。如果Servlet筛选器包装请求,则应该使用小于或等于OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER
.的顺序进行配置
To see the order of every Filter in your application, enable debug level logging for the web logging group (logging.level.web=debug ). Details of the registered filters, including their order and URL patterns, will then be logged at startup. |
Take care when registering Filter beans since they are initialized very early in the application lifecycle. If you need to register a Filter that interacts with other beans, consider using a DelegatingFilterProxyRegistrationBean instead. |
1.3.2. Servlet Context Initialization
嵌入式Servlet容器不直接执行jakarta.servlet.ServletContainerInitializer
接口或Spring的org.springframework.web.WebApplicationInitializer
接口。这是一个有意的设计决定,旨在降低设计用于在WAR中运行的第三方库可能会破坏Spring Boot应用程序的风险。
如果需要在Spring Boot应用程序中执行Servlet上下文初始化,则应该注册实现org.springframework.boot.web.servlet.ServletContextInitializer
接口的Bean。单个onStartup
方法提供对ServletContext
的访问,如有必要,可以轻松用作现有WebApplicationInitializer
的适配器。
1.3.3. The ServletWebServerApplicationContext
在幕后,Spring Boot使用不同类型的ApplicationContext
来支持嵌入式Servlet容器。ServletWebServerApplicationContext
是一种特殊类型的WebApplicationContext,它通过搜索单个ServletWebServerFactoryBean来引导自身。通常已自动配置了TomcatServletWebServerFactory
、JettyServletWebServerFactory
或UnderowServletWebServerFactory
。
You usually do not need to be aware of these implementation classes. Most applications are auto-configured, and the appropriate ApplicationContext and ServletWebServerFactory are created on your behalf. |
在嵌入式容器设置中,ServletContext
设置为服务器启动的一部分,服务器启动是在应用程序上下文初始化期间发生的。因此,无法使用ServletContext
可靠地初始化ApplicationContext
中的Bean。解决此问题的一种方法是将ApplicationContext
作为Bean的依赖项注入,并仅在需要时访问ServletContext
。另一种方法是在服务器启动后使用回调。这可以使用侦听ApplicationStartedEvent
的ApplicationListener
来完成,如下所示:
public class MyDemoBean implements ApplicationListener<ApplicationStartedEvent> { private ServletContext servletContext; @Override public void onApplicationEvent(ApplicationStartedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); this.servletContext = ((WebApplicationContext) applicationContext).getServletContext(); } }
1.3.4. Customizing Embedded Servlet Containers
可以使用SpringEnvironment
属性配置常见的Servlet容器设置。通常,您将在Application.Properties
或Application.yaml
文件中定义属性。
常见的服务器设置包括:
Spring Boot尽可能地尝试公开公共设置,但这并不总是可行的。对于这些情况,专用名称空间提供特定于服务器的定制(参见server.tomcat
和server.undertow
)。例如,访问日志可以使用嵌入式Servlet容器的特定功能进行配置。
See the ServerProperties class for a complete list. |
SameSite Cookies
Web浏览器可以使用SameSite
Cookie属性来控制是否以及如何在跨站点请求中提交Cookie。该属性对于已开始更改在缺少该属性时使用的缺省值的现代Web浏览器特别相关。
如果希望更改会话Cookie的<代码>SameSite
属性,则可以使用server.servlet.session.cookie.same-site
属性。自动配置的Tomcat、Jetty和Undertow服务器支持此属性。它还用于配置基于SessionRepository
Bean的Spring Session Servlet。
例如,如果希望会话Cookie的SameSite
属性为None
,则可以将以下内容添加到Application.Properties
或Application.yaml
文件中:
server.servlet.session.cookie.same-site=none
如果要更改添加到HttpServletResponse
的其他Cookie的SameSite
属性,可以使用CookieSameSiteSupplier
。向CookieSameSiteSupplier
传递Cookie
,并且可能返回SameSite
值或空
。
有许多方便的工厂和筛选器方法可用于快速匹配特定的Cookie。例如,添加以下Bean将自动为名称与正则表达式myapp.*
匹配的所有cookie应用SameSite
lax
。
@Configuration(proxyBeanMethods = false) public class MySameSiteConfiguration { @Bean public CookieSameSiteSupplier applicationCookieSameSiteSupplier() { return CookieSameSiteSupplier.ofLax().whenHasNameMatching("myapp.*"); } }
Programmatic Customization
如果需要以编程方式配置嵌入的Servlet容器,可以注册实现WebServerFactoryCustomizer
接口的Spring Bean。WebServerFactoryCustomizer
提供对ConfigurableServletWebServerFactory
,的访问,其中包括许多自定义设置器方法。以下示例显示以编程方式设置端口:
@Component public class MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> { @Override public void customize(ConfigurableServletWebServerFactory server) { server.setPort(9000); } }
TomcatServletWebServerFactory
、JettyServletWebServerFactory
和UnderowServletWebServerFactory
是ConfigurableServletWebServerFactory
的专用变体,它们分别为Tomcat、Jetty和Undertow提供了额外的定制设置方法。以下示例显示如何自定义TomcatServletWebServerFactory
,以提供对Tomcat特定配置选项的访问:
@Component public class MyTomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> { @Override public void customize(TomcatServletWebServerFactory server) { server.addConnectorCustomizers((connector) -> connector.setAsyncTimeout(Duration.ofSeconds(20).toMillis())); } }
Customizing ConfigurableServletWebServerFactory Directly
对于需要从ServletWebServerFactory
扩展的更高级用例,您可以自己公开这种类型的Bean。
为许多配置选项提供了设置器。如果您需要做一些更奇特的事情,还提供了几个受保护的方法“钩子”。有关详细信息,请参阅源代码文档。
Auto-configured customizers are still applied on your custom factory, so use that option carefully. |
2. Reactive Web Applications
通过为Spring Webflow提供自动配置,Spring Boot简化了反应式Web应用程序的开发。
2.1. The “Spring WebFlux Framework”
Spring WebFlux是Spring Framework5.0中引入的新的反应式Web框架。与Spring MVC不同,它不需要Servlet API,是完全异步和非阻塞的,并通过反应器项目实现了反应流规范。
Spring WebFlux有两种风格:函数式和基于注释。基于注释的模型非常接近于Spring MVC模型,如下例所示:
@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("/{userId}") public Mono<User> getUser(@PathVariable Long userId) { return this.userRepository.findById(userId); } @GetMapping("/{userId}/customers") public Flux<Customer> getUserCustomers(@PathVariable Long userId) { return this.userRepository.findById(userId).flatMapMany(this.customerRepository::findByUser); } @DeleteMapping("/{userId}") public Mono<Void> deleteUser(@PathVariable Long userId) { return this.userRepository.deleteById(userId); } }
函数变量“WebFlos.fn”将路由配置与请求的实际处理分开,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyRoutingConfiguration { private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON); @Bean public RouterFunction<ServerResponse> monoRouterFunction(MyUserHandler userHandler) { return route() .GET("/{user}", ACCEPT_JSON, userHandler::getUser) .GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers) .DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser) .build(); } }
@Component public class MyUserHandler { public Mono<ServerResponse> getUser(ServerRequest request) { ... } public Mono<ServerResponse> getUserCustomers(ServerRequest request) { ... } public Mono<ServerResponse> deleteUser(ServerRequest request) { ... } }
WebFlux是Spring框架的一部分,详细信息可在其参考文档中找到。
You can define as many RouterFunction beans as you like to modularize the definition of the router. Beans can be ordered if you need to apply a precedence. |
要开始使用,请将Spring-ot-starter-webflow
模块添加到应用程序中。
Adding both spring-boot-starter-web and spring-boot-starter-webflux modules in your application results in Spring Boot auto-configuring Spring MVC, not WebFlux. This behavior has been chosen because many Spring developers add spring-boot-starter-webflux to their Spring MVC application to use the reactive WebClient . You can still enforce your choice by setting the chosen application type to SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE) . |
2.1.1. Spring WebFlux Auto-configuration
Spring Boot为Spring WebFlux提供了自动配置,可以很好地与大多数应用程序配合使用。
自动配置在Spring默认设置的基础上添加了以下功能:
如果您想要保留Spring Boot WebFlux特性,并且想要添加额外的WebFlux配置,您可以添加您自己的@Configuration
类,其类型为WebFlosConfigurer
但没有@EnableWebFlux
。
如果您想要完全控制Spring WebFlux,可以添加您自己的@configuration
,并用@EnableWebFlux
进行注释。
2.1.2. HTTP Codecs with HttpMessageReaders and HttpMessageWriters
Spring WebFlux使用HttpMessageReader
和HttpMessageWriter
接口来转换HTTP请求和响应。通过查看类路径中可用的库,使用CodecConfigurer
将它们配置为具有合理的缺省值。
Spring Boot为编解码器提供专用的配置属性,spring.codec..*
。它还通过使用CodecCustomizer
实例应用进一步的定制。例如,spring.jackson.*
配置密钥应用于Jackson编解码器。
如果您需要添加或定制编解码器,您可以创建一个自定义的CodecCustomizer
组件,如下例所示:
@Configuration(proxyBeanMethods = false) public class MyCodecsConfiguration { @Bean public CodecCustomizer myCodecCustomizer() { return (configurer) -> { configurer.registerDefaults(false); configurer.customCodecs().register(new ServerSentEventHttpMessageReader()); // ... }; } }
您还可以利用Boot的定制JSON序列化程序和反序列化程序。
2.1.3. Static Content
默认情况下,Spring Boot提供类路径中名为/静态
(或/public
或/resource
或/META-INF/resource
)目录中的静态内容。它使用来自Spring WebFlux的ResourceWebHandler
,因此您可以通过添加您自己的WebFlosConfigurer
并覆盖addResourceHandler
方法来修改该行为。
默认情况下,资源映射到/**
,但您可以通过设置spring.webflux.static-path-pattern
属性对其进行优化。例如,将所有资源重定位到/resource/**
的方法如下:
spring.webflux.static-path-pattern=/resources/**
您还可以使用spring.web.resources.static-locations
.来自定义静态资源位置这样做会将缺省值替换为目录位置列表。如果这样做,默认欢迎页面检测将切换到您的自定义位置。因此,如果在启动时您的任何位置都有index.html
,那么它就是应用程序的主页。
除了前面列出的“标准”静态资源位置之外,还为Webjars内容设置了一个特例。默认情况下,路径在/webjars/**
中的任何资源都由JAR文件提供,如果它们以Webjars格式打包的话。可以使用spring.webflux.webjars-path-pattern
属性自定义路径。
Spring WebFlux applications do not strictly depend on the servlet API, so they cannot be deployed as war files and do not use the src/main/webapp directory. |
2.1.4. Welcome Page
Spring Boot支持静态和模板化欢迎页面。它首先在配置的静态内容位置中查找index.html
文件。如果没有找到,则查找索引
模板。如果找到其中一个,它将自动用作应用程序的欢迎页面。
2.1.5. Template Engines
除了REST Web服务,您还可以使用Spring WebFlux来提供动态的HTML内容。Spring WebFlux支持多种模板技术,包括Thymeleaf、FreeMarker和Mustache。
Spring Boot包括对以下模板引擎的自动配置支持:
当您以默认配置使用这些模板引擎之一时,您的模板将自动从src/main/Resources/Templates
中选取。
2.1.6. Error Handling
Spring Boot提供了一个WebExceptionHandler
,它以合理的方式处理所有错误。它在处理顺序中的位置紧靠在WebFlux提供的处理程序之前,后者被认为是最后一个。对于机器客户端,它生成一个JSON响应,其中包含错误、HTTP状态和异常消息的详细信息。对于浏览器客户端,有一个“白色标签”错误处理程序,它以HTML格式呈现相同的数据。您还可以提供自己的HTML模板来显示错误(请参阅下一节)。
在直接定制Spring Boot中的错误处理之前,您可以利用Spring WebFlux中的RFC7807问题详细信息支持。Spring WebFlux可以生成应用程序/问题+json
媒体类型的自定义错误消息,例如:
{
"type": "https://example.org/problems/unknown-project",
"title": "Unknown project",
"status": 404,
"detail": "No project found for id 'spring-unknown'",
"instance": "/projects/spring-unknown"
}
可以通过将spring.webflux.problemdetails.enabled
设置为TRUE
来启用此支持。
定制此功能的第一步通常涉及使用现有机制,但替换或增加错误内容。为此,您可以添加ErrorAttributes
类型的Bean。
要更改错误处理行为,您可以实现ErrorWebExceptionHandler
并注册该类型的Bean定义。由于ErrorWebExceptionHandler
是相当底层的,Spring Boot还提供了一个方便的AbstractErrorWebExceptionHandler
,可以让您以WebFlux函数的方式处理错误,如下例所示:
@Component public class MyErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { public MyErrorWebExceptionHandler(ErrorAttributes errorAttributes, Resources resources, ApplicationContext applicationContext) { super(errorAttributes, resources, applicationContext); } @Override protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) { return RouterFunctions.route(this::acceptsXml, this::handleErrorAsXml); } private boolean acceptsXml(ServerRequest request) { return request.headers().accept().contains(MediaType.APPLICATION_XML); } public Mono<ServerResponse> handleErrorAsXml(ServerRequest request) { BodyBuilder builder = ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR); // ... additional builder calls return builder.build(); } }
要了解更完整的情况,您还可以直接子类化DefaultErrorWebExceptionHandler
并覆盖特定的方法。
@Controller public class MyExceptionHandlingController { @GetMapping("/profile") public Rendering userProfile() { // ... throw new IllegalStateException(); } @ExceptionHandler(IllegalStateException.class) public Rendering handleIllegalState(ServerWebExchange exchange, IllegalStateException exc) { exchange.getAttributes().putIfAbsent(ErrorAttributes.ERROR_ATTRIBUTE, exc); return Rendering.view("errorView").modelAttribute("message", exc.getMessage()).build(); } }
Custom Error Pages
如果要显示给定状态代码的自定义HTML错误页,可以将文件添加到/error
目录。错误页可以是静态的HTML(即,添加到任何静态资源目录下),也可以是使用模板构建的。文件的名称应该是确切的状态代码或系列掩码。
例如,要将404
映射到静态HTML文件,您的目录结构如下所示:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
要使用Mustache模板映射所有5xx
错误,您的目录结构如下所示:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>
2.1.7. Web Filters
Spring WebFlux提供了一个WebFilter
接口,可以实现该接口来过滤HTTP请求-响应交换。WebFilter
在应用程序上下文中找到的Bean将自动用于筛选每个交换。
在过滤器的顺序很重要的地方,它们可以实现ordered
或使用@order
进行注释。Spring Boot自动配置可以为您配置网络过滤器。执行此操作时,将使用下表中所示的订单:
Web Filter | Order |
---|---|
|
|
|
|
2.2. Embedded Reactive Server Support
Spring Boot包括对以下嵌入式反应式Web服务器的支持:Reader Netty、Tomcat、Jetty和Undertow。大多数开发人员使用适当的“启动器”来获得完全配置的实例。默认情况下,嵌入式服务器侦听端口8080上的HTTP请求。
2.3. Reactive Server Resources Configuration
当自动配置反应器Netty或Jetty服务器时,Spring Boot将创建特定的Bean,这些Bean将向服务器实例提供HTTP资源:ReacterResourceFactory
或JettyResourceFactory
。
默认情况下,这些资源还将与反应堆Netty和Jetty客户端共享,以实现最佳性能,前提是:
-
服务器和客户端使用相同的技术
-
客户端实例是使用由Spring Boot自动配置的
WebClient.Builder
Bean构建的
开发人员可以通过提供定制的ReacterResourceFactory
或JettyResourceFactory
Bean来覆盖Jetty和反应器Netty的资源配置--这将同时应用于客户端和服务器。
您可以在WebClient运行时部分中了解有关客户端资源配置的更多信息。
3. Graceful Shutdown
所有四个嵌入式Web服务器(Jetty、Reactive Netty、Tomcat和Undertow)以及反应性Web应用程序和基于Servlet的Web应用程序都支持正常关闭。它发生在关闭应用程序上下文的过程中,并在停止SmartLifeccle
Bean的最早阶段执行。此停止处理使用超时,该超时提供了一段宽限期,在此期间将允许完成现有请求,但不允许任何新请求。不允许新请求的确切方式因所使用的Web服务器而异。Jetty、Reader Netty和Tomcat将停止在网络层接受请求。Untow将接受请求,但立即以服务不可用(503)响应响应。
Graceful shutdown with Tomcat requires Tomcat 9.0.33 or later. |
要启用正常关闭,请配置server.Shutdown
属性,如下例所示:
server.shutdown=graceful
要配置超时期限,请配置spring.lifecycle.timeout-per-shutdown-phase
属性,如下例所示:
spring.lifecycle.timeout-per-shutdown-phase=20s
Using graceful shutdown with your IDE may not work properly if it does not send a proper SIGTERM signal. See the documentation of your IDE for more details. |
4. Spring Security
如果Spring Security在类路径上,则默认情况下Web应用程序是受保护的。Spring Boot依靠Spring Security的内容协商策略来确定是使用httpBasic
还是使用formLogin
。要向Web应用程序添加方法级安全性,还可以使用所需设置添加@EnableGlobalMethodSecurity
。更多信息可以在Spring Security Reference Guide中找到。
默认UserDetailsService
只有一个用户。用户名为user
,密码是随机的,在应用程序启动时打印为警告级别,如下例所示:
Using generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35 This generated password is for development use only. Your security configuration must be updated before running your application in production.
If you fine-tune your logging configuration, ensure that the org.springframework.boot.autoconfigure.security category is set to log WARN -level messages. Otherwise, the default password is not printed. |
您可以通过提供spring.security.user.name
和spring.security.user.password
来更改用户名和密码。
默认情况下,您在Web应用程序中获得的基本功能包括:
-
一个
SecurityProperties.User
>UserDetailsService (或<代码>Reactive UserDetailsService ,如果是WebFlux应用程序)Bean,具有内存存储和具有生成的密码的单个用户(有关用户的属性,请参阅 -
整个应用程序(包括执行器端点,如果执行器在类路径上)的基于表单的登录或HTTP基本安全性(取决于请求中的
Accept
头)。 -
用于发布身份验证事件的
DefaultAuthenticationEventPublisher
。
您可以通过为其添加一个Bean来提供不同的AuthenticationEventPublisher
。
4.1. MVC Security
默认安全配置在SecurityAutoConfiguration
和UserDetailsServiceAutoConfiguration
.中实现安全自动配置
导入用于Web安全的SpringBootWebSecurityConfiguration
,UserDetailsServiceAutoConfiguration
配置身份验证,这也与非Web应用程序相关。要完全关闭默认的Web应用程序安全配置或组合多个Spring Security组件,如OAuth2客户端和资源服务器,添加一个SecurityFilterChain
类型的Bean(这样做并不会禁用UserDetailsService
配置或Actuator的安全性)。
若要同时关闭UserDetailsService
配置,您可以添加UserDetailsService
、AuthenticationProvider
或AuthenticationManager
类型的Bean。
可以通过添加自定义SecurityFilterChain
Bean来覆盖访问规则。Spring Boot提供了方便的方法,可用于覆盖执行器端点和静态资源的访问规则。EndpointRequest
可用于创建基于management.endpoints.web.base-path
属性的RequestMatcher
。路径请求
可以为常用位置的资源创建RequestMatcher
。
4.2. WebFlux Security
与Spring MVC应用程序类似,您可以通过添加Spring-ot-starter-security
依赖项来保护WebFlux应用程序。默认安全配置在ReactiveSecurityAutoConfiguration
和UserDetailsServiceAutoConfiguration
.中实施ReactiveSecurityAutoConfiguration
为Web安全导入WebFlosSecurityConfigurity
,UserDetailsServiceAutoConfiguration
配置身份验证,这在非Web应用中也是相关的。要完全关闭默认的Web应用程序安全配置,您可以添加一个WebFilterChainProxy
类型的Bean(这样做并不会禁用UserDetailsService
配置或Actuator的安全性)。
若要同时关闭UserDetailsService
配置,您可以添加Reactive UserDetailsService
或Reactive AuthationManager
类型的Bean。
通过添加定制的SecurityWebFilterChain
Bean,可以配置访问规则和多个Spring Security组件的使用,如OAuth 2客户端和资源服务器。Spring Boot提供了方便的方法,可用于覆盖执行器端点和静态资源的访问规则。EndpointRequest
可用于创建基于management.endpoints.web.base-path
属性的ServerWebExchangeMatcher
。
路径请求
可以为常用位置的资源创建ServerWebExchangeMatcher
。
例如,您可以通过添加以下内容来自定义您的安全配置:
@Configuration(proxyBeanMethods = false) public class MyWebFluxSecurityConfiguration { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { http.authorizeExchange((exchange) -> { exchange.matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll(); exchange.pathMatchers("/foo", "/bar").authenticated(); }); http.formLogin(withDefaults()); return http.build(); } }
4.3. OAuth2
OAuth2是一个得到Spring支持的广泛使用的授权框架。
4.3.1. Client
如果您的类路径上有Spring-Security-OAuth2-Client
,那么您可以利用一些自动配置来设置OAuth2/Open ID Connect客户端。此配置使用OAuth2ClientProperties
下的属性。相同的属性适用于Servlet和反应式应用程序。
您可以在spring.security.oauth2.client
前缀下注册多个OAuth2客户端和提供者,如下例所示:
spring.security.oauth2.client.registration.my-client-1.client-id=abcd
spring.security.oauth2.client.registration.my-client-1.client-secret=password
spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope
spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-1.scope=user
spring.security.oauth2.client.registration.my-client-1.redirect-uri=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-1.client-authentication-method=basic
spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-2.client-id=abcd
spring.security.oauth2.client.registration.my-client-2.client-secret=password
spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope
spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider
spring.security.oauth2.client.registration.my-client-2.scope=email
spring.security.oauth2.client.registration.my-client-2.redirect-uri=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-2.client-authentication-method=basic
spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=https://my-auth-server/oauth/authorize
spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://my-auth-server/oauth/token
spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=https://my-auth-server/userinfo
spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header
spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=https://my-auth-server/token_keys
spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name
对于支持OpenID Connect发现的OpenID Connect提供商,可以进一步简化配置。提供者需要配置一个Issuer-uri
,这是它断言为其颁发者标识符的URI。例如,如果提供的颁发者-uri
是“https://example.com”,“,则将向”https://example.com/.well-known/openid-configuration“.发出OpenID提供者配置请求
预期结果将是OpenID提供程序配置响应
。以下示例显示如何使用Issuer-uri
配置OpenID Connect提供程序:
spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
默认情况下,Spring Security的OAuth2LoginAuthenticationFilter
只处理与/login/OAuth2/code/*
匹配的URL。如果您想要自定义重定向-uri
以使用不同的模式,则需要提供处理该自定义模式的配置。例如,对于Servlet应用程序,您可以添加自己的SecurityFilterChain
,如下所示:
@Configuration(proxyBeanMethods = false) public class MyOAuthClientConfiguration { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated()); http.oauth2Login((login) -> login.redirectionEndpoint().baseUri("custom-callback")); return http.build(); } }
Spring Boot auto-configures an InMemoryOAuth2AuthorizedClientService which is used by Spring Security for the management of client registrations. The InMemoryOAuth2AuthorizedClientService has limited capabilities and we recommend using it only for development environments. For production environments, consider using a JdbcOAuth2AuthorizedClientService or creating your own implementation of OAuth2AuthorizedClientService . |
OAuth2 Client Registration for Common Providers
对于常见的OAuth2和OpenID提供者,包括Google、Github、Facebook和Okta,我们提供了一组提供者默认设置(分别为Google
、GitHub
、Facebook
和Okta
)。
如果不需要自定义这些提供程序,则可以将提供程序
属性设置为需要推断其缺省值的属性。此外,如果客户端注册的键与默认支持的提供程序匹配,则Spring Boot也会推断出这一点。
换句话说,以下示例中的两种配置使用Google提供程序:
spring.security.oauth2.client.registration.my-client.client-id=abcd
spring.security.oauth2.client.registration.my-client.client-secret=password
spring.security.oauth2.client.registration.my-client.provider=google
spring.security.oauth2.client.registration.google.client-id=abcd
spring.security.oauth2.client.registration.google.client-secret=password
4.3.2. Resource Server
如果您的类路径上有spring-security-oauth2-resource-server
,那么Spring Boot可以设置一个OAuth2资源服务器。对于JWT配置,需要指定JWK Set URI或OIDC Issuer URI,如下例所示:
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
If the authorization server does not support a JWK Set URI, you can configure the resource server with the Public Key used for verifying the signature of the JWT. This can be done using the spring.security.oauth2.resourceserver.jwt.public-key-location property, where the value needs to point to a file containing the public key in the PEM-encoded x509 format. |
相同的属性适用于Servlet和反应式应用程序。
或者,您可以为Servlet应用程序定义您自己的JwtDecoder
Bean,或者为反应式应用程序定义一个Reactive JwtDecoder
。
在使用不透明令牌而不是JWT的情况下,您可以配置以下属性以通过自检验证令牌:
spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://example.com/check-token
spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id
spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret
同样,相同的属性也适用于Servlet和反应式应用程序。
或者,您可以为Servlet应用程序定义您自己的OpaqueTokenIntrospector
Bean,或者为反应式应用程序定义一个Reactive OpaqueTokenIntrospector
。
4.3.3. Authorization Server
目前,Spring Security不支持实现OAuth 2.0授权服务器。然而,该功能可以从Spring Security OAuth项目中获得,该项目最终将被Spring Security完全取代。在此之前,您可以使用spring-security-oauth2-autoconfigure
模块轻松设置OAuth2.0授权服务器;有关说明,请参阅其文档。
4.4. SAML 2.0
4.4.1. Relying Party
如果您的类路径上有spring-security-saml2-service-provider
,则可以利用一些自动配置来设置SAML2.0依赖方。此配置使用Saml2RelyingPartyProperties
下的属性。
依赖方注册表示身份提供商IdP和服务提供商SP之间的配对配置。您可以在spring.security.saml2.relyingparty
前缀下注册多个依赖方,如下例所示:
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party1.decryption.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party1.decryption.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party1.singlelogout.url=https://myapp/logout/saml2/slo
spring.security.saml2.relyingparty.registration.my-relying-party1.singlelogout.response-url=https://remoteidp2.slo.url
spring.security.saml2.relyingparty.registration.my-relying-party1.singlelogout.binding=POST
spring.security.saml2.relyingparty.registration.my-relying-party1.assertingparty.verification.credentials[0].certificate-location=path-to-verification-cert
spring.security.saml2.relyingparty.registration.my-relying-party1.assertingparty.entity-id=remote-idp-entity-id1
spring.security.saml2.relyingparty.registration.my-relying-party1.assertingparty.sso-url=https://remoteidp1.sso.url
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party2.decryption.credentials[0].private-key-location=path-to-private-key
spring.security.saml2.relyingparty.registration.my-relying-party2.decryption.credentials[0].certificate-location=path-to-certificate
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.verification.credentials[0].certificate-location=path-to-other-verification-cert
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.entity-id=remote-idp-entity-id2
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.sso-url=https://remoteidp2.sso.url
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.singlelogout.url=https://remoteidp2.slo.url
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.singlelogout.response-url=https://myapp/logout/saml2/slo
spring.security.saml2.relyingparty.registration.my-relying-party2.assertingparty.singlelogout.binding=POST
对于SAML2注销,默认情况下,Spring Security的Saml2LogoutRequestFilter
和Saml2LogoutResponseFilter
只处理匹配/logout/saml2/slo
的URL。如果要自定义AP发起的注销请求发送到的url
或AP向其发送注销响应的Response-url
以使用不同的模式,则需要提供处理该自定义模式的配置。例如,对于Servlet应用程序,您可以添加自己的SecurityFilterChain
,如下所示:
@Configuration(proxyBeanMethods = false) public class MySamlRelyingPartyConfiguration { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests().anyRequest().authenticated(); http.saml2Login(); http.saml2Logout((saml2) -> saml2.logoutRequest((request) -> request.logoutUrl("/SLOService.saml2")) .logoutResponse((response) -> response.logoutUrl("/SLOService.saml2"))); return http.build(); } }
5. Spring Session
Spring Boot为各种数据存储提供了SpringSession自动配置。构建Servlet Web应用程序时,可以自动配置以下存储:
-
雷迪斯人
-
JDBC
-
黑兹卡斯特
-
MongoDB
此外,Spring Boot for ApacheGeode提供了将ApacheGeode用作会话存储的自动配置。
Servlet自动配置取代了使用@Enable*HttpSession
的需要。
如果类路径上存在单个Spring会话模块,则Spring Boot会自动使用该存储实现。如果您有多个实现,则Spring Boot使用以下顺序来选择特定的实现:
-
雷迪斯人
-
JDBC
-
黑兹卡斯特
-
MongoDB
-
如果Redis、JDBC、Hazelcast和MongoDB都不可用,则不配置
SessionRepository
。
在构建反应式Web应用程序时,可以自动配置以下存储:
-
雷迪斯人
-
MongoDB
反应式自动配置取代了使用@Enable*WebSession
的需要。
与Servlet配置类似,如果您有多个实现,则Spring Boot使用以下顺序来选择特定的实现:
-
雷迪斯人
-
MongoDB
-
如果Redis和MongoDB都不可用,则不配置
Reactive SessionRepository
。
每个商店都有特定的附加设置。例如,可以定制JDBC存储的表名称,如下例所示:
spring.session.jdbc.table-name=SESSIONS
要设置会话的超时,可以使用spring.ession.timeout
属性。如果未使用Servlet Web应用程序设置该属性,则自动配置将恢复为server.servlet.ession.timeout
的值。
您可以使用@Enable*HttpSession
(Servlet)或@Enable*WebSession
(被动)来控制Spring会话的配置。这将导致自动配置后退。然后,可以使用注释的属性来配置Spring会话,而不是使用前面描述的配置属性。
6. Spring for GraphQL
如果您想构建GraphQL应用程序,您可以利用Spring Boot对Spring for GraphQL的自动配置。Spring for GraphQL项目基于GraphQL Java。您至少需要Spring-Boot-starter-GraphQL
starter。因为GraphQL与传输无关,所以您还需要在应用程序中有一个或多个额外的启动器,才能在Web上公开您的GraphQL API:
Starter | Transport | Implementation |
---|---|---|
|
HTTP |
Spring MVC |
|
WebSocket |
Servlet应用程序的WebSocket |
|
HTTP、WebSocket |
Spring WebFlux |
|
TCP、WebSocket |
反应堆网上的Spring WebFlux |
6.1. GraphQL Schema
一个Spring GraphQL应用程序需要在启动时定义一个模式。默认情况下,您可以在src/main/resource/GraphQL/**
下编写“.graph qls”或“.gqls”模式文件,Spring Boot会自动获取它们。您可以使用spring.graph ql.schema.Locations
和使用spring.graphql.schema.file-extensions
.的文件扩展名来自定义位置
If you want Spring Boot to detect schema files in all your application modules and dependencies for that location, you can set spring.graphql.schema.locations to "classpath*:graphql/**/" (note the classpath*: prefix). |
在接下来的部分中,我们将考虑这个样例GraphQL模式,它定义了两种类型和两个查询:
type Query {
greeting(name: String! = "Spring"): String!
project(slug: ID!): Project
}
""" A Project in the Spring portfolio """
type Project {
""" Unique string id used in URLs """
slug: ID!
""" Project name """
name: String!
""" URL of the git repository """
repositoryUrl: String!
""" Current support status """
status: ProjectStatus!
}
enum ProjectStatus {
""" Actively supported by the Spring team """
ACTIVE
""" Supported by the community """
COMMUNITY
""" Prototype, not officially supported yet """
INCUBATING
""" Project being retired, in maintenance mode """
ATTIC
""" End-Of-Lifed """
EOL
}
By default, field introspection will be allowed on the schema as it is required for tools such as GraphiQL. If you wish to not expose information about the schema, you can disable introspection by setting spring.graphql.schema.introspection.enabled to false . |
6.2. GraphQL RuntimeWiring
GraphQL JavaRounmeWiring.Builder
可用于注册自定义标量类型、指令、类型解析器、DataFetcher等。您可以在您的Spring配置中声明`RounmeWiringConfigurer
Bean来访问RounmeWiring.Builder
。Spring Boot检测到这样的Bean,并将它们添加到GraphQlSource构建器。
然而,通常情况下,应用程序不会直接实现DataFetcher
,而是创建注释控制器。Spring Boot将自动检测带有带注释的处理程序方法的@Controler
类,并将这些类注册为DataFetcher的类。以下是带有`@Controler
类的问候语查询的示例实现:
@Controller public class GreetingController { @QueryMapping public String greeting(@Argument String name) { return "Hello, " + name + "!"; } }
6.3. Querydsl and QueryByExample Repositories Support
Spring Data提供了对Querydsl和QueryByExample存储库的支持。Spring GraphQL可以将Querydsl和QueryByExample存储库配置为DataFetcher
。
用@GraphQlRepository
注释并扩展以下内容之一的Spring数据存储库:
-
QuerydslPredicateExecutor
-
ReactiveQuerydslPredicateExecutor
-
QueryByExampleExecutor
-
Reactive QueryByExampleExecutor
被Spring Boot检测到,并被认为是匹配顶级查询的DataFetcher
的候选者。
6.4. Transports
6.4.1. HTTP and WebSocket
默认情况下,GraphQL HTTP终结点位于HTTP POST“/GraphQL”。路径可以通过spring.graph ql.Path
进行自定义。
The HTTP endpoint for both Spring MVC and Spring WebFlux is provided by a RouterFunction bean with an @Order of 0 . If you define your own RouterFunction beans, you may want to add appropriate @Order annotations to ensure that they are sorted correctly. |
默认情况下,GraphQL WebSocket终结点处于关闭状态。要启用它,请执行以下操作:
-
对于Servlet应用程序,添加WebSocket starter
Spring-ot-starter-web套接字
-
对于WebFlux应用程序,不需要其他依赖项
-
对于这两者,都必须设置
spring.graph ql.websocket.Path
应用程序属性
Spring GraphQL提供了一个Web拦截模型。这对于从HTTP请求报头中检索信息并将其设置在GraphQL上下文中,或者从相同的上下文中获取信息并将其写入响应报头非常有用。使用Spring Boot,您可以声明一个WebInterceptor
Bean,以便将其注册到Web传输。
Spring MVC和Spring WebFlux支持CORS(跨域资源共享)请求。CORS是GraphQL应用程序Web配置的关键部分,可以从使用不同域的浏览器访问这些应用程序。
Spring Boot支持spring.graph ql.cos.*
名称空间下的许多配置属性;下面是一个简短的配置示例:
spring.graphql.cors.allowed-origins=https://example.org
spring.graphql.cors.allowed-methods=GET,POST
spring.graphql.cors.max-age=1800s
6.4.2. RSocket
RSocket也被支持作为一种传输,在WebSocket或TCP之上。一旦配置了RSocket服务器,我们就可以使用spring.graph ql.rsocket.map
在特定的路由上配置我们的GraphQL处理程序。例如,将该映射配置为“GraphQL”
意味着我们可以在使用RSocketGraphQlClient
发送请求时将其用作路由。
RSocketGraphQlClient.Builder<;?>;
Boot自动配置您可以注入组件中的Spring Bean:
@Component
public class RSocketGraphQlClientExample {
private final RSocketGraphQlClient graphQlClient;
public RSocketGraphQlClientExample(RSocketGraphQlClient.Builder<?> builder) {
this.graphQlClient = builder.tcp("example.spring.io", 8181).route("graphql").build();
}
然后发送一个请求:
Mono<Book> book = this.graphQlClient.document("{ bookById(id: \"book-1\"){ id name pageCount author } }")
.retrieve("bookById").toEntity(Book.class);
6.5. Exceptions Handling
Spring GraphQL使应用程序能够注册一个或多个按顺序调用的SpringDataFetcherExceptionResolver
组件。必须将异常解析为graph ql.GraphQLError
对象的列表,请参阅Spring GraphQL异常处理文档。Spring Boot将自动检测DataFetcherExceptionResolver
Bean,并使用GraphQlSource.Builder
注册它们。
6.6. GraphiQL and Schema printer
Spring GraphQL提供了在使用或开发GraphQL API时帮助开发人员的基础设施。
Spring GraphQL附带了一个默认的GraphiQL页面,该页面默认显示在“/graph iql”
。默认情况下,此页处于禁用状态,可以使用spring.graph ql.graph iql.Enabled
属性打开它。许多公开此类页面的应用程序将倾向于自定义生成。默认实现在开发期间非常有用,这就是为什么它在开发期间自动用spring-boot-devtools
公开的原因。
当启用spring.graphql.schema.printer.enabled
属性时,您还可以选择在<代码>/GraphQL/SCHEMA处以文本格式公开GraphQL架构。
7. Spring HATEOAS
如果您开发了一个利用超媒体的RESTful API,那么Spring Boot为Spring HATEOAS提供了自动配置,可以很好地与大多数应用程序配合使用。自动配置取代了使用@EnableHypermediaSupport
的需要,并注册了许多Bean来简化基于超媒体的应用程序的构建,包括LinkDiscoverers
(用于客户端支持)和ObjectMapper
,它们被配置为将响应正确地编组到所需的表示形式中。对象映射器
是通过设置各种spring.jackson.*
属性或Jackson2ObjectMapperBuilder
Bean(如果存在)来自定义的。
您可以使用@EnableHypermediaSupport
来控制Spring HATEOAS的配置。请注意,这样做会禁用前面描述的ObjectMapper
定制。
spring-boot-starter-hateoas is specific to Spring MVC and should not be combined with Spring WebFlux. In order to use Spring HATEOAS with Spring WebFlux, you can add a direct dependency on org.springframework.hateoas:spring-hateoas along with spring-boot-starter-webflux . |