Spring Boot 之 web 开发

使用 JSP

  • SpringBoot 中不推荐使用 JSP

    • 使用模板技术代替 JSP
  • 使用 JSP 需要配置后才能使用

    1. 添加处理 jsp 的依赖

      <dependency>
          <groupId>org.apache.tomcat.embed</groupId>
          <artifactId>tomcat-embed-jasper</artifactId>
      </dependency>
      
    2. 若要使用 servlet、jsp 、jstl 等的功能也需要添加相关依赖

      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
      </dependency>
      <dependency>
          <groupId>javax.servlet.jsp</groupId>
          <artifactId>javax.servlet.jsp-api</artifactId>
          <version>2.3.1</version>
      </dependency>
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>jstl</artifactId>
      </dependency>
      
    3. 创建存放 jsp 的目录,一般为 webapp,设为项目中 jsp 资源目录

      • 创建 index.jsp
    4. 在 pom.xml 文件指定 jsp 文件编译后存放的目录

      • webapp 目录下所有文件编译到 target 目录下 META-INF/resources 目录

        • 包括子目录文件
      • <resources>
            <resource>
                <!-- 指定 jsp 文件的编译路径 -->
                <directory>src/mian/webapp</directory>
                <!-- 编译的目标目录 -->
                <targetPath>META-INF/resources</targetPath>
                <!-- 包含子目录及所有文件 -->
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
        
    5. 创建 Controller 访问 jsp

      • 方法参数 HttpRequestModel 对象来返回数据

        @RequestMapping
        public String doOther(Model model){
            //将数据放到 request 作用域;等价于 request.setAttribute()
            model.addAttribute("data", "废物");
            //返回 index.jsp 页面,页面的逻辑名,由视图解析器包装为完整视图
            return "index";
        }
        
    6. application.properties 文件中配置视图解析器

      • # 配置视图解析器
        spring.mvc.view.prefix=/
        spring.mvc.view.suffix=.jsp
        

Web开发

