SpringBoot(二)——Thymeleaf及MVC装配扩展

个人博客:http://blog.kunpw.cn/

SpringBoot配置了什么?能不能对其进行修改?能修改什么?能不能扩展?通过自动装配原理的学习,接下来主要根据自动装配源码分析并得到以下结论。

1.导入静态资源

  • 这里的静态资源由果索因,即在网页中localhost:8080/后输入webjars路径相当于访问源文件路径,以此找到源文件中存放静态资源位置,注:静态资源包含html等文件;

  • 找到WebMvcAutoConfiguration文件以下部分:

public void addResourceHandlers(ResourceHandlerRegistry registry) {
    // 这一段是判断是否在配置文件中自主配置资源路径,如果配置则默认配置失效,直接在此返回
    if (!this.resourceProperties.isAddMappings()) {
        logger.debug("Default resource handling disabled");
        return;
    }
    
    Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
    CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
    
    // webjars是以jar包形式封装引入前端资源,此处可以从官网取出引入静态资源依赖的代码
    if (!registry.hasMappingForPattern("/webjars/**")) {
        customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
               .addResourceLocations("classpath:/META-INF/resources/webjars/")
               .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
    }
    
    String staticPathPattern = this.mvcProperties.getStaticPathPattern();
    /* 首先从mvcProperties对象的类WebMvcProperties文件中找到staticPathPattern变量
    	其次从resourceProperties对象的类ResourceProperties文件中找到staticLocations变量
    */
    if (!registry.hasMappingForPattern(staticPathPattern)) {
        customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)                                    .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))                      .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
    }
}
  • webjars引入 Maven jquery为例:

    image-20210305125609037
    • 将该段依赖代码放到pom.xml文件依赖中并加载相关依赖项,如图:

      image-20210305130316069

      这一段的含义是localhost:8080/webjars/路径相当于外部依赖库目录的classpath:/META-INF/resources/webjars/,因此在网页中输入localhost:8080/webjars/jquery/3.6.0/jquery.js即可获取到该静态资源,如图所示:

      image-20210305130913244
  • ResourceProperties文件静态资源默认路径:

    image-20210305131847108
    • 此处四个路径全部是根目录下resources文件下目录,而系统默认生成static文件夹用以存放静态资源。经过实践发现后三者优先级:/resources > /static > /public,而第一个路径其实就是外部依赖包路径,参考webjars
    • WebMvcProperties文件下staticPathPattern变量的默认地址就是根路径,即根路径下的资源也能直接访问到;
  • 关于在application.properties文件中修改资源路径,一般不使用,修改的话直接修改staticPathPattern变量即可,这样一来默认存放静态资源的路径就会全部失效;

2.定制首页

WebMvcAutoConfiguration文件中:

/* 此方法用以获取location路径,并调用getIndexHtml方法在默认路径中寻找index.html文件
	ResourceProperties文件中staticLocations变量即为静态资源路径,因此首页index.html文件可放在静态资源路径下
	不过一般不使用此方法,下述模板引擎会讲到另一种方式
*/
private Optional<Resource> getWelcomePage() {
    String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
    return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}

private Resource getIndexHtml(String location) {
    return this.resourceLoader.getResource(location + "index.html");
}

private boolean isReadable(Resource resource) {
    try {
        return resource.exists() && (resource.getURL() != null);
    }
    catch (Exception ex) {
        return false;
    }
}

3.模板引擎Thymeleaf

使用模板自动渲染数据生成静态网页

