SpringBoot开发Web应用集成Thymeleaf(官方推荐)

spring-boot-starter-web

Spring Boot提供了spring-boot-starter-web为Web开发予以支持,spring-boot-starter-web为我们提供了嵌入的Tomcat以及Spring MVC的依赖。

Spring MVC自动配置

Spring Boot为Spring MVC提供适用于多数应用的自动配置功能。在Spring默认基础上,自动配置添加了以下特性:

  1. 引入ContentNegotiatingViewResolver和BeanNameViewResolver beans。
  2. 对静态资源的支持,包括对WebJars的支持。
  3. 自动注册Converter,GenericConverter,Formatter beans。
  4. 对HttpMessageConverters的支持。
  5. 自动注册MessageCodeResolver。
  6. 对静态index.html的支持。
  7. 对自定义Favicon的支持。

如果想要自己完全控制WebMVC配置,就需要在@Configuration注解的配置类上增加@EnableWebMvc注解。增加该注解以后WebMvcAutoConfiguration中配置就不会生效,你需要自己来配置需要的每一项。这种情况下的配置还是要多看一下WebMvcAutoConfiguration类(上面7个默认配置就在此处设定)。

@EnableWebMvc
@Configuration
public class TestMvc {
    ···
}

如果想保留Spring Boot MVC的特性(应用默认配置),并只是添加自定义的MVC配置(拦截器,formatters,视图控制器等),你可以自定义一个配置类并继承WebMvcConfigurerAdapter类。在类中通过配置@Bean方法来注册自己想要的bean甚至是自定义的bean。或重写父类某一方法实现自己的处理逻辑

@Configuration
public class CustomizeWebMvcConfiguration extends WebMvcConfigurerAdapter {
        ···
    @Bean
    public BeanNameViewResolver beanNameViewResolver () {
        return  new BeanNameViewResolver(); // 示例代码
    }
  
   /* 一个道理
   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
   </bean>
   */
  
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
       registry.addResourceHandler("/webjar/**").addResourceLocations("classpath:/webjar/");
        super.addResourceHandlers(registry);
    }

        ···
}

当你使用@EnableWebMvc来配置spring mvc时,会把WebMvcConfigurationSupport当成配置文件来用,将其中所有标识有@Bean注解的方法配置成bean,这就成了Spring mvc的默认配置

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
        ····
}

各个组件都是可以定制化的,在WebMvcConfigurationSupport是通过模板方法模式来实现的,在各个发布成Bean的方法中(@Bean),都调用了自定义组件的抽象方法,所以可以在其在子类中对这些组件进行覆盖,如:

  • 对HandlerAdapter组件,有addInterceptors(InterceptorRegistry registry)可以添加自己的拦截器;

  • 对conversionService组件,有addFormatters(FormatterRegistry registry)可以添加自己的类型转换器;

    ···

从而实现定制化。

上面提到子类,Spring mvc提供的默认实现是DelegatingWebMvcConfiguration,覆盖父类的方法之前,它会寻找容器中所有的WebMvcConfigurer实现类,将所有WebMvcConfigurer实现类中的配置组合起来,组成一个超级配置,再对WebMvcConfigurationSupport中对应的发布成Bean的方法进行覆盖。这样,WebMvcConfigurationSupport中的bean配置发布时,就会把这所有自定义配置都带上了。

@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
        ···
}

总的来说就是,WebMvcConfigurationSupport负责bean的发布。分派自己的子类DelegatingWebMvcConfiguration去寻找用户所有实现了WebMvcConfigurer接口的实现类。并将用户所有发布成Bean的方法组合起来。交还给WebMvcConfigurationSupport统一发布并配置。

参考:Spring mvc注解配置的背后

静态文件

默认情况下,Spring Boot从classpath下一个叫/static(/public,/resources或/META-INF/resources)的文件夹或从ServletContext根目录提供静态内容。(这几个都是静态资源的映射路径,优先级顺序为:META-INF/resources > resources > static > public)

对应的配置文件配置如下:

# 默认映射,默认值为 /**
spring.mvc.static-path-pattern=
# 默认值为 classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
spring.resources.static-locations=这里设置要指向的路径,多个使用英文逗号隔开

