[笔记迁移][Spring Boot]SpringMVC Web开发[4]

1. 使用Spring Boot(三步走)

  1. 用Spring Initializer创建Spring Boot应用,选中需要的模块
  2. Spring Boot默认将这些场景自动配置(xxxAutoConfiguration注入组件+xxxProperties封装配置),只需要在主配置文件中指定少量配置就可以运行
  3. 编写业务逻辑代码

2. RESTful-CRUD实例

2.1 准备
2.1.1 使用Spring Initializer快速创建自带web模块的Spring Boot项目
2.1.2 Spring Boot对静态资源的映射规则
//用来设置和静态资源有关的参数,如缓存时间等
@ConfigurationProperties(prefix = "spring.resources",ignoreUnknownFields = false)
public class ResourceProperties implements ResourceLoaderAware, InitializingBean
//org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration

//静态资源处理器
public void addResourceHandlers(ResourceHandlerRegistry registry) {
   
            if (!this.resourceProperties.isAddMappings()) {
   
                logger.debug("Default resource handling disabled");
            } else {
   
                Integer cachePeriod = this.resourceProperties.getCachePeriod();
                //规则一:localhost:8080/webjars/jquery/3.2.1/jquery.js
                if (!registry.hasMappingForPattern("/webjars/**")) {
   
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{
   "/webjars/**"}).addResourceLocations(new String[]{
   "classpath:/META-INF/resources/webjars/"}).setCachePeriod(cachePeriod));
                }
				//规则二:去ResourceProperties里配置拿staticLocation,这是一个常量数组RESOURCE_LOCATIONS={"/","classpath:/META-INF/resources","classpath:/resources/","classpath:/static/","classpathL/public/"},这些位置就是存放静态资源的位置	
                String staticPathPattern = this.mvcProperties.getStaticPathPattern(); 
                if (!registry.hasMappingForPattern(staticPathPattern)) {
   
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{
   staticPathPattern}).addResourceLocations(this.resourceProperties.getStaticLocations()).setCachePeriod(cachePeriod)); //staicLocation->ResourceProperty#RESOURCE_LOCATIONS,是一个常量数组
                }

            }
        }

  1. 规则一:所有匹配/webjars/**的资源请求都去 classpath:/META-INF/resources/webjars/ 找资源。
    【webjars】:以jar包的方式引入静态资源:https://www.webjars.org/ ,可以查询到所需资源的对应版本并将dependency引入pom.xml,如jquery。

    <dependency>
    	<groupId>org.webjars</groupId>
    	<artifactId>jquery</artifactId>
    	<version>3.2.1</version>
    </dependency>
    

    导入后的jar包目录结构JQueryWebjars
    只需要写wejars下面的资源路径即可,访问路径举例:localhost:8080/webjars/jquery/3.2.1/jquery.js

  2. /** 访问当前项目的任何资源,如果没有处理,将从以下静态资源文件夹中查找
    classpath:/META-INF/resources/
    classpath:/resources/
    classpath:/static/
    classpath:/public/
    / (即当前项目的根路径)
    注意,上面的静态资源文件夹的名字不在访问路径中出现,访问路径举例:localhost:8080/assets/js/Chart.min.js

//配置欢迎页映射
@Bean
public WebMvcAutoConfiguration.WelcomePageHandlerMapping welcomePageHandlerMapping(ResourceProperties resourceProperties) {
   
			//底层调用返回的是,第一个“存在的index.html”的Resource对象,与getStaticPathPattern()返回的/**映射
            return new WebMvcAutoConfiguration.WelcomePageHandlerMapping(resourceProperties.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
}
/*底层的核心调用
private String[] getStaticWelcomePageLocations() {
   
        String[] result = new String[this.staticLocations.length];

        for(int i = 0; i < result.length; ++i) {
   
            String location = this.staticLocations[i];
            if (!location.endsWith("/")) {
   
                location = location + "/";
            }
			//将静态资源文件夹的路径都拼接上index.html,返回{/index.html,classpath:/META-INF/resource/index.html,classpath:/resource/index.html,classpath:/static/index.html,classpath:/public/index.html}
            result[i] = location + "index.html";
        }
*/
  1. 欢迎页:静态资源文件夹下的所有index.html页面;被/**映射。 访问路径举例:localhost:8080/ => index.html
//配置图标
@Configuration
@ConditionalOnProperty(value = {
   "spring.mvc.favicon.enabled"},matchIfMissing = true)
public static class FaviconConfiguration {
   
    private final ResourceProperties resourceProperties;

    public FaviconConfiguration(ResourceProperties resourceProperties) {
   
       this.resourceProperties = resourceProperties;
}
  
@Bean
public SimpleUrlHandlerMapping faviconHandlerMapping() {
   
      SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
      mapping.setOrder(-2147483647);
  	  //将所有**/favicon.ico映射给faviconRequestHandler,底层核心调用resourceProperties.getFaviconLocations()中,还是拿静态资源文件夹的路径来取得图标路径
      mapping.setUrlMap(Collections.singletonMap("**/favicon.ico",
                                             this.faviconRequestHandler()));
       return mapping;
}
/*底层核心调用
  List<Resource> getFaviconLocations() {
        List<Resource> locations = new ArrayList(this.staticLocations.length + 1);
        if (this.resourceLoader != null) {
            String[] var2 = this.staticLocations;
            int var3 = var2.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                String location = var2[var4];
                locations.add(this.resourceLoader.getResource(location));
            }
        }
*/
  1. 所有的**/favicon.ico都是在静态资源文件夹下找
  2. 通过在主配置文件中修改spring.resources.static-locations(就是前面源码中ResourcePropeties一直在用的staticLocations)自定义静态资源文件夹(配置之后,之前默认的静态资源文件夹路径都不可用),可以定义多个,因为上面看到了它本身是一个数组(用逗号分隔)。