image-20210305211634119
  • Thymeleaf导入依赖包:

    <!-- Thymeleaf -->
        <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        </dependency>
        <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-java8time</artifactId>
        </dependency>
    

    在父配置文件中进入依赖文件可查看Thymeleaf的默认导入版本。

  • 首先查看源码,在ThymeleafProperties文件(每一个引入依赖都拥有自己的自动装配文件)中看到代码:

    // 两个变量分别定义了默认前缀和默认后缀,即前缀路径在根目录下resources/templates/目录下,即通过thymeleaf转换的html页面全部存放于该目录下
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    
  • templates目录下新建test.html文件,并在controller目录下新建IndexController.java文件用于测试Thymeleaf:

    • IndexController.java文件:
    package com.kun.demoweb.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    // thymeleaf转换的所有templates目录下页面全部需要通过Controller跳转
    @Controller
    public class IndexController {
    
        // 跳转路由
        @RequestMapping("/test")
        public String test(Model model){
            // 添加属性值传递到页面中
            model.addAttribute("msg","hello,springboot");
            // 从此处索引页面文件名
            return "test";
        }
    }
    
    • test.html文件:
    <!DOCTYPE html>
    <!-- html引入thymeleaf -->
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <!-- thymeleaf语法,引用传递过来的属性,类似于Vue语法 -->
        <!-- 在html标签属性前添加th: 所有属性都可以被thymeleaf接管 -->
        <div th:text="${msg}"></div>
    </head>
    <body>
    
    </body>
    </html>
    
  • Thymeleaf常见属性,此处不细讲,可去官网下载文档具体学习:

    image-20210305220947183
  • Thymeleaf常见语法:

    image-20210305221142248

4.装配扩展SpringMVC

  • 查看官网image-20210305230035024

  • 创建config包,新建MyMvcConfig.java文件用于扩展SpringMVC,并根据官网说明添加注解及接口,且不能使用注解@EnableWebMvc防止全部接管,由此可以重写一些功能;

  • image-20210305230640368

  • 如图,示例重写自己的视图解析器:

    • 先找到该文件:

      /*	1.resolveViewName方法获取所有的候选视图,并从中选择最好的视图返回,此时返回的视图解析器是Thymeleaf的
      */
      @Override
      @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 = getMediaTypes(((ServletRequestAttributes) attrs).getRequest());
          if (requestedMediaTypes != null) {
              List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);
              View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
              if (bestView != null) {
                  return bestView;
              }
          }
      
          String mediaTypeInfo = logger.isDebugEnabled() && requestedMediaTypes != null ?
              " given " + requestedMediaTypes.toString() : "";
      
          if (this.useNotAcceptableStatusCode) {
              if (logger.isDebugEnabled()) {
                  logger.debug("Using 406 NOT_ACCEPTABLE" + mediaTypeInfo);
              }
              return NOT_ACCEPTABLE_VIEW;
          }
          else {
              logger.debug("View remains unresolved" + mediaTypeInfo);
              return null;
          }
      }
      /*	2.getCandidateViews方法用以从Bean工具类中获取所有的候选视图
      */
      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");
              for (ViewResolver viewResolver : this.viewResolvers) {
                  View view = viewResolver.resolveViewName(viewName, locale);
                  if (view != null) {
                      candidateViews.add(view);
                  }
                  for (MediaType requestedMediaType : requestedMediaTypes) {
                      List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
                      for (String extension : extensions) {
                          String viewNameWithExtension = viewName + '.' + extension;
                          view = viewResolver.resolveViewName(viewNameWithExtension, locale);
                          if (view != null) {
                              candidateViews.add(view);
                          }
                      }
                  }
              }
          }
          if (!CollectionUtils.isEmpty(this.defaultViews)) {
              candidateViews.addAll(this.defaultViews);
          }
          return candidateViews;
      }
      
    • 将自己重写的视图解析器放入Bean工具类中即可:

      package com.kun.demoweb.config;
      
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.servlet.View;
      import org.springframework.web.servlet.ViewResolver;
      import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
      
      import java.util.Locale;
      
      @Configuration
      public class MyMvcConfig implements WebMvcConfigurer {
      
          // 将自定义的视图解析器添加进Bean中
          @Bean
          public ViewResolver myViewResolver(){
              return new MyViewResolver();
          }
      
          // 自定义自己的视图解析器,并重写resolveViewName方法
          public static class MyViewResolver implements ViewResolver {
              @Override
              public View resolveViewName(String viewName, Locale locale) throws Exception {
                  return null;
              }
          }
      }
      
      
  • Ctrl+shift+N搜索文件快捷方式;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值