探究SpringBoot中的SpringMVC

摘要:spring boot就是一个大框架里面包含了许许多多的东西,其中spring就是最核心的内容之一,当然就包含spring mvc。spring mvc 是只是spring 解决web层请求的一个板块。因而他们的关系大概就是这样:spring mvc? < spring

spring boot就是一个大框架里面包含了许许多多的东西,其中spring就是最核心的内容之一,当然就包含spring mvc。spring mvc 是只是spring 解决web层请求的一个板块。因而他们的关系大概就是这样:spring mvc? < spring <springboot。

理清SpringBoot与SpringMVC的关系

Spring 框架就像一个家族,有众多衍生产品例如 boot、security、jpa等等。但他们的基础都是Spring 的 ioc和 aop ioc 提供了依赖注入的容器 aop ,处理了面向横切面的编程,而后在此两者的基础上实现了其余延伸产品的高级功能。

Spring MVC是基于 Servlet 的一个 MVC 框架 主要处理 WEB 开发的问题,由于 Spring 的配置非常复杂,各种XML、 JavaConfig、hin解决起来比较繁琐。

于是为了简化开发者的使用,从而创造性地推出了Spring boot,商定优于配置,简化了spring的配置流程。


说得更简便少量:Spring 最初利用“工厂模式”(DI)和“代理商模式”(AOP)解耦应用组件。

大家觉得挺好用,于是按照这种模式搞了一个 MVC框架(少量用Spring 解耦的组件),用开发 web 应用( SpringMVC )。

而后有发现每次开发都写很多样板代码,为了简化工作流程,于是开发出了少量“懒人整合包”(starter),这套就是 Spring Boot。

Spring MVC的功能Spring MVC提供了一种轻度耦合的方式来开发web应用。Spring MVC是Spring的一个板块,式一个web框架。

通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。处理的问题领域是网站应用程序或者者服务开发——URL路由、Session、模板引擎、静态Web资源等等。


Spring Boot的功能Spring Boot实现了自动配置,降低了项目搭建的复杂度。

众所周知Spring框架需要进行大量的配置,Spring Boot引入自动配置的概念,让项目设置变得很容易。

Spring Boot本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的处理方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。

同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即可使用(out-of-the-box),大部分的Spring Boot应用都只要要非常一些的配置代码,开发者能够更加专注于业务逻辑。Spring Boot只是承载者,辅助你简化项目搭建过程的。假如承载的是WEB项目,使用Spring MVC作为MVC框架,那么工作流程和你上面形容的是完全一样的,由于这部分工作是Spring MVC做的而不是Spring Boot。对使用者来说,换用Spring Boot以后,项目初始化方法变了,配置文件变了,另外就是不需要单独安装Tomcat这类容器服务器了,maven打出jar包直接跑起来就是个网站,但你最核心的业务逻辑实现与业务流程实现没有任何变化。

所以,用最简练的语言概括就是:

Spring 是一个“引擎”;

Spring MVC 是基于Spring的一个 MVC 框架 ;

Spring Boot 是基于Spring4的条件注册的一套快速开发整合包。


Spring MVC自动配置

Spring Boot为Spring MVC提供的auto-configuration适用于大多数应用,并在Spring默认功能上增加了以下特性:

引入ContentNegotiatingViewResolver和BeanNameViewResolver?beans。

对静态资源的支持,包括对WebJars的支持。

自动注册Converter,GenericConverter,Formatter?beans。

对HttpMessageConverters的支持。

自动注册MessageCodeResolver。

对静态index.html的支持。

对自己设置Favicon的支持。

自动使用ConfigurableWebBindingInitializer?bean。

假如保留Spring Boot MVC特性,你只要增加其余的MVC配置(阻拦器,格式化解决器,视图控制器等)。你可以增加自己的WebMvcConfigurerAdapter类型的@Configuration类,而不需要注解@EnableWebMvc。假如希望使用自己设置的RequestMappingHandlerMapping,RequestMappingHandlerAdapter,或者ExceptionHandlerExceptionResolver,你可以公告一个WebMvcRegistrationsAdapter实例提供这些组件。