静态资源

  1. 通过 Maven 依赖导入 jar 包

    • 自动加载 jar 包中的 /META-INF/resources/webjars 路径找到静态资源
    • WebJars 是将 web 前端资源(如:jQuery、Bootstrap)打成 jar 包文件
      • 借助版本管理工具( Maven、gradle 等)进行版本管理
      • 保证这些 Web 资源版本的唯一性。避免了文件混乱、版本不一致等问题
  2. 加载 staticPathPattern = "/**" 路径

    • 默认到以下四个资源目录中查找静态资源:按优先级顺序排列

      1. "classpath:/META-INF/resources/"

      2. "classpath:/resources/"

        • 一般存放资源文件
      3. "classpath:/static/":默认生成目录

        • 一般存放静态资源
      4. "classpath:/public/"

        • 一般存放公共共享资源
    • 自定义加载静态资源文件的路径

      • 加载系统资源目录后查找自定义资源目录

        • spring.mvc.static-path-pattern:阐述 HTTP 请求路径

          • # 只有静态资源的访问路径为 /resources/** 时,才会处理请求
            spring.mvc.static-path-pattern=/resources/**,
            
        • spring.resources.static-locations:静态资源的存放位置

          • 添加静态资源文件路径:列表性的配置
            • 查找文件时会依赖于配置的先后顺序依次进行
        spring:
          # 资源请求路径
          mvc:
            static-path-pattern: \**
          # 资源访问地址
          resources:
            static-locations: [classpath: /META-INF/resources/, classpath: /resources/, classpath: /static/, classpath: /public/, file: ${web:vue-path}]
        

MVC 扩展

实现
  • 在 SpringBoot 中对 MVC 有默认的支持实现

    • 可以自定义实现 mvc 接管 框架的定义
  • 创建类实现不同的 mvc 组件接口以自定义拓展组件功能

    • 在类中重写方法自定义组件功能
  • 创建 MVC 配置类实现 WebMvcConfigurer 接口,此类就是 mvc 的配置类

    • 不能添加 @EnableWebMvc 注解
      • 该注解引入 @Import({DelegatingWebMvcConfiguration.class})
        • 这个类继承了 WebMvcConfigurationSupport
      • 添加此注解会使 WebAutoMvcConfigurer 自动装配失效
        • WebMvcAutoConfiguration 自动配置类生效需要所有配置类中不存在 WebMvcConfigurationSupport.class
    • 将自定义的组件类注册到容器中
拦截器
  • 拦截器是 SpringMVC 中的一种对象
    • 能拦截对 controller 的请求
  • 拦截器框架中有系统的拦截器
    • 可以自定义拦截器
    • 实现对请求预先处理
SpringMVC

自定义拦截器使用

  1. 创建类实现 HandlerInterceptor 接口

    • 接口中有三个方法
      • 处理方法前执行
      • 处理方法后执行
      • 请求完成后执行
    • 根据需求选择方法重写使用
  2. 在 SpringMVC 配置文件中声明拦截器

    <mvc:interceptors>
    	<mvc:interceptor>
        	<mvc:path="url"/>
            <bean class="拦截器全限定名">
        </mvc:interceptor>
    </mvc:interceptors>
    
SpringBoot
  1. 创建类实现 HandlerInterceptor 接口
  2. 注册拦截器
    • 创建配置类实现 WebMvcConfigurer 接口
      • 此接口中有大量方法处理 SpringMVC 内容
    • 注解 @Configuration 使此类作为配置类作为配置类
    • 重写 addInterceptors 方法注册拦截器
      1. 创建拦截器对象放入
      2. 执行拦截的 url
      3. 排除拦截的 url
  3. 创建 controller 类方法处理请求测试拦截器
// 拦截器定义
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行了拦截器");
        return true;
    }
}
// 注册拦截器,将拦截器对象放到容器中
@Configuration
public class WebConf implements WebMvcConfigurer {
    // 自动装配;对象赋值
    @Resource
    private MyInterceptor interceptor;

    //注册拦截器
    @Override
    public void addInterceptors( InterceptorRegistry registry) {
        // 将拦截器对象放到容器中,拦截 /doSome 请求,排除 /doOther 请求
        registry.addInterceptor(interceptor).addPathPatterns("/doSome"). excludePathPatterns("/doOther");
    }
}
Servlet

自定义使用 servlet

  1. 定义 MyServlet 类继承 HttpServlet
    • 重写 doGet()doPost() 方法处理请求
  2. 创建配置类注册 servlet 对象
    • 注解 @Configuration 作为配置类使用
    • 定义方法注册 servlet 对象
      • 方法返回值为 ServletRegistrationBean<T> 对象
      • 创建 ServletRegistrationBean<T> 对象注册 myServlet
        • 使用有参构造传入 servlet 对象和对应请求的 url 地址
        • url 参数类型为可变长,可以传入多个 url
      • 方法上注解 @Bean 将对象存放到容器
  3. 自定义 servlet 类方法将会覆盖掉 controller 中的处理方法
// MyServlet 类,注解创建对象
@Component
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, 
                         HttpServletResponse resp) 
        throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, 
                          HttpServletResponse resp) 
        throws ServletException, IOException {
        // 指定数据类型、编码格式
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        // 输出数据
        writer.println("执行了 servlet");
        // 刷新并关闭流
        writer.flush();
        writer.close();
    }
}

// 配置类,注册 servlet 对象
@Configuration
public class ServletConf {
    // 自动赋值对象
    @Resource
    private MyServlet servlet;
    
    /*
    * 创建对象并放到容器中
    * 注册 servlet 对象并处理 /myServlet 请求,
    * 注册后 servlet 方法将会覆盖 controller 中对应请求处理方法
    */
    @Bean
    public ServletRegistrationBean<Servlet> servletRegistrationBean(){
        // 有参构造,传入 servlet 对象和对应的 url 地址(可变参数)
        return new ServletRegistrationBean<>(servlet, "/myServlet");
        /*
        无参构造注册 servlet
        ServletRegistrationBean<Servlet> bean =  new ServletRegistrationBean<>();
        bean.setServlet(servlet);
        bean.addUrlMappings("/myServlet", "/doSome", "/doOther");
        return bean;
        */
    }
}
Filter
使用方式
  • Filter 是 Servlet 中的过滤器

    • 可以处理请求:对请求的参数、属性进行调整

    • 常在过滤器中处理字符编码

  • 自定义使用 Filter,类似 servlet 的步骤

    1. 创建过滤器类实现接口 Filter
      • 实现方法 doFilter()
    2. 注册 Filter
      • 创建配置类
        • 添加注解 @Configuration
      • 定义方法注册过滤器对象
        1. 方法上添加注解 @Bean
        2. 方法返回值 FilterRegistratonBean<>
        3. 调用方法传入 filter 对象注册
        4. 设置过滤的 url 请求