2.2 Spring Boot默认不支持JSP => 推荐模板引擎(ViewResolver)Thymeleaf
2.2.1 引入Thymeleaf-starter
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!--默认引用2.1.6,过低,需要切换3.x。在当前工程pom.xml抽取的<properties>中加入如下配置来覆盖父依赖-->
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<!--布局功能的支持程序,thymeleaf3主程序,layout2以上版本-->
<thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
2.2.2 使用
  1. 只要把html页面置于classpath:/templates/中,thymeleaf便能自动渲染。
  2. 在h5页面的<html>中导入thymeleaf的命名空间以获取语法提示。
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    
  3. Thymeleaf配置封装ThymeleafProperties
    @ConfigurationProperties(
        prefix = "spring.thymeleaf"
    )
    public class ThymeleafProperties {
         
        private static final Charset DEFAULT_ENCODING = Charset.forName("UTF-8");
        private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
      
      	//只要把HTML页面置于classpath:/templates/中,thymeleaf便能自动渲染
        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 = "HTML5";
        private Charset encoding;
        private MimeType contentType;
        private boolean cache;
        private Integer templateResolverOrder;
        private String[] viewNames;
        private String[] excludedViewNames;
        private boolean enabled;
    }
    
2.2.3 语法(详见Thymeleaf官网pdf)
  1. th:text 替换当前元素内的文本内容
    ==推广至==>“th:任意属性” 可以对html原生对应属性进行替换(只有经过模板引擎渲染的访问才会发生属性替换,直接访问单纯的静态 html不会替换)。

  2. 属性解析的优先级ThymeGrammar

  3. 表达式

    Simple Expression 简单表达式
    Variable Expression 变量表达式 ${} 底层是OGNL表达式,OGNL功能

    内置Basic Object:
      #ctx: the context object
      #vars: the context variables
      #locale: the context locale
      #request: HttpServletRequest
      #response: HttpServeltResponse
      #session: HttpSession
      #servletContext: ServletContext

    内置工具对象:
      #execInfo: information about the template being processed.
      #message: methods for obtaining externalized messages inside variables expression, in the same way as they would be obtained using #{…}
      #uris: methods for escaping parts of URLs/URIs
      #conversions: methods for executingthe configured conversion service(if any)
      #dates: methods for java.util.Date objects: formatting, component extraction…
      #calendars: analogous to #date, but for java.util.Calendar objects
      #numbers: methods for formatting numeric objects
      #strings: methods for String objects: contains, startWith, prepending/appending…
      #objects: methods for objects in general
      #bools: method for boolean evaluation
      #arrays: method for arrays
      #lists
      #sets
      #maps
      #aggregates: methods for creating aggregates on array of collection
      #ids: methods for dealing with id attributes that might be repeated
    Selecting Variable Expression 选择表达式 基本功能和${}一样,但补充了功能:配合th:object进行使用,在外层div属性th:object指定对象后,可以直接在内部元素直接使用*{字段名}取到其内部属性值
    Message Expression 国际化表达式 #{},获取国际化内容
    Link URL Expression @{},定义URL,th:href
    @{/order/process(execId=${execId},execType=‘FAST’)},execId和execType是传递的两个参数,用逗号隔开,可以套用${}动态取参数
    Fragment Expression 文档片段表达式 ~{…}

    字面量表达式,数学表达式,布尔表达式,运算符表达式、条件运算等与OGNL一致
    【Special tokes 特殊表达式(表示无操作,如在三元运算中):_】

  4. 常见场景实例

	<body>
   	success!
   	<!-- th:text 将div内的文本内容设置为指定值-->
   	<div th:text="${hello}"></div>
   	<div th:utext="${hello}"></div>
   	<hr/>
   	<!--与增强foreach相似的遍历th:each, 每次遍历都会生成当前标签-->
   	<h4 th:text="${user}" th:each="user:${users}"></h4>
   	<hr>
   	<h4>
   	  	<!--[[]]与th:text等价,[()]与th:utext等价 -->
   	    <span th:each="user:${users}">[[${user}]]</span>
   	</h4>
   	</body>