假如想全面控制Spring MVC,你可以增加自己的@Configuration,并使用@EnableWebMvc注解。

HttpMessageConverters

Spring MVC使用HttpMessageConverter接口转换HTTP请求和响应,合适的默认配置可以开箱即可使用,例如对象自动转换为JSON(使用Jackson库)或者XML(假如Jackson XML扩展可用,否则使用JAXB),字符串默认使用UTF-8编码。

可以使用Spring Boot的HttpMessageConverters类增加或者自己设置转换类:

import?org.springframework.boot.autoconfigure.web.HttpMessageConverters;

import?org.springframework.context.annotation.*;

import?org.springframework.http.converter.*;

@Configuration

public?class?MyConfiguration?{

????@Bean

????public?HttpMessageConverters?customConverters()?{

????????HttpMessageConverter<?>?additional?=?...

????????HttpMessageConverter<?>?another?=?...

????????return?new?HttpMessageConverters(additional,?another);

????}

}

上下文中出现的所有HttpMessageConverter?bean都将增加到converters列表,你可以通过这种方式覆盖默认的转换器列表(converters)。

自己设置JSON序列化器和反序列化器

假如使用Jackson序列化,反序列化JSON数据,你可能想编写自己的JsonSerializer和JsonDeserializer类。自己设置序列化器(serializers)通常通过Module注册到Jackson,但Spring Boot提供了@JsonComponent注解这一替代方式,它能轻松的将序列化器注册为Spring Beans。

MessageCodesResolver

Spring MVC有一个实现策略,用于从绑定的errors产生用来渲染错误信息的错误码:MessageCodesResolver。Spring Boot会自动为你创立该实现,只需设置spring.mvc.message-codes-resolver.format属性为PREFIX_ERROR_CODE或者POSTFIX_ERROR_CODE(具体查看DefaultMessageCodesResolver.Format枚举值)。

静态内容

默认情况下,Spring Boot从classpath下的/static(/public,/resources或者/META-INF/resources)文件夹,或者从ServletContext根目录提供静态内容。这是通过Spring MVC的ResourceHttpRequestHandler实现的,你可以自己设置WebMvcConfigurerAdapter并覆写addResourceHandlers方法来改变该行为(加载静态文件)。

在单机web应用中,容器会启动默认的servlet,并用它加载ServletContext根目录下的内容以响应那些Spring不解决的请求。大多数情况下这都不会发生(除非你修改默认的MVC配置),由于Spring总能够通过DispatcherServlet解决这些请求。

你可以设置spring.resources.staticLocations属性自己设置静态资源的位置(配置一系列目录位置代替默认的值),假如你这样做,默认的欢迎页面将从自己设置位置加载,所以只需这些路径中的任何地方有一个index.html,它都会成为应用的主页。