可以通过修改spring.mvc.static-path-pattern来修改默认的映射,例如改成/thymeleaf/**,那运行的时候访问 http://lcoalhost:8080/thymeleaf/index.html 才对应到index.html页面。

这使用了Spring MVC的ResourceHttpRequestHandler,所以你可以通过添加自己的WebMvcConfigurerAdapter并覆写addResourceHandlers方法来改变这个行为(加载静态文件)。

在一个单独的web应用中,容器默认的servlet是开启的,如果Spring决定不处理某些请求,默认的servlet作为一个回退(降级)将从ServletContext根目录加载内容。大多数时候,这不会发生(除非你修改默认的MVC配置),因为Spring总能够通过DispatcherServlet处理请求。

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

:如果你的应用将被打包成jar,那就不要使用src/main/webapp文件夹。尽管该文件夹是一个共同的标准,但它仅在打包成war的情况下起作用,并且如果产生一个jar,多数构建工具都会静悄悄的忽略它

默认实现类:

class WebMvcConfigurerComposite implements WebMvcConfigurer {
                ···
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        for (WebMvcConfigurer delegate : this.delegates) {
            delegate.addResourceHandlers(registry);
    }
                ···
}
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
            ···
    @Bean
    public HandlerMapping resourceHandlerMapping() {
        ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
                this.servletContext, mvcContentNegotiationManager());
         // 关键代码
        addResourceHandlers(registry); 
      
        AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
        if (handlerMapping != null) {
            handlerMapping.setPathMatcher(mvcPathMatcher());
            handlerMapping.setUrlPathHelper(mvcUrlPathHelper());
            handlerMapping.setInterceptors(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
            handlerMapping.setCorsConfigurations(getCorsConfigurations());
        }
        else {
            handlerMapping = new EmptyHandlerMapping();
        }
        return handlerMapping;
    }
                ···
}

扩展类:

public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer {
                ···
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    }
                ···
}

模板引擎

Spring Boot支持多种模版引擎包括:

  • FreeMarker
  • Groovy
  • Thymeleaf(官方推荐)

JSP技术Spring Boot官方是不推荐的:

  1. Tomcat 只支持war的打包方式,不支持可执行的jar。
  2. Jetty 嵌套的容器不支持jsp
  3. Undertow
  4. 创建自定义error.jsp页面不会覆盖错误处理的默认视图,而应该使用自定义错误页面

当你使用上述模板引擎中的任何一个,它们默认的模板配置路径为:src/main/resources/templates

Thymeleaf模板引擎

Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎。类似JSP,Velocity,FreeMaker等,它也可以轻易的与Spring MVC等Web框架进行集成作为Web应用的模板引擎。与其它模板引擎相比,Thymeleaf最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个Web应用。它的功能特性如下:


引入依赖

<!--thymeleaf模板引擎 -->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

需要注意的是:

spring-boot-starter-thymeleaf会自动包含spring-boot-starter-web,所以我们就不需要单独引入web依赖了。

Model

@Data
@AllArgsConstructor
public class User {
    private String username;
    private String password;
}

Controller

@Controller
@RequestMapping(value = "/thymeleaf")
public class ThymeleafController {

    @RequestMapping(path = "/", method = RequestMethod.GET)
    public ModelAndView index() {
        List<User> userList = new ArrayList<User>();
        User user = new User("jyg", "jyg");
        userList.add(user);
        user = new User("lyn", "lyn");
        userList.add(user);
        ModelAndView modelAndView = new ModelAndView("index.html");
        modelAndView.addObject("userList", userList);
        return modelAndView;
    }
}

Html

  1. 首先通过xmlns:th=”http://www.thymeleaf.org“ 命名 thymeleaf 空间,将静态页面转换为动态的视图,需要进行动态处理的元素将使用“th:”前缀。
xmlns:th="http://www.thymeleaf.org"
  1. 代码:

    <body>
    <h1>Thymeleaf</h1>
    <hr/>
        <table class="table table-striped table-bordered table-hover">
            <tr class="info">
                <td>用户名</td>
                <td>密码</td>
            </tr>
            <!--/*@thymesVar id="userList" type=""*/-->
            <tr th:each="user : ${userList}" class="success">
                <td th:text="${user.username}">冀永光</td>
                <td th:text="${user.password}">jiyongguang.</td>
            </tr>
        </table>
    </body>
    

Thymeleaf 做到了什么

直接访问 index.html :

访问 http://localhost:8080/thymeleaf/

Thymeleaf 做到了不破坏 Html 自身内容的数据逻辑分离。

Thymeleaf的默认参数配置

# THYMELEAF (ThymeleafAutoConfiguration)
#开启模板缓存(默认值:true)
spring.thymeleaf.cache=true 
#Check that the template exists before rendering it.
spring.thymeleaf.check-template=true 
#检查模板位置是否正确(默认值:true)
spring.thymeleaf.check-template-location=true
#Content-Type的值(默认值:text/html)
spring.thymeleaf.content-type=text/html
#开启MVC Thymeleaf视图解析(默认值:true)
spring.thymeleaf.enabled=true
#模板编码
spring.thymeleaf.encoding=UTF-8
#要被排除在解析之外的视图名称列表,用逗号分隔
spring.thymeleaf.excluded-view-names=
#要运用于模板之上的模板模式。另见StandardTemplate-ModeHandlers(默认值:HTML5)
spring.thymeleaf.mode=HTML5
#在构建URL时添加到视图名称前的前缀(默认值:classpath:/templates/)
spring.thymeleaf.prefix=classpath:/templates/
#在构建URL时添加到视图名称后的后缀(默认值:.html)
spring.thymeleaf.suffix=.html
#Thymeleaf模板解析器在解析器链中的顺序。默认情况下,它排第一位。顺序从1开始,只有在定义了额外的TemplateResolver Bean时才需要设置这个属性。
spring.thymeleaf.template-resolver-order=
#可解析的视图名称列表,用逗号分隔
spring.thymeleaf.view-names=
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容