关键词:
3.19
目录
1.Springboot开发步骤
2.Springboot对静态资源的映射规则
3.模板引擎
引入Thymeleaf
Thymeleaf使用和语法
4.SpringMVC自动配置原理
5.修改Springboot的默认配置
6.全面接管SpringMvc
1.步骤:
1.创建springboot应用,选中需要的模块
2.springboot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来
3.编写业务代码
2.springboot对静态资源的映射规则:
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); } else { Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl(); if (!registry.hasMappingForPattern("/webjars/**")) { this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl)); } String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl)); } } }
所有/webjars/**,都去classpath:/META-INF/resources/webjars/找资源
webjars:以jar包的方式引入静态资源 https://www.webjars.org/
<!--引入jquery-webjar--> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.3.1</version> </dependency> <!--引入bootstrap--> <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>4.1.2</version> </dependency>
1)http://localhost:8084/webjars/jquery/3.3.1/jquery.js 能访问到引入的文档
在访问的时候只需要写webjars下面资源的名称即可
String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl)); }
2)/** 访问当前项目的任何资源
静态资源文件夹:
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"
"/":当前项目的根目录
为什么默认是这四个路径呢?可以看下面的源码。
/Users/mac/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.0.0.RELEASE/spring-boot-autoconfigure-2.0.0.RELEASE.jar!/org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.class
this.staticPathPattern = "/**";
private static final String[] SERVLET_LOCATIONS = new String[]{"/"};
/Users/mac/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.0.0.RELEASE/spring-boot-autoconfigure-2.0.0.RELEASE.jar!/org/springframework/boot/autoconfigure/web/ResourceProperties.class
private static final String[] CLASSPATH_RESOURCE_LOCATIONS =
new String[]{"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"};
3)首页 静态资源下的所有index.html页面,被"/**"映射,localhost:8084/ 找index页面
4)配置喜欢的图标 也是在静态文件夹里找
源码:
@Bean public SimpleUrlHandlerMapping faviconHandlerMapping() { SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); mapping.setOrder(-2147483647); mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", this.faviconRequestHandler())); return mapping; }
修改成功!
5)修改默认静态资源路径 application.properties
#多个路径可以用,隔离开路径 spring.resources.static-locations=classpath:/hello/,classpath:/public/
3.模板引擎
JSP、Velocity、Freemarker、Thymeleaf
springboot推荐的Thymeleaf:语法更简单,功能更强大
1.引入thymeleaf
2.0.0版本springboot默认导入的是3.0.9版本的thymeleaf
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
2.thymeleaf使用和语法
@ConfigurationProperties( prefix = "spring.thymeleaf" ) public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING; public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html"; private boolean checkTemplate = true; private boolean checkTemplateLocation = true; private String prefix = "classpath:/templates/"; private String suffix = ".html"; private String mode = "HTML";
把HTML页面放在classpath:/templates/,thymeleaf就能自动渲染
thymeleaf语法官方文档:
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.pdf
使用:
1)导入thymeleaf的名称空间
<html lang="en" xmlns:th="http://www.thymeleaf.org">
2)表达式
--------------------------
success.xml
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--th:text将div里面的文本内容替换 th:任意HTML属性,来替换原生属性的值 --> <div th:text="${hello}"></div> <div th:utext="${hello}"></div> <!--th:each每次遍历都会生成当前这个标签 3个h4--> <h4 th:text="${user}" th:each="user:${users}"></h4> <h4> <!--3个span--> <span th:each="user:${users}">[[${user}]]</span> </h4> </body> </html>
helloController.java
package com.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import java.lang.reflect.Array; import java.util.Arrays; import java.util.Map; /* @RestContronller=@Controller+@ResponseBody */ @Controller public class helloContronller { @RequestMapping("/success") public String success(Map<String,Object>map){ map.put("hello","<h1>123888910<h1>"); map.put("users", Arrays.asList("zhangsan","lalala")); return "success"; } }
实验结果:
4.springMVC自动配置原理
官方文档:
1.
Inclusion of ContentNegotiatingViewResolver
and BeanNameViewResolver
beans.
自动配置视图了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染)
ContentNegotiatingViewResolver 组合所有的视图解析器
@Bean @ConditionalOnBean({ViewResolver.class}) @ConditionalOnMissingBean( name = {"viewResolver"}, value = {ContentNegotiatingViewResolver.class} ) public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) { ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver(); resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class)); resolver.setOrder(-2147483648); return resolver; }
可以看到ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
进入ContentNegotiatingViewResolver类 找到其中的resolveViewName方法,看如何解析视图。
@Nullable public View resolveViewName(String viewName, Locale locale) throws Exception { RequestAttributes attrs = RequestContextHolder.getRequestAttributes(); Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes"); List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest()); if (requestedMediaTypes != null) { List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes); View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs); if (bestView != null) { return bestView; ··· ···
视图通过getCandidateViews方法获取,进入该方法
发现该方法获取viewResolvers视图解析器并遍历
private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception { List<View> candidateViews = new ArrayList(); if (this.viewResolvers != null) { Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set"); Iterator var5 = this.viewResolvers.iterator(); while(var5.hasNext()) { ViewResolver viewResolver = (ViewResolver)var5.next(); View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { candidateViews.add(view); } ··· ···
那么视图解析器viewResolvers是怎么得到的呢?通过BeanFactory工具从容器中获取所有视图解析器。
protected void initServletContext(ServletContext servletContext) { Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values(); ViewResolver viewResolver; if (this.viewResolvers == null) { this.viewResolvers = new ArrayList(matchingBeans.size()); Iterator var3 = matchingBeans.iterator(); ··· ···
也就是说:
BeanFactory工具从容器中获取所有视图解析器viewResolvers
->getCandidateViews方法获取viewResolvers并遍历,返回值是List<View>列表
->在ContentNegotiatingViewResolver类中,resolveViewName方法使用getCandidateViews方法解析视图,返回值是View
->在ContentNegotiatingViewResolver类中,创建该类对象
所以,ContentNegotiatingViewResolver 组合了所有的视图解析器。
如何定制视图解析器:可以给容器中添加一个视图解析器,自动将其组合进来。通过测试验证正确性:
DemoApplication.java
package com; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.servlet.View; import org.springframework.web.servlet.ViewResolver; import java.util.Locale; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } //将自己的视图解析器增加到容器中 @Bean public ViewResolver myViewResolver(){ return new MyViewResolver(); } //视图解析器实现ViewResolver接口 private static class MyViewResolver implements ViewResolver{ @Override public View resolveViewName(String s, Locale locale) throws Exception { return null; } } }
在DispatcherServlet.class的doDispatch方法处打上断点,debug
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
可以看到在容器中已经将自定义ViewResolver的组件添加进来了(蓝色行)
Support for serving static resources, including support for WebJars (covered later in this document)).静态资源文件夹路径webjars
Automatic registration of Converter
, GenericConverter
, and Formatter
beans.
Converter
: 转化器 类型转换
GenericConverter
Formatter:
格式化器
自己也可以添加格式化器转换器,只需放在容器中
Support for HttpMessageConverters
(covered later in this document).
HttpMessageConverters:springboot用来转换Http请求和响应的,从容器中确定,获取所有的
HttpMessageConverter 可以自己配置,添加到容器
Automatic registration of MessageCodesResolver
(covered later in this document). 定义错误代码生成规则 可以自己配置,添加到容器
Static index.html
support. 静态资源首页
Custom Favicon
support (covered later in this document). 图标设置 可以自己配置,添加到容器
Automatic use of a ConfigurableWebBindingInitializer
bean (covered later in this document). 初始化ConfigurableWebBinder把请求数据绑定到JavaBean中
可以自己配置,添加到容器
更多容器中的组件具体可以看:org.springframework.boot.autoconfigure.web.servlet 里的xxxConfiguration类:web的所有自动配置场景。
5.修改springboot的默认配置
模式:
扩展springmvc
springmvc.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd"> <mvc:view-controller path="/hello" view-name="success"/> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/hello"/> <bean></bean> </mvc:interceptor> </mvc:interceptors> </beans>
原来在springmvc中可以如上配置(拦截hello请求),那么在springboot中不写xml配置文件怎么实现呢?
有两种方法:
" '' ''
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration
class of type WebMvcConfigurer
but without @EnableWebMvc
. If you wish to provide custom instances of RequestMappingHandlerMapping
, RequestMappingHandlerAdapter
, or ExceptionHandlerExceptionResolver
, you can declare a WebMvcRegistrationsAdapter
instance to provide such components.
If you want to take complete control of Spring MVC, you can add your own @Configuration
annotated with @EnableWebMvc
.'' '' ''
方法1:直接继承WebMvcConfigurationSupport
并添加@Configuration
注解
编写一个配置类(@Configuration)继承父类重写方法,不能标注@EnableWebMvc注解(springmvc的自动配置和我们的扩展配置都会生效,如果加上@EnableWebMvc则springmvc的自动配置全部失效-具体原因参见源码)。
package com.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; @Configuration public class MyMvcConfig extends WebMvcConfigurationSupport { @Override protected void addViewControllers(ViewControllerRegistry registry) { //super.addViewControllers(registry); //浏览器发送/s请求,也来到success页面 registry.addViewController("/s").setViewName("success"); } }
方法2:直接在配置类上添加@EnableWebMvc
并实现WebMvcConfigurer
接口
会导致静态资源失效,需重写方法如下:
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**") .addResourceLocations("classpath:/resources/") .addResourceLocations("classpath:/static/") .addResourceLocations("classpath:/public/"); super.addResourceHandlers(registry); }
6.全面接管SpringMvc(开发中不推荐)
springboot对springmvc的自动配置不需要了,所有都是自己配置。所有的springmvc的自动配置都失效了。
需要在配置类中添加@EnableWebMvc注解。
@EnableWebMvc @Configuration public class MyMvcConfig extends WebMvcConfigurationSupport { @Override protected void addViewControllers(ViewControllerRegistry registry) {
原理:
进入@EnableWebMvc
@Import({DelegatingWebMvcConfiguration.class}) public @interface EnableWebMvc {
进入DelegatingWebMvcConfiguration.class
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
在自动配置类WebMvcConfiguration.class可以看到:
@Configuration @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class}) //容器中缺少 WebMvcConfigurationSupport类型的bean时,自动配置类才会生效 @ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) @AutoConfigureOrder(-2147483638) @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class}) public class WebMvcAutoConfiguration { public static final String DEFAULT_PREFIX = ""; public static final String DEFAULT_SUFFIX = "";
也就是说:@EnableWebMvc将DelegatingWebMvcConfiguration类中对应的组件都导入到容器中,而这个类是继承WebMvcConfigurationSupport类的,所以将父类中的组件也会导入容器。在自动配置类中可以看到,只有容器中没有WebMvcConfigurationSupport类中组件,这个自动配置类才会生效。而此时容器中已经有了WebMvcConfigurationSupport类中组件,所以自动配置类不会再生效了。
炼金术:区分前端开发/客户端开发/后端开发/核心开发
前端开发,指只做过HTML、CSS、JavaScript以及具备使用在此基础上构建的各种Web类型的UI框架开发的能力,例如React、Vue、Elm等Web框架,同时对NodeJS生态下的Gulp、Webpack等打包工具链、有所熟悉。前端开发人员还需要对PC端网页渲染... 查看详情
原生开发h5开发混合移动开发的优缺点
一、原生开发(NativeApp开发)原生开发,是在Android、IOS等移动平台上利用官方提供的开发语言、开发类库、开发工具进行App开发。比如Android是利用Java、Eclipse、AndroidStudio;IOS是利用Objective-C和Xcode进行开发。通俗点来讲,原生开... 查看详情
软件开发模式之敏捷开发(scrum)
简介这几年关于敏捷开发在互联网企业中越来越广泛被使用到,运用的比较多的当属scrum敏捷开发和xp敏捷开发,人人都在谈论敏捷开发。那什么才是敏捷开发呢?目录什么是敏捷开发?传统的开发模式和敏捷开发模式的对比?... 查看详情
敏捷开发与传统开发
本文主要介绍和讨论什么是敏捷开发和传统软件开发,分析这两个软件开发方法的特点并作出对比。首先介绍什么是传统软件开发。 传统开发传统软件开发主要指的是传统软件开发的模型。传统的软件开发模型包括瀑布... 查看详情
敏捷软件开发vs传统软件开发
敏捷软件开发VS传统软件开发软件开发方法是软件工程理论的重要内容,在软件开发方法中,对于开发软件时的“做什么”和”如何做“,给出了明确的、详细的回答。那软件开发方法的”做什么”和”如何做”之间究竟有什么... 查看详情
watchos开发教程之六:表盘功能开发(代码片段)
WatchOS开发教程系列文章:WatchOS开发教程之一:WatchApp架构及生命周期WatchOS开发教程之二:布局适配和系统Icon设计尺寸WatchOS开发教程之三:导航方式和控件详解WatchOS开发教程之四:Watch与iPhone的通信和数据共享WatchOS开发教程之五:通知... 查看详情
qt开发(二十三)——软件开发流程
QT开发(二十三)——软件开发流程一、软件开发流程简介软件开发流程是通过一系列步骤保证软件产品的顺利完成,是软件产品在生命周期内的管理学。软件开发流程的本质是软件开发流程与具体技术无关,是开发团队必须遵... 查看详情
炼金术:区分前端开发/客户端开发/后端开发/核心开发
前端开发,指只做过HTML、CSS、JavaScript以及具备使用在此基础上构建的各种Web类型的UI框架开发的能力,例如React、Vue、Elm等Web框架,同时对NodeJS生态下的Gulp、Webpack等打包工具链、有所熟悉。前端开发人员还需要对PC... 查看详情
开发平台用来开发软件真的能降低开发成本?
开发时间方面也能减少吗?可以的,开发平台可以大幅缩短开发周期、降低开发成本、提高开发质量,让管理系统可伴随业务变革不断进化升级。下面盘点一些市面上主流的开发平台厂商,企业在选型过程中可以根据需求去评估... 查看详情
开发趋势:快速开发平台知多少?
开发趋势:快速开发平台知多少? 一、什么是快速开发平台 简而言之,就是可以使得开发更为快速的平台。当开发平台产生之后,虽然减少了编程人员大量的编程时间,但是很多开发平台的效果并不是很理想,比... 查看详情
watchos开发教程之五:通知功能开发(代码片段)
WatchOS开发教程系列文章:WatchOS开发教程之一:WatchApp架构及生命周期WatchOS开发教程之二:布局适配和系统Icon设计尺寸WatchOS开发教程之三:导航方式和控件详解WatchOS开发教程之四:Watch与iPhone的通信和数据共享WatchOS开发教程之五:通知... 查看详情
敏捷开发感想
敏捷开发(Agile Development)是一种以人为核心、迭代、循序渐进的开发方法。敏捷开发是针对传统的瀑布开发模式的弊端而产生的一种新的开发模式,目标是提高开发效率和响应能力。除了原则和实践,模式也是很重要的,... 查看详情
招募英雄-招募前端开发/java开发/区块链开发工程师
大量招聘前端开发/Java开发/区块链开发工程师,详情见大图,简历速速砸来哦。可以发送简历到图中的邮箱。 查看详情
敏捷开发入门教程-----摘抄
敏捷开发入门教程 作者: 阮一峰日期: 2019年3月6日感谢 腾讯课堂NEXT学院 赞助本站,官方小程序课程 正在招生。敏捷开发(agiledevelopment)是非常流行的软件开发方法。据统计,2018年90%的软件开发采用敏... 查看详情
完整的整车开发流程
完整的整车开发流程 完整的整车开发流程资料 整车开发流程 整车开发流程大众开发流程介绍 (奇瑞)整车开发流程 整车设计开发流程 最详细的整车开发流程 查看详情
敏捷开发
敏捷开发是一种应对快速变化的需求的一种软件开发能力。敏捷开发的原则:1.以最有效率的方式交付使客户满意的软件。2.在开发期间开发人员与业务人员必须天天在一起。3.在开发团队中要以面对面方式交流。4.每隔一段时间... 查看详情
mis系统的开发具备的条件
MIS的开发方式有自行开发、委托开发、联合开发、购买现成软件包进行二次开发几种形式。一般来说根据企业的技术力量、资源及外部环境而定。补充:管理信息系统的开发策略不可行的开发方法:组织结构法,机械的按照现有... 查看详情
力软敏捷开发框架-轻量化app一键快速开发
APP怎么快速开发?2018年,力软敏捷开发框架的APP在线制作平台已经逐步成熟。你不需要任何的编程技术,自己就可以通过力软敏捷开发框架上面的APP应用,拼图式自己快速搭建出一个手机互联网APP。 在整体框架都已经... 查看详情