2.3 底层 SpringMVC 自动配置WebMvcAutoConfiguration

Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
The auto-configuration adds the following features on top of Spring’s defaults:

  • Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
    (自动配置视图解析器ViewResolver。ContentNegotiatingViewResolver将获取容器中所有的ViewResolver。=>只要在配置类中向容器注入ViewResolver的实现类对象,就可以被ContentNegotiatingViewResolver自动组合进来。)

  • Support for serving static resources, including support for WebJars (see below).
  • Static index.html support.
  • Custom Favicon support (see below).
    (对webjars、静态资源文件夹、首页、图标等支持)

  • Automatic registration of Converter, GenericConverter, Formatter beans.
    (自动配置了映射绑定时的类型转换Converter和数据格式化Formatter=>只要在配置类中向容器注入Converter或Formatter的实现类对象,就可以添加自定义转换器)

  • Support for HttpMessageConverters (see below).
    (自动配置对JSON和POJO的转换器=>只要在配置类中注入HttpMessageConverter,就可以添加自定义HttpMessageConverter)

  • Automatic registration of MessageCodesResolver (see below).
    定义错误代码生成规则,如JSR303数据校验

  • Automatic use of a ConfigurableWebBindingInitializer bean (see below).
    (自动配置ConfigurableWebBindingInitializer用来初始化WebDataBinder=>只要在配置类中注入ConfigurableWebBindingInitializer,就可以自定义WebDataBinder来替换默认的)
  1. 自动配置视图解析器ViewResolver
    //WebMVCAutoConfiguration.java
    //1.1 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.java
    //1.1.1 ContentNegotiatingViewResolver的核心方法:解析最佳视图实现
     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) {
         
            	//获取候选的View对象
                List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
                 /*	底层getCadidateViews()的核心代码
                    private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes) throws Exception {
        				List<View> candidateViews = new ArrayList();
        				Iterator var5 = this.viewResolvers.iterator();
    					//遍历所有的ViewResolver进行解析
    			        while(var5.hasNext()) {
    			            ViewResolver viewResolver = (ViewResolver)var5.next();
    			            View view = viewResolver.resolveViewName(viewName, locale);
    			            if (view != null) {
    			                candidateViews.add(view);
    			            }
    			
    			            Iterator var8 = requestedMediaTypes.iterator();
    			
    			            while(var8.hasNext()) {
    			                MediaType requestedMediaType = (MediaType)var8.next();
    			                List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
    			                Iterator var11 = extensions.iterator();
    			
    			                while(var11.hasNext()) {
    			                    String extension = (String)var11.next();
    			                    String viewNameWithExtension = viewName + '.' + extension;
    			                    view = viewResolver.resolveViewName(viewNameWithExtension, locale);
    			                    if (view != null) {
    			                        candidateViews.add(view);
    			                    }
    			                }
    			            }
    			        }
                }*/
                //从候选View中选出最佳View对象后返回
                View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
                if (bestView != null) {
         
                    return bestView;
                }
      }
      //... ...
    }
    
    //1.1.2 ContentNegotiatingViewResolver如何获取所有的视图解析器ViewResolver?
    //如何自定义视图解析器?给容器注入自定义ViewResolver实现类,ContentanargotiatingViewResolver自动组合进来
     protected void initServletContext(ServletContext servletContext) {
         
     		//用BeanFacotryUtils工具获取容器中所有ViewResolver的实现类,这就是candidateViewResolvers
            Collection<ViewResolver> matchingBeans = BeanFactoryUtils
              .beansOfTypeIncludingAncestors(this.getApplicationContext(), ViewResolver.class)
              .values();
    
    	   if (this.viewResolvers == null) {
         
                this.viewResolvers = new ArrayList(matchingBeans.size());
                Iterator var3 = matchingBeans.iterator();
    
                while(var3.hasNext()) {
         
                    ViewResolver viewResolver = (ViewResolver)var3.next();
                    if (this != viewResolver) {
         
                        this.viewResolvers.add(viewResolver);
                    }
                }
            } else {
         
                for(int i = 0; i < this.viewResolvers.size(); ++i) {
         
                    if (!matchingBeans.contains(this.viewResolvers.get(i))) {
         
                        String name = ((ViewResolver)this.viewResolvers.get(i)).getClass().getName() + i;
                        this.getApplicationContext().getAutowireCapableBeanFactory().initializeBean(this.viewResolvers.get(i), name);
                    }
                }
            }
    
  2. 自动配置类型转换器Converter与格式化器Formatter ===> ConverterFormatter
    //WebMvcAutoConfiguration.java
    //2.1 DateFormatter
    @Bean
    @ConditionalOnProperty(prefix = "spring.mvc",name = {
         "date-format"})//需要在配
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值