此外,除了上述标准的静态资源位置,有个例外情况是Webjars内容。任何在/webjars/**路径下的资源都将从jar文件中提供,只需它们以Webjars的格式打包。

注?假如你的应用将被打包成jar,那就不要使用src/main/webapp文件夹。虽然该文件夹是通常的标准格式,但它仅在打包成war的情况下起作用,在打包成jar时,多数构建工具都会默认忽略它。

Spring Boot也支持Spring MVC提供的高级资源解决特性,可用于清理缓存的静态资源或者对WebJar使用版本无感知的URLs。

假如想使用针对WebJars版本无感知的URLs(version agnostic),只要要增加webjars-locator依赖,而后公告你的Webjar。以jQuery为例,"/webjars/jquery/dist/jquery.min.js"实际为"/webjars/jquery/x.y.z/dist/jquery.min.js",x.y.z为Webjar的版本。

注?假如使用JBoss,你需要公告webjars-locator-jboss-vfs依赖而不是webjars-locator,否则所有的Webjars将解析为404。

以下的配置为所有的静态资源提供一种缓存清理(cache busting)方案,实际上是将内容hash增加到URLs中,比方<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>:

spring.resources.chain.strategy.content.enabled=true

spring.resources.chain.strategy.content.paths=/**

注?实现该功能的是ResourceUrlEncodingFilter,它在模板运行期会重写资源链接,Thymeleaf,Velocity和FreeMarker会自动配置该filter,JSP需要手动配置。其余模板引擎还没自动支持,不过你可以使用ResourceUrlProvider自己设置板块宏或者帮助类。

当使用比方JavaScript板块加载器动态加载资源时,重命名文件是不行的,这也是提供其余策略并能结合使用的起因。下面是一个"fixed"策略,在URL中增加一个静态version字符串而不需要改变文件名:

spring.resources.chain.strategy.content.enabled=true

spring.resources.chain.strategy.content.paths=/**

spring.resources.chain.strategy.fixed.enabled=true

spring.resources.chain.strategy.fixed.paths=/js/lib/

spring.resources.chain.strategy.fixed.version=v12

使用以上策略,JavaScript板块加载器加载"/js/lib/"下的文件时会使用一个固定的版本策略"/v12/js/lib/mymodule.js",其余资源依旧使用内容hash的方式<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>。查看ResourceProperties获取更多支持的选项。

欢迎页面

Spring Boot支持静态和模板欢迎页面。它首先index.html在配置的静态内容位置中查找?文件。假如找不到,则会查找index模板。假如找到任何一个,它将自动用作应用程序的欢迎页面。、

自己设置Favicon

Spring Boot?favicon.ico在配置的静态内容位置和类路径的根目录(按此顺序)中查找a?。假如存在这样的文件,它会自动用作应用程序的图标。

路径匹配和内容协商

Spring MVC可以通过查看请求路径并将它匹配到应用程序中定义的映射(例如@GetMapping?Controller方法上的注释),将传入的HTTP请求映射四处理程序。

Spring Boot选择默认禁用后缀模式匹配,这意味着请求"GET /projects/spring-boot.json"不会匹配?@GetMapping("/projects/spring-boot")映射。这被认为是Spring MVC应用程序的?最佳实践。此功能在过去对于没有发送正确的“Accept”请求标头的HTTP用户端来说非常有用;?我们需要确保将正确的内容类型发送到用户端。如今,内容协商更可靠。

还有其余少量方法可以解决不一致地发送适当的“接受”请求标头的HTTP用户端。我们可以使用查询参数来确保相似的请求"GET /projects/spring-boot?format=json"?将映射到@GetMapping("/projects/spring-boot")以下内容,而不是使用后缀匹配:

spring.mvc.contentnegotiation.favor-parameter?=?true

#我们可以更改参数名称,默认为“格式”:

#spring.mvc.contentnegotiation.parameter-name?=?myparam

#我们还可以通过以下方式注册其余文件扩展名/媒体类型:

spring.mvc.contentnegotiation.media-types.markdown?=?text?/?markdown

假如您理解注意事项并依然希望应用程序使用后缀模式匹配,则需要进行以下配置:

spring.mvc.contentnegotiation.favor-path-extension?=?true

#您也可以将该功能限制为已知扩展

#spring.mvc.pathmatch.use-registered-suffix-pattern?=?true

#我们还可以通过以下方式注册其余文件扩展名/媒体类型:

#spring.mvc.contentnegotiation.media-types.adoc?=?text?/?asciidoc


ConfigurableWebBindingInitializer

Spring MVC使用WebBindingInitializer为每个特殊的请求初始化相应的WebDataBinder,假如你创立自己的ConfigurableWebBindingInitializer @Bean,Spring Boot会自动配置Spring MVC使用它。

模板引擎

正如REST web服务,你也可以使用Spring MVC提供动态HTML内容。Spring MVC支持各种各样的模板技术,包括Velocity, FreeMarker和JSPs,很多其余的模板引擎也提供它们自己的Spring MVC集成。

Spring Boot为以下的模板引擎提供自动配置支持:

FreeMarker

Groovy

Thymeleaf

Velocity(1.4已不再支持)

Mustache

注:因为在内嵌servlet容器中使用JSPs存在少量已知的限制,所以建议尽量不使用它们。

使用以上引擎中的任何一种,并采用默认配置,则板块会从src/main/resources/templates无限加载。

注:IntelliJ IDEA根据你运行应用的方式会对classpath进行不同的排序。在IDE里通过main方法运行应用,跟从Maven,或者Gradle,或者打包好的jar中运行相比会导致不同的顺序,这可能导致Spring Boot不能从classpath下成功地找到模板。假如遇到这个问题,你可以在IDE里重新对classpath进行排序,将板块的类和资源放到第一位。或者者,你可以配置板块的前缀为classpath*:/templates/,这样会查找classpath下的所有模板目录。

错误解决

Spring Boot默认提供一个/error映射用来以合适的方式解决所有的错误,并将它注册为servlet容器中全局的 错误页面。对于机器用户端(相对于浏览器而言,浏览器偏重于人的行为),它会产生一个具备详细错误,HTTP状态,异常信息的JSON响应。对于浏览器用户端,它会产生一个白色标签样式(whitelabel)的错误视图,该视图将以HTML格式显示同样的数据(可以增加一个解析为'error'的View来自己设置它)。为了完全替换默认的行为,你可以实现ErrorController,并注册一个该类型的bean定义,或者简单地增加一个ErrorAttributes类型的bean以使用现存的机制,只是替换显示的内容。

注BasicErrorController可以作为自己设置ErrorController的基类,假如你想增加对新context type的解决(默认解决text/html),这会很有帮助。你只要要继承BasicErrorController,增加一个public方法,并注解带有produces属性的@RequestMapping,而后创立该新类型的bean。

你也可以定义一个@ControllerAdvice去自己设置某个特殊controller或者exception类型的JSON文档:

@ControllerAdvice(basePackageClasses?=?FooController.class)

public?class?FooControllerAdvice?extends?ResponseEntityExceptionHandler?{

????@ExceptionHandler(YourException.class)

????@ResponseBody

????ResponseEntity<?>?handleControllerException(HttpServletRequest?request,?Throwable?ex)?{

????????HttpStatus?status?=?getStatus(request);

????????return?new?ResponseEntity<>(new?CustomErrorType(status.value(),?ex.getMessage()),?status);

????}

????private?HttpStatus?getStatus(HttpServletRequest?request)?{

????????Integer?statusCode?=?(Integer)?request.getAttribute("javax.servlet.error.status_code");

????????if?(statusCode?==?null)?{

????????????return?HttpStatus.INTERNAL_SERVER_ERROR;

????????}

????????return?HttpStatus.valueOf(statusCode);

????}

}

在以上示例中,假如跟FooController相同package的某个controller抛出YourException,一个CustomerErrorType类型的POJO的json展现将代替ErrorAttributes展现。

自己设置错误页面

假如想为某个给定的状态码展现一个自己设置的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.ftl

?????????????+-?<other?templates>

对于更复杂的映射,你可以增加实现ErrorViewResolver接口的beans:

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

????????return?...

????}

}

你也可以使用Spring MVC特性,比方@ExceptionHandler方法和@ControllerAdvice,ErrorController将解决所有未解决的异常。

映射Spring MVC以外的错误页面

对于不使用Spring MVC的应用,你可以通过ErrorPageRegistrar接口直接注册ErrorPages。该笼统直接工作于底层内嵌servlet容器,即便你没有Spring MVC的DispatcherServlet,它们依旧可以工作。

@Bean

public?ErrorPageRegistrar?errorPageRegistrar(){

????return?new?MyErrorPageRegistrar();

}

//?...

private?static?class?MyErrorPageRegistrar?implements?ErrorPageRegistrar?{

????@Override

????public?void?registerErrorPages(ErrorPageRegistry?registry)?{

????????registry.addErrorPages(new?ErrorPage(HttpStatus.BAD_REQUEST,?"/400"));

????}

}

注.假如你注册一个ErrorPage,该页面需要被一个Filter解决(在少量非Spring web框架中很常见,比方Jersey,Wicket),那么该Filter需要明确注册为一个ERROR分发器(dispatcher),例如:

@Bean

public?FilterRegistrationBean?myFilter()?{

????FilterRegistrationBean?registration?=?new?FilterRegistrationBean();

????registration.setFilter(new?MyFilter());

????...

????registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));

????return?registration;

}

(默认的FilterRegistrationBean不包含ERROR?dispatcher类型)。

WebSphere应用服务器的错误解决

当部署到一个servlet容器时,Spring Boot通过它的错误页面过滤器将带有错误状态的请求转发到恰当的错误页面。request只有在response还没提交时才能转发(forwarded)到正确的错误页面,而WebSphere应用服务器8.0及后续版本默认情况会在servlet方法成功执行后提交response,你需要设置com.ibm.ws.webcontainer.invokeFlushAfterService属性为false来关闭该行为。

Spring HATEOAS

假如正在开发基于超媒体的RESTful API,你可能需要Spring HATEOAS,而Spring Boot会为其提供自动配置,这在大多数应用中都运作良好。 自动配置取代了@EnableHypermediaSupport,只要注册肯定数量的beans就能轻松构建基于超媒体的应用,这些beans包括LinkDiscoverers(用户端支持),ObjectMapper(用于将响应编排为想要的形式)。ObjectMapper可以根据spring.jackson.*属性或者Jackson2ObjectMapperBuilder?bean进行自己设置。

通过注解@EnableHypermediaSupport,你可以控制Spring HATEOAS的配置,但这会禁用上述ObjectMapper的自己设置功能。

CORS支持

跨域资源共享(CORS)是一个大多数浏览器都实现了的W3C标准,它允许你以灵活的方式指定跨域请求如何被受权,而不是采用那些不安全,性能低的方式,比方IFRAME或者JSONP。

从4.2版本开始,Spring MVC对CORS提供开箱即可使用的支持。不用增加任何特殊配置,只要要在Spring Boot应用的controller方法上注解@CrossOrigin,并增加CORS配置。通过注册一个自己设置addCorsMappings(CorsRegistry)方法的WebMvcConfigurer?bean可以指定全局CORS配置:

@Configuration

public?class?MyConfiguration?{

????@Bean

????public?WebMvcConfigurer?corsConfigurer()?{

????????return?new?WebMvcConfigurerAdapter()?{

????????????@Override

????????????public?void?addCorsMappings(CorsRegistry?registry)?{

????????????????registry.addMapping("/api/**");

????????????}

????????};

????}

}

相关视频链接:https://pan.baidu.com/s/13pyAIZFjLNfIimU359BxqQ

  • 全部评论(0)
最新发布的资讯信息
【系统环境|服务器应用】Discuz发布帖子时默认显示第一个主题分类的修改方法(2019-12-09 00:13)
【系统环境|软件环境】Android | App内存优化 之 内存泄漏 要点概述 以及 处理实战(2019-12-04 14:27)
【系统环境|软件环境】MySQL InnoDB 事务(2019-12-04 14:26)
【系统环境|软件环境】vue-router(单页面应用控制中心)常见用法(2019-12-04 14:26)
【系统环境|软件环境】Linux中的Kill命令(2019-12-04 14:26)
【系统环境|软件环境】Linux 入门时必学60个文件解决命令(2019-12-04 14:26)
【系统环境|软件环境】更新版ThreeJS 3D粒子波浪动画(2019-12-04 14:26)
【系统环境|软件环境】前台开发WebStorm常用快捷键,火速收藏!(2019-12-04 14:25)
【系统环境|软件环境】微博H5登录和发微博组件(2019-12-04 14:25)
【系统环境|软件环境】5分钟谈前台面试,小伙伴都惊呆了(2019-12-04 14:23)