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),容器中没有WebMvcConfigurationSupportWebMvcAutoConfiguration才生效.

@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的所有入口

所有的功能会和WebMvcPropertiesWebProperties这两个类进行绑定WebMvcProperties配置的前缀为:spring.mvcWebProperties配置前缀为: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 是一个自动配置类,它里面有一个 EnableWebMvcConfigurationEnableWebMvcConfiguration继承与 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/xmltext/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 注解所有请求进来,都先来到DispatcherServletdoDispatch()进行处理,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

如果找不到精确的错误码,会通过5xx4xx 模糊去找

同上,有模板引擎的,去 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.html404.htmlclasspath:/templates/error/下面,放通用模糊匹配的错误码页面。 5xx.html4xx.html

如果发生业务错误

核心业务,每一种错误,都应该代码控制,跳转到自己定制的错误页。通用业务,classpath:/templates/error.html页面,显示错误信息

嵌入式容器

springboot嵌入式容器

Servlet容器:用于管理、运行Servlet组件(Servlet、Filter、Listener)的环境,一般指服务器

springboot默认嵌入了tomcat服务器,无需自己搭建服务器环境

自动配置原理

SpringBoot 默认嵌入Tomcat作为Servlet容器。自动配置类是ServletWebServerFactoryAutoConfigurationEmbeddedWebServerFactoryCustomizerAutoConfiguration自动配置类开始分析功能。xxxxAutoConfiguration

ServletWebServerFactoryAutoConfiguration 自动配置了嵌入式容器场景

绑定了ServerProperties配置类,所有和服务器有关的配置都以 server开头ServletWebServerFactoryAutoConfiguration 导入了 嵌入式的三大服务器 TomcatJettyUndertow

导入 TomcatJettyUndertow 都有条件注解,需要系统中有对应类才行(也就是导了包)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出来。

ServletWebServerApplicationContextioc容器,启动的时候会调用创建web服务器Spring容器刷新(启动)的时候,会预留一个时机,刷新子容器。onRefresh()refresh() 容器刷新 十二大步的刷新子容器会调用 onRefresh()

总结:

Web场景的Spring容器启动,在onRefresh的时候,会调用创建web服务器的方法。

Web服务器的创建是通过WebServerFactory搞定的。容器中又会根据导了什么包条件注解,启动相关的 服务器配置,默认EmbeddedTomcat会给容器中放一个 TomcatServletWebServerFactory,导致项目启动,自动创建出Tomcat。

用法:

修改server下的相关配置就可以修改服务器参数通过给容器中放一个**ServletWebServerFactory**,来禁用掉SpringBoot默认放的服务器工厂,实现自定义嵌入任意服务器。如果想切换服务器,可以在导入web场景的时候,禁用掉tomcat,导入其他服务器的包(实际意义不大)



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。