springboot3 web
isTrueLoveColour 2024-08-06 15:03:02 阅读 80
springboot web配置
springboot web的配置有:
SpringMvc配置的前缀为:<code>spring.mvcweb场景的通用配置为:spring.web
文件上传的配置为:spring.servlet.multipart
服务器相关配置为:server
接管SpringMVC 的三种方式
方式 | 用法 | 效果 | |
---|---|---|---|
全自动 | 直接编写控制器逻辑 | 全部使用自动配置默认效果 | |
手自一体 | @Configuration + 配置**WebMvcConfigurer** + 配置 WebMvcRegistrations | 不要标注 @**EnableWebMvc** | 保留自动配置效果 手动设置部分功能 定义MVC底层组件 |
全手动 | @Configuration + 配置**WebMvcConfigurer** | 标注 @**EnableWebMvc** | 禁用自动配置效果 全手动设置 |
WebMvcConfigurer 定义扩展SpringMVC底层功能
提供方法 | 核心参数 | 功能 | 默认 |
---|---|---|---|
addFormatters | FormatterRegistry | 格式化器:支持属性上@NumberFormat和@DatetimeFormat的数据类型转换 | GenericConversionService |
getValidator | 无 | 数据校验:校验 Controller 上使用@Valid标注的参数合法性。需要导入starter-validator | 无 |
addInterceptors | InterceptorRegistry | 拦截器:拦截收到的所有请求 | 无 |
configureContentNegotiation | ContentNegotiationConfigurer | 内容协商:支持多种数据格式返回。需要配合支持这种类型的HttpMessageConverter | 支持 json |
configureMessageConverters | List<HttpMessageConverter<?>> | 消息转换器:标注@ResponseBody的返回值会利用MessageConverter直接写出去 | 8 个,支持byte,string,multipart,resource,json |
addViewControllers | ViewControllerRegistry | 视图映射:直接将请求路径与物理视图映射。用于无 java 业务逻辑的直接视图页渲染 | 无 mvc:view-controller |
configureViewResolvers | ViewResolverRegistry | 视图解析器:逻辑视图转为物理视图 | ViewResolverComposite |
addResourceHandlers | ResourceHandlerRegistry | 静态资源处理:静态资源路径映射、缓存控制 | ResourceHandlerRegistry |
configureDefaultServletHandling | DefaultServletHandlerConfigurer | 默认 Servlet:可以覆盖 Tomcat 的DefaultServlet。让DispatcherServlet拦截/ | 无 |
configurePathMatch | PathMatchConfigurer | 路径匹配:自定义 URL 路径匹配。可以自动为所有路径加上指定前缀,比如 /api | 无 |
configureAsyncSupport | AsyncSupportConfigurer | 异步支持: | TaskExecutionAutoConfiguration |
addCorsMappings | CorsRegistry | 跨域: | 无 |
addArgumentResolvers | List | 参数解析器: | mvc 默认提供 |
addReturnValueHandlers | List | 返回值解析器: | mvc 默认提供 |
configureHandlerExceptionResolvers | List | 异常处理器: | 默认 3 个 ExceptionHandlerExceptionResolver ResponseStatusExceptionResolver DefaultHandlerExceptionResolver |
getMessageCodesResolver | 无 | 消息码解析器:国际化使用 | 无 |
@EnableWebMvc 禁用默认行为
@EnableWebMvc
给容器中导入 DelegatingWebMvcConfiguration
组件,他是 WebMvcConfigurationSupport
WebMvcAutoConfiguration
有一个核心的条件注解, @ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
,容器中没有WebMvcConfigurationSupport
,WebMvcAutoConfiguration
才生效.
@EnableWebMvc
导入 WebMvcConfigurationSupport
导致 WebMvcAutoConfiguration
失效。导致禁用了默认行为
WebMvcConfigurationSupport
这个类提供了很多默认配置并且判断了系统中是否由相应的类,如果有就启用相应的功能
SpringBoot 默认配置好了 SpringMVC 的所有常用特性。
如果我们需要全面接管SpringMVC的所有配置并禁用默认配置,仅需要编写一个WebMvcConfigurer
配置类,并标注 @EnableWebMvc
即可
全手动模式
@EnableWebMvc
: 禁用默认配置WebMvcConfigurer
组件:定义MVC的底层行为
web场景的最佳实践:
导入web的stater, 默认就会使用springboot 的 web配置,包括:
静态资源处理数据类型转换json类型的处理国际化等
使用 @Configuration
编写一个配置类继承 WebMvcAutoConfiguration
,可以自定义一些web的配置,springboot 默认的web配置也能同时生效
但是如果在配置类上加上@EnableWebMvc
就会使springboot所有的默认web配置失效,全部使用自定义配置
静态资源
WebMvcAutoConfiguration
定义了静态资源的规则
向容器中放入了两个filter:
HiddenHttpMethodFilter
规定了页面表单的rest请求(get、post、put、delete)FormContentFilter
规定了表单内容
因为在http规范里,只有get(数据放在url后)和post(数据放在请求体)请求可以携带数据,put、delete请求体的数据会被忽略FormContentFilter
使put、delete请求体也能携带数据
向容器中放入了WebMvcConfigurer
组件,提供了配置spring mvc的所有入口
所有的功能会和WebMvcProperties
和WebProperties
这两个类进行绑定WebMvcProperties
配置的前缀为:spring.mvc
WebProperties
配置前缀为:spring.web
EnableWebMvcConfiguration
向容器中放入了WebMvcConfigurationSupport
组件
如果我们向容器中放入这个组件,springboot静态资源的配置都不会生效配置了HandlerMapping
相关的配置,会根据请求路径访问对应的Handler
,包括:
欢迎页:WelcomePageHandlerMapping
会在四个静态文件夹下寻找index.html
,只要存在,项目启动访问ip端口号就会访问首页
boot会在静态资源目录下找 favicon.ico 图标
WebMvcConfigurer
中定义了静态资源的配置
访问/webjars/**
路径会去classpath:/META-INF/resources/webjars/
下找资源
访问/**
路径会去静态资源默认的四个位置,所以只要静态资源放到下面四个文件夹中就能直接访问:
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
静态资源默认都有缓存设置:如果浏览器访问了一个静态资源,并且这个资源没有发生改变,下次访问的时候就直接访问浏览器缓存,不会在向服务器发起请求
关于缓存的配置,可以通过配置文件spring.web
来配置CachePeriod:缓存的有效时间,以秒为单位,默认为0CacheControl:与HTTP有关UseLastModified:是否使用最后修改,需要配合HTTP缓存,默认关闭
为什么容器中放一个WebMvcConfigurer
就能配置底层行为
WebMvcAutoConfiguration 是一个自动配置类,它里面有一个 EnableWebMvcConfiguration
EnableWebMvcConfiguration
继承与 DelegatingWebMvcConfiguration
,这两个都生效DelegatingWebMvcConfiguration
利用 DI 把容器中 所有 WebMvcConfigurer
注入进来别人调用 DelegatingWebMvcConfiguration
的方法配置底层规则,而它调用所有 WebMvcConfigurer
的配置底层方法。
自定义静态资源
配置方式,参考对应配置类的属性
spring:
mvc:
# webjars 访问路径前缀
webjars-path-pattern: /webjars/**
# 静态资源通用的范文前缀
static-path-pattern: /**
web:
resources:
# 是否开启静态资源映射,默认就是开启
add-mappings: true
cache:
# 缓存的时间,单位秒
period: 60
cachecontrol:
# 缓存的时间,是缓存的精确配置,会覆盖上面的配置
max-age: 100
# 静态资源文件夹
static-locations: classpath:/META-INF/resources/,classpath:/resources/, classpath:/static/, classpath:/public/
代码方式
只要给容器中放入一个WebMvcConfigurer
组件即可,再通过WebMvcConfigurer
组件去设置各种配置
可以实现WebMvcConfigurer
//EnableWebMvc 注解会禁用掉springboot的默认配置
//@EnableWebMvc
//这是一个配置类
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
// 静态资源展示
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//注意文件路径最后的斜杠(文件分隔符),如果缺少了,就不能够正确的映射到相应的目录
//这里的意思是,所有带 /static 的请求,都会被路由到 file:H:/upload/
registry.addResourceHandler("/static/**").
addResourceLocations("file:H:/upload/").
//设置缓存
setCacheControl(CacheControl.maxAge(Duration.ofMillis(100)));
}
}
也可以使用@bean的方式
@Bean
public WebMvcConfigurer setWebMvcConfigurer(){
return new WebMvcConfigurer() {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").
addResourceLocations("file:H:/upload/").
//设置缓存
setCacheControl(CacheControl.maxAge(Duration.ofMillis(100)));
}
};
}
路径匹配
Ant 风格的路径模式语法具有以下规则:
*
:表示任意数量的字符。?
:表示任意一个字符。**
:表示任意数量的目录。{}
:表示一个命名的模式占位符。[]
:表示字符集合,例如[a-z]表示小写字母。
例如:
*.html
匹配任意名称,扩展名为.html
的文件。/folder1/*/*.java
匹配在folder1
目录下的任意两级目录下的.java
文件。/folder2/**/*.jsp
匹配在folder2
目录下任意目录深度的.jsp
文件。/{type}/{id}.html
匹配任意文件名为{id}.html
,在任意命名的{type}
目录下的文件。
注意:Ant 风格的路径模式语法中的特殊字符需要转义,如:
要匹配文件路径中的星号,则需要转义为\*。要匹配文件路径中的问号,则需要转义为\?。
Spring5.3 之后加入了更多的请求路径匹配的实现策略;
以前只支持 AntPathMatcher 策略, 现在提供了 PathPatternParser 策略。并且可以让我们指定到底使用那种策略。
AntPathMatcher 与 PathPatternParser
PathPatternParser 在 jmh 基准测试下,有 6~8 倍吞吐量提升,降低 30%~40%空间分配率PathPatternParser 兼容 AntPathMatcher语法,并支持更多类型的路径模式PathPatternParser “**” 多段匹配的支持仅允许在模式末尾使用sprngboot 默认使用 PathPatternParser路径匹配规则,但是如果路径中间需要有 **,需要要替换成ant风格路径
内容协商
如果想要一套系统返回多种数据格式,就需要多端内容适配
SpringBoot 多端内容适配 ,默认规则:
基于请求头内容协商(默认开启):
客户端向服务端发送请求,携带HTTP标准的Accept请求头。例如Accept: <code>application/json、text/xml
、text/yaml
服务端根据客户端请求头期望的数据类型进行动态返回
基于请求参数内容协商(需要开启):
例如发送请求 GET /projects/spring-boot?format=json
匹配到 @GetMapping(“/projects/spring-boot”)
根据参数协商,优先返回 json 类型数据【需要开启参数匹配设置】
发送请求 GET /projects/spring-boot?format=xml,优先返回 xml 类型数据
# 开启基于请求参数的内容协商功能。 默认参数名:format。 默认此功能不开启
spring.mvc.contentnegotiation.favor-parameter=true
# 指定内容协商时使用的参数名。默认是 format,可以改成自定义的值,例如 type
spring.mvc.contentnegotiation.parameter-name=format
HttpMessageConverter
@ResponseBody
注解
如果controller类上标注了@RestController
,因为@RestController
包含了@ResponseBody
,所以相当于controller所有方法的返回值标注了 @ResponseBody
注解所有请求进来,都先来到DispatcherServlet
的doDispatch()
进行处理,doDispatch()
会找到一个 HandlerAdapter
适配器,利用适配器执行目标方法RequestMappingHandlerAdapter
来执行,调用invokeHandlerMethod()
来执行目标方法目标方法执行之前,需要准备好:
HandlerMethodArgumentResolver
:参数解析器,确定目标方法每个参数值HandlerMethodReturnValueHandler
:返回值处理器,确定目标方法的返回值改怎么处理 由RequestMappingHandlerAdapter
里面的invokeAndHandle()
真正执行目标方法目标方法执行完成,会返回返回值对象得到返回值对象后,需要找到一个合适的返回值处理器: HandlerMethodReturnValueHandler
最终找到 RequestResponseBodyMethodProcessor
能处理 标注了 @ResponseBody
注解的方法RequestResponseBodyMethodProcessor
调用writeWithMessageConverters
,利用MessageConverter
把返回值写出去
所以由@ResponseBody
注解标注的方法,返回值是由MessageConverter
处理的
写出返回结果时,会遍历容器种所有的MessageConverter
,然后根据请求头中的Accept
找到适配的MessageConverter
所以如果需要输出某种格式,就需要导入对应的HttpMessageConverter
WebMvcAutoConfiguration
提供几种默认HttpMessageConverters
EnableWebMvcConfiguration
通过 addDefaultHttpMessageConverters
添加了默认的MessageConverter
;如下:
ByteArrayHttpMessageConverter
: 支持字节数据读写StringHttpMessageConverter
: 支持字符串读写ResourceHttpMessageConverter
:支持资源读写ResourceRegionHttpMessageConverter
: 支持分区资源写出AllEncompassingFormHttpMessageConverter
:支持表单xml/json读写MappingJackson2HttpMessageConverter
: 支持请求响应体Json读写
springboot默认提供的MessageConverter
功能有限,只能json和普通的返回,如果需要额外的返回类型,就需要导入其他的HttpMessageConverter
示例
适配xml:
如果想要返回 xml 数据,需要先导入依赖,然后在返回的实体上加上<code>@JacksonXmlRootElement注解:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
请求头Accept为:application/xml
就能返回xml
请求头Accept为:<code>application/json 就能返回 json
自定义返回格式
以适配yaml为例:
导入依赖:
<code><dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
编写配置
#告知系统增加了一种新的返回格式
spring.mvc.contentnegotiation.media-types.yaml=text/yaml
需要自定义一个HttpMessageConverters
/**
* 把对象写为yaml的组件,这里的泛型代表支持的格式
* AbstractHttpMessageConverter是HttpMessageConverter的默认实现
*/
@Component
public class YamlMessageConverter extends AbstractHttpMessageConverter<Object> {
//设置yaml工厂,可以把对象转为yaml
private ObjectMapper objectMapper ;
public YamlMessageConverter() {
//支持的类型,对应 spring.mvc.contentnegotiation.media-types.yaml=text/yaml 的类型
//告诉springboot这个MessageConverter支持的类型
super(new MediaType("type","yaml"));
this.objectMapper = new ObjectMapper(new YAMLFactory());;
}
/**
* 是否支持把某种类型写出
*
* @param clazz
* @return
*/
@Override
protected boolean supports(Class clazz) {
//这里可以增加条件判断,直接返回true就是只要是对象类型都支持
return true;
}
/**
* 配合 @RequestBody 注解,格式化请求参数
*
* @param clazz
* @param inputMessage
*/
@Override
protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
/**
* 配合 `@ResponseBody` 写出返回结果
*
* @param o 需要写出的对象,也就是方法的返回值
* @param outputMessage
*/
@Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
//自动关流
try (OutputStream outputStream = outputMessage.getBody()){
//写出返回结果
this.objectMapper.writeValue(outputStream,o);
}
}
}
把自定义的HttpMessageConverters
添加到容器,WebMvcConfigurer
中可以添加HttpMessageConverter
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
//配置yaml的消息转换器:HttpMessageConverter
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new YamlMessageConverter());
}
}
国际化
国际化的自动配置参照MessageSourceAutoConfiguration
实现步骤:
Spring Boot 在类路径根下查找messages资源绑定文件。文件名为:messages.properties多语言可以定义多个消息文件,命名为messages_区域代码.properties。如:
amessages.properties:默认bmessages_zh_CN.properties:中文环境cmessages_en_US.properties:英语环境 在程序中可以自动注入 MessageSource组件,获取国际化的配置项值在页面中可以使用表达式 #{}获取国际化的配置项值
@Autowired //国际化取消息用的组件
MessageSource messageSource;
@GetMapping("/haha")
public String haha(HttpServletRequest request){
Locale locale = request.getLocale();
//利用代码的方式获取国际化配置文件中指定的配置项的值
String login = messageSource.getMessage("login", null, locale);
return login;
}
错误处理机制
错误处理的自动配置都在ErrorMvcAutoConfiguration
中,两大核心机制:
SpringMVC的错误处理机制依然保留,MVC处理不了,才会交给boot进行处理SpringBoot 会自适应处理错误,响应页面或JSON数据
SpringBoot 会自适应处理错误,同样的错误,客户端和浏览器得到的数据格式是不一样的
springMvc异常处理方法:
@ExceptionHandler注解处理异常:注解的参数为能处理的异常类型,可以标识一个方法处理错误,默认只能处理这个类里发生的指定类型的错误
<code> /**
* 错误处理方法,ExceptionHandler注解的参数为能处理的异常类型
*/
@ExceptionHandler(Exception.class)
public Object error(Exception e) {
return "网络异常,请稍后再试:"+e.getMessage()+"**********";
}
@ControllerAdvice: 标注一个类,代表这个类会集中处理所有 @Controller 发生的错误
/**
* ControllerAdvice 标注一个类,代表这个类会集中处理所有 @Controller 发生的错误
*/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public void error(Exception e, HttpServletResponse response) {
log.info( "网络异常,请稍后再试:{}",e.getMessage());
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = null;
try {
writer = response.getWriter();
} catch (IOException ex) {
ex.printStackTrace();
}
writer.write("网络异常,请稍后再试:"+e.getMessage());
writer.flush();
writer.close();
}
}
如果全局和具体类都配置了异常处理,采用就近原则,以类里配置的优先
springBoot 错误处理:
如果发生错误以后,springMvc异常处理机制不生效,转发给springBoot来处理
springBoot会把错误转发到/error路径进行处理,并且在底层写好一个 BasicErrorController的组件,专门处理这个请求
既可以返回页面,也可以返回json
如果需要返回页面,需要解析出一个错误页(总结就是:先精确后模糊)
如果发生了500、404等错误
如果有模板引擎,默认会去 classpath:/templates/error/错误码.html
如果没有模板引擎,会在静态资源文件夹下找:精确码.html
如果找不到精确的错误码,会通过5xx
、4xx
模糊去找
同上,有模板引擎的,去 classpath:/templates/error/5xx.html
下找,没有的静态资源文件夹下找
如果依然找不到,会返回error视图
如果是返回json,会返回默认的JSON格式的错误信息
/**默认会读取server.error.path配置,如果每有配置就会读取默认值:error.path:/error
*/
@RequestMapping("${server.error.path:${error.path:/error}}")
配置文件
server:
error:
# 当发生错误以后,错误会转发给这个路径进行处理,所以可以自定义错误页面
path: /error
spring:
web:
resources:
#默认配置为 :classpath:/META-INF/resources/,classpath:/resources/, classpath:/static/, classpath:/public/
#如果想要访问到指定的错误页,还需要加上以下配置:
static-locations: classpath:/templates/
如果前后端不分离,需要服务端页面渲染,最佳实践:
对于不可预知的一些,HTTP码表示的服务器或客户端错误
给classpath:/templates/error/
下面,放常用精确的错误码页面。500.html
,404.html
给classpath:/templates/error/
下面,放通用模糊匹配的错误码页面。 5xx.html
,4xx.html
如果发生业务错误
核心业务,每一种错误,都应该代码控制,跳转到自己定制的错误页。通用业务,classpath:/templates/error.html
页面,显示错误信息
嵌入式容器
springboot嵌入式容器
Servlet容器:用于管理、运行Servlet组件(Servlet、Filter、Listener)的环境,一般指服务器
springboot默认嵌入了tomcat服务器,无需自己搭建服务器环境
自动配置原理
SpringBoot 默认嵌入Tomcat作为Servlet容器。自动配置类是ServletWebServerFactoryAutoConfiguration
,EmbeddedWebServerFactoryCustomizerAutoConfiguration
自动配置类开始分析功能。xxxxAutoConfiguration
ServletWebServerFactoryAutoConfiguration
自动配置了嵌入式容器场景
绑定了ServerProperties
配置类,所有和服务器有关的配置都以 server
开头ServletWebServerFactoryAutoConfiguration
导入了 嵌入式的三大服务器 Tomcat
、Jetty
、Undertow
导入 Tomcat
、Jetty
、Undertow
都有条件注解,需要系统中有对应类才行(也就是导了包)web场景默认导入了Tomcat
的包,所以 Tomcat
配置会生效,给容器中放入 TomcatServletWebServerFactory都给容器中 ServletWebServerFactory
放了一个 web服务器工厂(造web服务器的)web服务器工厂的getWebServer
方法可以获取web服务器,TomcatServletWebServerFactory 创建了 tomcat。
源代码为:
@AutoConfiguration(after = SslAutoConfiguration.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
//绑定了ServerProperties配置类
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
//导入了 嵌入式的三大服务器
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration { }
TomcatServletWebServerFactory getWebServer
创建了 tomcat。
ServletWebServerFactory 什么时候会创建 webServer出来。
ServletWebServerApplicationContext
ioc容器,启动的时候会调用创建web服务器Spring容器刷新(启动)的时候,会预留一个时机,刷新子容器。onRefresh()
refresh() 容器刷新 十二大步的刷新子容器会调用 onRefresh()
;
总结:
Web场景的Spring容器启动,在onRefresh的时候,会调用创建web服务器的方法。
Web服务器的创建是通过WebServerFactory搞定的。容器中又会根据导了什么包条件注解,启动相关的 服务器配置,默认EmbeddedTomcat
会给容器中放一个 TomcatServletWebServerFactory
,导致项目启动,自动创建出Tomcat。
用法:
修改server
下的相关配置就可以修改服务器参数通过给容器中放一个**ServletWebServerFactory**
,来禁用掉SpringBoot默认放的服务器工厂,实现自定义嵌入任意服务器。如果想切换服务器,可以在导入web场景的时候,禁用掉tomcat,导入其他服务器的包(实际意义不大)
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。