// 自定义过滤器类
@Component
public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, 
                         ServletResponse servletResponse, 
                         FilterChain filterChain) 
        throws IOException, ServletException {
        System.out.println("执行了过滤器方法");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
// 定义配置类,注册 Filter 对象
@Configuration
public class FilterConf {
    @Resource
    private MyFilter filter;
    
    @Bean
    public FilterRegistrationBean<Filter> filterFilterRegistrationBean(){
      FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
        // 注册过滤器
        bean.setFilter(filter);
        // 添加过滤请求,相当于 <url-pattern> 标签
        bean.addUrlPatterns("/*");
        return bean;
    }
}
字符集过滤器
  • CharacterEncodingFilter:字符集过滤器
    • 解决 post 请求中文乱码
      • 默认编码:ISO-8859-1
    • encoding:当前使用的编码方式
    • forceRequestEncoding:默认 false,不使用当前编码
    • forceResponseEncoding:默认 false,不使用当前编码
配置类
  1. 直接在过滤器配置类中创建 CharacterEncodingFilter 对象

    • 设置对象属性

      • 指定编码格式
      • 指定使用编码格式
    • 将对象放到容器中

    • @Configuration
      public class FilterConf {
          @Bean
          public FilterRegistrationBean<Filter> filterFilterRegistrationBean(){
              // 创建返回对象
              FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
              // 创建字符集过滤器
              CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
      	    // 设置编码格式,并指定使用:将属性赋值为 true
              encodingFilter.setEncoding("utf-8");
              encodingFilter.setForceEncoding(true);
              bean.setFilter(encodingFilter);
              bean.addUrlPatterns("/*");
              return bean;
          }
      
      }
      
  2. 修改配置文件

    # SpringBoot 已经默认配置了 CharacterEncodingFilter
    # 但编码格式 ISO-8859-1,将此项设置为 false 以使用自定义过滤器
    server.servlet.encoding.enabled: false
    
配置文件指定
# 使用 SpringBoot 的字符过滤器
server.servlet.encoding.enabled=true
# 设置字符格式为 utf-8
server.servlet.encoding.charset=utf-8
# 强制应答和请求使用 encoding 编码
server.servlet.encoding.force=true

页面

  • 页面配置
    • 将所有静态资源由 Tymeleaf 接管
      • 使用表达式动态获取数据
  • 国际化
    • 配置 i18n 文件:国际化文件
      • internationalization,国际化
      • L10N:localization,本地化
    • 通过按钮自定义切换语言版本
      • 需要自定义组件 LocaleResolver
    • 将组件放入容器中:通过 @Bean
  • 错误
    • templates 目录下创建 error 目录
    • 页面报错时会自动加载目录下页面
      • 例如:404 错误会加载 404 页面

Thymeleaf

介绍

  • Thymeleaf 模板

    • 一个流行的模板引擎,采用 Java 开发
      • Java 生态下模板引擎有 ThymeleafFreemakerVelocityBeetl(国产) 等
      • jsp 就是最早的模板技术
    • 模板做视图层显示数据
  • Thymeleaf 对网络环境没有严格要求

    • 能用于 web 环境和非 web 环境
      • 非 web 环境下能直接显示模板上的静态数据
      • web 环境下能像 jsp 一样从后台接收数据并替换模板的静态数据
    • 基于 html,以 html 标签为载体实现
      • 语法应用在 html 标签中
  • SpringBoot 集成了 Thymeleaf 模板技术

    • 官方推荐使用 Thymeleaf 代替 jsp 技术
      • jsp 需要编译运行,效率低

配置

  • 创建 SpringBoot 项目添加 Thymeleaf 起步依赖

    • 自动引入最新版本 Thymeleaf 依赖
  • 基本都为默认配置,无需修改

    • 根据需求自定义修改
    # 模板缓存: 默认打开;开发阶段关闭模板缓存,使修改立即生效
    spring.thymeleaf.cache=false
    # 编码格式: 默认 UTF-8
    spring.thymeleaf.encoding=UTF-8
    # 模板类型: 默认 HTML 文件
    spring.thymeleaf.mode=HTML
    # 模板前缀: 默认类路径的前缀 classpath:/templates/
    spring.thymeleaf.prefix=classpath:/templates/
    # 模板后缀: 默认后缀 .html
    spring.thymeleaf.suffix=.html
    

表达式

${key}
  • th:text="${key}":标准变量表达式
    • 获取 key 对应的文本数据
  • 在页面 html 标签中使用 tx:text="${key}"接收替换数据
    • th:test="":Thymeleaf 的属性,用于文本显示
  • key 是 request 作用域中的 key
    1. 使用 reque st.setAttribute(key, value); 添加数据
    2. model.addAttribute(key, value);
<!-- key 是 request 作用域内的 key,获取对应的 value -->
<p th:text="${key}">正常的静态数据</p>

<body>
<h1>标准变量表达式 ${} </h1>
<h2 th:text="${data}">全部信息</h2>
<div>
    <!-- date 对应 value 为 Java 对象时,可获取其属性或方法使用 -->
    <h3>id&nbsp;=&nbsp;</h3><h3 th:text="${data.id}">id</h3><br/>
    <h3>name&nbsp;=&nbsp;</h3><h3 th:text="${data.name}">id</h3><br/>
    <h3>age&nbsp;=&nbsp;</h3><h3 th:text="${data.getAge()}">id</h3><br/>
    <h3>date&nbsp;=&nbsp;</h3><h3 th:text="${data.getDate()}">id</h3><br/>
</div>
</body>
*{key}
  • th:text="*{}":选择变量表达式
    • 获取 key 对应的 value 对象的属性
  • 需要和 th:object="${key}" 一起使用
    • 简单获取对象的属性值
    • th:object="${key}" 作用范围内可以直接使用 key 对应 value 对象的属性
      • *{field}:通过对象字段直接获取值
      • 等价于:th:text=${data.name}
  • 或通过完整名获取属性
    • th:text="{data.name}":和 ${key} 格式相同
<body>
<h1>选择变量表达式 *{}</h1>
<h2 th:text="${data}">全部信息</h2>
    
<!-- 获取 value 对象 -->
<div th:object="${data}">
    <!-- 作用范围内直接获取属性、方法;等价于 data.id -->
    <h3>id&nbsp;=&nbsp;</h3><h3 th:text="*{id}">id</h3><br/>
    <h3>name&nbsp;=&nbsp;</h3><h3 th:text="*{name}">name</h3><br/>
    <h3>age&nbsp;=&nbsp;</h3><h3 th:text="*{getAge()}">age</h3><br/>
    <h3>date&nbsp;=&nbsp;</h3><h3 th:text="*{getDate()}">date</h3><br/>
</div>
    
<h3>age</h3><h3 th:text="*{data.age}">使用完整名</h3>
</body>
@{url}
  • th:href="@{url}":链接表达式

    • 表示链接,使用在链接中

      <!-- 可用在链接中 -->
      <script src=" "></script>    
      <link href=" "></link>
      <a href=" "></a>    		
      <form action=" "></form>
      <img src=""></img>
      
    • url 可以是绝对地址或相对地址

  • 传参

    • () 内传递参数:th:href="@{do4/(id=${id}, name=${name})}"
      • 多个参数使用 , 分隔
    • 嵌套表达式、拼接字符串:"@{'do3?id=' + ${id}}"
    <body>
    <h2>链接表达式 @{url}</h2>
    <h3>链接绝对路径</h3>
    <a th:href="@{https://www.baidu.com}">绝对地址,链接到百度</a>
    
    <h3>链接相对路径</h3>
    <!-- url中拼接传参 -->
    <a th:href="@{'do3?id=' + ${id}}">相对地址,传参</a>
    
    <h3>相对地址,使用字符串传参</h3>
    <a th:href="@{'do4?id=' + ${id} + '&name=' + ${name}}">相对地址,使用字符串传参</a>
        
    <!-- () 内引用参数 -->
    <h3>推荐使用的传参方式</h3>
    <a th:href="@{do3/(id=${id})}">单个参数</a>
    <a th:href="@{do4/(id=${id}, name=${name})}">多参数</a>
    </body>
    

属性

  • 大部分属性和 HTML 相同,作用和原来相同
    • 添加前缀 th
      • 添加 th 之后经过模板引擎处理
    • 可以使用变量表达式
th:action
  • 定义后台控制器路径
    • 类似 <form> 标签的 action 属性
    • 结合 URL 表达式,获取动态变量
<form id="login" th:action="@{/login}" th:method="post"></form>
th:method

设置请求的方法

<form id="login" th:action="@{/login}" th:method="post"></form>
th:href

定义超链接,结合 URL 表达式获取动态变量

<a th:href="@{do3/(id=${id})}">单个参数</a>
th:src
  • 用于外部资源引用
    • 比如:<script> 标签的 src 属性、<img> 标签的 src 属性
  • 常与 @{} 表达式结合使用
  • 在 SpringBoot 项目的静态资源都放到 resoruces 目录下的 static 目录
    • 写路径时不含 static 目录
<!-- 引入 JQuery 文件 -->
<script type="text/javascript" th:src="@{/js/jquery-3.4.1.js}"></script>
th:text
  • 用于文本显示
    • 该属性显示的文本在标签体中
  • 如果是文本框数据会在文本框外显示
    • 想要显示在文本框内使用 th:value
<input type="text" id="reakName" name="realName" th:text="${realName}">
th:utext
  • 将文本转义
    • 按照 html 语法格式执行
th:style

设置样式

<a th:onclick="'fun1(' + ${user.id} + ')'" th:style="'color:red'">点击</a>
th:each

循环遍历

  • 从后台传来对象集合就可以使用此属性遍历输出
    • 与 JSTL 中 <c:forEach>类似
    • 可以循环遍历集合、数组、Map
  • th:each 所在的标签会被循环
  • 语法:th:each="demo,demoStat:${Demo}"
    • demo:自定义的循环变量名
    • demoStat: ${Demo} 循环体信息
      • index:获取当前迭代对象的下标,从 0 开始
      • count:当前迭代对象序列,从 1 开始
      • size:被迭代对象大小
      • current:当前迭代变量
      • even、odd:布尔值,当前循环是否是偶数,从 0 开始
      • first、last:布尔值,当前循环是否是第一个、最后一个
      • demoStat 可不定义,默认存在:变量+Stat
        • demo:${Demo},默认循环体信息 demoStat
    • 使用 th:text=${demo} 接收循环变量
循环 List、Array
<table th:border="1" th:cellpadding="5" th:cellspacing="0" >
    <thead>
    <tr>
        <td> id </td>
        <td> name </td>
        <td> age </td>
        <td> date </td>
    </tr>
    </thead>
    <tbody>
    <!-- demo:${Demo} 等价于 demo,demoStat:${Demo} -->
    <tr th:each="demo:${Demo}">
        <td th:text="${demo.getId()}">id</td>
        <td th:text="${demo.getName()}">name</td>
        <td th:text="${demo.age}">age</td>
        <td th:text="${demo.date}">date</td>
    </tr>
    </tbody>
</table>
循环 Map
  • Map 循环无序
    • 通过 key 获取 Map 的 key
    • 通过 value 获取 Map 的 value
<table th:border="1" th:cellpadding="5" th:cellspacing="0" >
    <thead>
    <tr>
        <td> 编号 </td>
        <td> key </td>
        <td> id </td>
        <td> 姓名 </td>
        <td> 年龄 </td>
        <td> 生辰 </td>
    </tr>
    </thead>
    <tbody>
    <tr th:each="map:${Demo}">
        <!-- map 定义 id 为 key, demo 对象为 value -->
        <td th:text="${mapStat.count} + '/' + ${mapStat.size}"></td>
        <!-- key 属性获取 Map 中的 key -->
        <td th:text="${map.key}"></td>
        <!-- value 属性获取对应的 value 值,通过对象获取属性或方法 -->
        <td th:text="${map.value.id}">id</td>
        <td th:text="${map.value.name}">name</td>
        <td th:text="${map.value.getAge()}">age</td>
        <td th:text="${map.value.getDate()}">date</td>
    </tr>
    </tbody>
</table>
循环 List-Map
  • 先循环外层 List
  • 再循环内层 Map
  • 注意 th:each 的循环范围
<table th:border="1" th:cellpadding="5" th:cellspacing="0">
    <thead>
    <tr>
        <td> 编号</td>
        <td> key</td>
        <td> id</td>
        <td> 姓名</td>
        <td> 年龄</td>
        <td> 生辰</td>
    </tr>
    </thead>
    <tbody>
    <div th:each="list:${Demo}">
        <tr th:each="map:${list}">
            <td th:text="${mapStat.count}"></td>
            <td th:text="${map.key}"></td>
            <td th:text="${map.value.id}"></td>
            <td th:text="${map.value.name}"></td>
            <td th:text="${map.value.age}"></td>
            <td th:text="${map.value.date}"></td>
        </tr>
    </div>
    </tbody>
</table>
th:if
  • 条件判断 if
  • 语法:th:if="boolean 条件"
    • 条件为 true 显示标签体内容
    • 非 null 的内容不进行表达式判断时都为 true
      • th:“${name}”:name 只要不是 null 就显示内容
    • 对于 null 默认为 false
      • 只有进行th:if${name == null}才会显示内容
  • th:unlessth:if的相反操作
<div th:if="true">显示文本内容</div>
<div th:unless="false">显示文本内容</div>
<!--
添加的数据
model.addAttribute("test1", true);
model.addAttribute("test2", false);
model.addAttribute("name", "张三");
model.addAttribute("hobby", "");
model.addAttribute("age", 18);
model.addAttribute("date", null);
-->
<body>
<h2>测试 if、unless 判断条件</h2>
<h3 th:if="${test1}">if 为 true 显示</h3>
<h3 th:unless="${test2}">unless 为 false 显示</h3>
<h3 th:if="${name}"> name非空,可以显示 </h3>
<h3 th:if="${hobby}">hobby="" 默认为 true,可以显示</h3>
<h3 th:if="${age}"> age非空,可以显示</h3>
<h3 th:if="${date}">date=null 默认为 false,不显示</h3>
<h3 th:unless="${date}">date=null 默认为 false,可以显示</h3>
</body>
switch case
  • 判断语句:用法类似 Java
    • 最多只有一个匹配成功
<div th:switch="${key}">
	<p th:case="value1">结果1</p>
    <p th:case="value2">结果2</p>
    <p th:case="*">默认值</p>
    <!-- 只有一个能匹配成功,都不匹配时执行默认case -->
</div>
<!-- model.addAttribute("age", 18); -->
<div th:switch="${age}">
    <h3 th:case=10>年龄为 10 岁</h3>
    <h3 th:case=12>年龄为 12 岁</h3>
    <h3 th:case=18>年龄为 18 岁,显示此行</h3>
    <h3 th:case="*">年龄未知,默认语句,都不匹配时显示</h3>
</div>
th:inline
  • 内联
  • 三个取值类型
    • textjavascriptnone
内联 text
  • 可以让 Thymeleaf 不依赖于 html 标签

    • 直接使用 内联表达式[[表达式]] 即可获取动态数据
    • 父级标签上加 th:inline="text"属性
      • 可省略
    <p>显示姓名是:[[${name}]]</p>
    
<body>
<h1>测试 inLine 内联使用</h1>

<h2>inLine text 内联文本</h2>
<div th:inline="text">
    <h3>数据 data = [[${data}]]</h3>
</div>
    
<h2>省略 th:inline 标签</h2>
<h3>数据:[[${data}]]</h3>
</body>
内联 javascript
  • 将模板数据和 Java 数据联合
  • 在 JS 脚本中可以直接使用 Thymeleaf 取值表达式
<head>
    <meta charset="UTF-8">
    <title>内联 inLine</title>
    <script type="text/javascript" th:inline="javascript">
        function fun(){
            alert([[${data}]]);
        }
    </script>
</head>
<body>
<h2>测试 javascript 使用 inline</h2>
<input type="button" name="btn" value="单机获取数据" onclick="fun()">
</body>

字面量

  • 在模板文件中直接写,可以正常显示

    • 模板表达式中引用的是 model 中数据
  • 文本字面量:'' 包围的字符串

    • 引用变量不存在时会显示 null
  • 数字、布尔值、null 字面量直接使用

<h2>测试字面量</h2>
<!-- 后台数据
model.addAttribute("test1", true);
model.addAttribute("name", "张三");
model.addAttribute("date", null);
-->
<div>
<!-- 
${name} 引用 name 值,不存在时显示为 null,其他内容正常显示
若例如 ${111} 使用数字,作为数字字面量直接显示
-->
    <h3 th:text="'文本字面量' + ';动态数据 name = ' + ${name}">姓名</h3>
    <h3 th:if="${20 > 5}">数字字面量直接使用,正常显示</h3>
    <h3 th:if="${test1 == true}">布尔字面量 true 直接使用,正常显示</h3>
    <h3 th:if="${date == null}">null 字面量直接使用,正常显示</h3>
</div>

字符串连接

  1. 使用 '' 将静态字符串包裹,使用 + 连接动态数据
  2. 使用双竖线 || 包裹字符串和表达式
<!-- 文本字面量,'' 和 + 连接字符串 -->
<h3 th:text="'正常显示文本字面量' + ';动态数据 name = ' + ${name}">姓名</h3>
<!-- 使用 || 包裹连接字符串-->
<h3 th:text="|正常显示,拼接数据 name = ${name}|">姓名</h3>

运算符

  • 算术运算:+ - * / %
    • 别名:div(除)、mod(求余)
  • 关系比较:>、<、>=、<=
    • 别名:gt、lt、ge、le
    • html 页面中部分符号无法正常显示,需要使用转义字符
  • 相等判断:==、!=
    • 别名:eq、ne
  • 三元运算符:... ? ... : ...
<div>
    <!-- th:text 直接显示运算结果, th:if 根据表达式结果判断是否显示-->
    <p th:text="${ 20 > 10}">xtrue</p>
    <p th:test="${20 + 50}"> 70 </p>
    <p th:if="${false == false}"></p>
    <!-- 三元运算符 -->
    <p th:text="${ date == null ? '张三' : '李四' }"></p>
    <!-- 嵌套三元运算符 -->
    <p th:text="${age == null ? '废物' : (age > 10 ? '大于10':'小于10')}"></p>
</div>

内置基本对象

介绍
  • 模板引擎提供了一组内置的对象

    • 可以直接在模板中使用

    • 对象由 # 开始引用

  • 常用对象

    • #request:表示 HttpServletRequest
      • 数据类型:HttpServletRequest
      • 可使用类中所有方法
    • #session:表示 HttpSession
      • 数据类型:HttpSession
      • 可使用类中所有方法
    • session 表示 Map 对象
      • 类型:Map,存储在 Map 结构中
      • #session 的简化形式,获取 session 中指定 key 的值
      • session.getSession 等价 session.getAttribute("getSession")
    • param:表示参数对象
      • 请求的参数集合
    • applicationservletContext
//添加数据
@GetMapping("/baseObject")
public String baseObject(Model model, HttpServletRequest request, HttpSession session) {
    model.addAttribute("name", "李四");
    request.setAttribute("requestData", "request 中数据");
    request.getSession().setAttribute("getSession", "getSession 中数据");
    session.setAttribute("session", "session 中数据");
    return "baseObject";
}
<!-- 获取数据 -->
<body>
<h2>测试基本内置对象</h2>
<h2 th:text="${#request.getAttribute('requestData')}"></h2>
<h2 th:text="${#session.getAttribute('getSession')}"></h2>
<h2 th:text="${session.session}"></h2>
<h2 th:text="${session.getSession}"></h2>
</body>
#request
  • 内置对象的方法
<h2>#request 方法</h2>
完整 url,不含参数:  <span th:text="${#request.getRequestURL()}"></span><br/>
访问地址,不含参数:	<span th:text="${#request.getRequestURI()}"></span><br/>
参数部分:			<span th:text="${#request.getQueryString()}"></span><br/>
上下文:			 <span th:text="${#request.getContextPath()}"></span><br/>
ip:				    <span th:text="${#request.getServerName()}"></span><br/>
端口号:			 <span th:text="${#request.getServerPort()}"></span><br/>
<!-- 还有很多操作方法 -->
<!--
url:http://localhost:8080/baseObject
显示结果:
完整 url,不含参数http://localhost:8080/baseObject
访问地址,不含参数/baseObject
参数部分
上下文
iplocalhost
端口号8080
-->
param
  • 获取请求中的参数
name的参数值	 <span th:text="${param.name}"></span><br/>
参数的数量		<span th:text="${param.size}"></span><br/>

内置工具类对象

  • 模板自带的对 日期、数字、字符串、集合 等的处理
  • 内置对象前都需要加 # ,一般都以 s 结尾
#dates
  • 测试部分方法
<!-- 数据 model.addAttribute("date", new Date()); -->
<!-- 默认格式化显示日期 -->
<p th:text="${#dates.format(date)}"></p>
<!-- 自定义格式化日期 -->
<p th:text="${#dates.format(date, 'yyyy-MM-dd HH:mm:ss')}"></p>
<!-- 获取年(月、日)信息 -->
<p th:text="${#dates.year(date)}">
<!-- 创建日期,当前日期(可自定义) -->
<p th:text="${#dates.createNow()}">
#numbers
  • 操作数字、格式化显示等
  • 测试部分方法
<!-- 数据:model.addAttribute("doubleNum",12.3456); -->

<!-- 数字货币格式化,默认当前本国货币 -->
<p th:text="${#numbers.formatCurrency(doubleNum)}"></p>
<!-- 格式化显示小数,整数部分 5 位,小数部分 2 位-->
<p th:text="${#numbers.formatDecimal(doubleNum, 5, 2)}"></p>
#strings
  • 操作字符串:格式化、截取等操作
  • 测试部分方法
<!-- 数据:model.addAttribute("string","asdfgghj");  -->

<!-- 字符串全部大写 -->
<p th:text="${#strings.toUpperCase(string)}">
<!-- 查找匹配的第一个子字符串位置 -->
<p th:text="${#strings.indexOf(string, 'gg')}">
<!-- 截取字符串,自定义范围(可只指定开始范围截取到最后) -->
<p th:text="${#strings.substring(string, 3, 6)}">
#lists
  • 操作 List 集合
  • 测试部分方法
<!-- 是否存在指定元素(结果取反处理了), boolean 类型 -->
<p th:if="!${#lists.contains(list, demo)}">存在成员</p>
<!-- 集合长度,lsit 不能为 null,可以是空集合 -->
<p th:text="${#lists.size(list)}"></p>
<!-- 集合元素是否为 null -->
<p th:text="${#lists.isEmpty(list)}"></p>
null 处理
  • th:text=“demo?.name”:引用 demo 对应的对象的 name 属性
    • ?:询问前面对象是否为 null
      • 不为 null 时正常处理
      • null 不执行后面的语句
  • 在直接执行对象为 null 时无需处理
<!-- 数据
Demo demo = null;
Demo demo1 = new Demo();
-->
<!-- demo 为 null 且未处理引用属性;报异常 -->
<p th:text="${demo.name}"></p>
<!-- demo 为 null 但直接使用,不显示此句,无异常 -->
<p th:text="${demo}"></p>
<!-- 对 null 的处理,先判断 ? 前是否为 null;为 null 时不显示此句,无异常 -->
<p th:text="${demo?.name}"></p> 
<!-- demo1 不为 null,但 name 为 null;不显示此句,无异常 -->
name=<p th:text="${demo1.name}">name</p>

自定义模板

自定义
  • 定义

    • <!-- 语法格式 -->
      th:fragment="自定义模板名"
      
      <!-- 示例 -->
      <div th:fragment="demo">
          <p>测试模板</p>
          <p>废物</p>
      </div>
      
  • 引用

    • 使用模板方式
      • th:include:包含模板
        • include 插入模板将 引用标签体全部替换
      • th:insert:插入模板
        • insert 插入模板时将内容都插入 引用的标签体内
<!-- 语法格式 -->
~{templatename :: selector} 或 templatename :: selector
<!-- 
templatename:模板所在的文件名,后缀可带可不带
selector:自定义的模板名
之间空格分隔
-->
示例
模板定义
  • head 和 end 两个模板
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>自定义 head 模板</title>
</head>
<body>
<div th:fragment="head">
    <p>name:二狗</p>
    <p>地址:泰国</p>
</div>

<div th:fragment="end">
    <p>end</p>
    <p>版权所有</p>
</div>

</body>
</html>
使用 th:insert
<!-- 使用:插入模板 -->
<h3>插入模板 th:insert </h3>
<div th:insert="head :: head">
    <!-- 或 ~{head :: head} -->
    两种方式使用模板:插入模板效果相同
</div>

<!-- 页面效果源码 -->
<h3>插入模板 th:insert </h3>
<!-- 保留原 div 标签 -->
<div>
    <!-- 整个模板内容插入 div 标签体内 -->
    <head>
    	<meta charset="UTF-8">
    	<title>自定义 head 模板</title>
    </head>
    <div>
    	<p>name:二狗</p>
    	<p>地址:泰国</p>
    </div>
</div>
<!-- 到此结束 -->
使用 th:include
<!-- 使用:包含模板 -->
<h3>包含模板 th:include </h3>
<div th:include="end :: end">
    包含模板使用
</div>

<!-- 页面效果源码 -->
<h3>包含模板 th:include </h3>
<!-- 模板内容整个替换掉标签体 -->
<div>
    <p>end</p>
    <p>版权:二狗所有,盗版必究</p>
</div>
使用整个文件作为模板
  • 使用 html 标签引用整个模板
<!-- 使用包含将整个文件引入 -->
<h3>使用整个文件作为模板</h3>
<div th:include="head :: html">
    包含模板使用
</div>

<!-- 页面效果源码 -->
<!-- 使用整个模板内容替换掉 div 标签体 -->
<div>
<head>
    <meta charset="UTF-8">
    <title>自定义 head 模板</title>
</head>
<body>
<div>
    <p>name:二狗</p>
    <p>地址:泰国</p>
</div>
<div>
    <p>end</p>
    <p>版权所有</p>
</div>
</body>
</div>
<!-- 使用 insert 插入模板时将内容都插入 div 标签体内 -->
使用其他目录模板
  • 使用 目录名/文件名 引用其他目录模板
  • <div th:include="目录名/文件名 :: 模板名">
<h3>引用其他目录模板 </h3>
<div th:insert="test/head :: head">
    <!-- 或 ~{head :: head} -->
两种方式使用模板:插入模板效果相同
</div>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值