快速导航
1 SpringBoot简介
1.1 SpringBoot四大核心
1.1.1 自动配置(常用)
1.1.2 起步依赖(常用)
1.1.3 Actuator(少用)
1.1.4 命令行界面(少用)
1.2 第一个SpringBoot程序
1.3 yaml入门详解
1.4 核心配置文件
- SpringBoot中只能有一个主核心配置文件且命名为application.properties,如果有子配置文件其命名因为 application-xxx.properties,若想生效其子配置文件,应在主核心配置文件加上以下
spring.profiles.active=xxx
2. SpringBoot框架web开发
2.1 SpringBoot集成jsp
2.1.1 思路
- 创建webapp目录来存放jsp页面。
- 添加SpringBoot内嵌Tomcat的依赖对jsp进行解析。
- SpringBoot工程指定了jsp文件编译的路径META-INF/resources
注:
SpringBoot内嵌的Tomcat是解析不了jsp,得添加依赖。
依赖包:
<!--springboot框架内嵌Tomcat对jsp解析的依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--加完其依赖后,指定其路径-->
<build>
resources>
<resource>
<!--指定源文件路径-->
<directory>src/main/webapp</directory>
<!--指定编译的路径-->
<targetPath>META-INF/resources</targetPath>
<includes>
<include>*.*</include>
</includes>
</resource>
<!--让resources不改变其路径-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
2.2 SpringBoot整合Mybatis案例
2.2.1 准备工作
2.2.2 思路分析
- 添加依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
- 配置数据库
#数据库配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/web_maven?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
#指定mapper映射文件路径
mybatis.mapper-locations=classpath:mapper/*.xml
- 利用mybatis逆向工程生成数据持久层和实体bean
GeneratorMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--指定连接数据库的JDBC驱动包所在的路径。绝对路径-->
<classPathEntry location="D:\apache-maven-3.6.3\repo\mysql\mysql-connector-java\5.1.30\mysql-connector-java-5.1.30.jar" />
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--关闭自动生成注解-->
<commentGenerator>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--配置数据库信息-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/web_maven"
userId="root"
password="123456">
</jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="true" />
</javaTypeResolver>
<!--生成实体类-->
<javaModelGenerator targetPackage="com.example.bean" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!--数据持久层-->
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.example.mapper" targetProject="src/main/java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!--tableName表的名称 domainObjectName实体类名称-->
<table schema="DB2ADMIN" tableName="t_student" domainObjectName="Student" >
</table>
</context>
</generatorConfiguration>
注:
-
在开发中如果有多个xxxmapper类,要在主程序类中添加@MapperScan(basePackages = “com.example.mapper”),如果是少量xxxmapper类可以加上注解@Mapper。个人建议使用扫包的方式!
-
xxxmapper类的映射文件xxxmapper.xml可以放在mapper类中,也可以方法resources包下。如果是放在resources包下需要再核心配置文件中指定其映射文件的路径。
2.3 SpringBoot事务支持
springboot事务底层依然采用着spring本身提供的事务管理。
- 在主程序类中使用注解@EnableTransactionManagement来开启事务。
- 在service实现类的事务方法上添加注解@Transactional。
2.4 SpringBoot下的Spring MVC常用注解
2.4.1 Controller
spring mvc的注解,处理http请求
推荐详解文章
2.4.2RestController
Spring 4后新增注解,是@Controller注解功能的增强。它是有@Controller和@ResponseBody的组合注解。如果一个Controller类添加了@RestController,那么该类下的所有方法都相当于都添加了@ResponseBody注解。它可以返回json格式数据。
2.4.3 RequestMapping
支持 Get 请求,也支持 Post 请求
2.4.4 GetMapping
- RequestMapping 和 Get 请求方法的组合
- 只支持 Get 请求
- Get 请求主要用于查询操作
2.4.5 PostMapping
- RequestMapping 和 Post 请求方法的组合
- 只支持 Post 请求
- Post 请求主要用户新增数据
2.4.6 PutMapping
- RequestMapping 和 Put 请求方法的组合
- 只支持 Put 请求
- Put 通常用于修改数据
2.4.7DeleteMapping
- RequestMapping 和 Delete 请求方法的组合
- 只支持 Delete 请求
- 通常用于删除数据
//RestController 注解相当于加了给方法加了@ResponseBody 注解,所以是不能跳转页面的,
只能返回字符串或者 json 数据
@RestController
public class MVCController {
@GetMapping(value = "/query")
public String get() {
return "@GetMapping 注解,通常查询时使用";
}
@PostMapping(value = "/add")
public String add() {
return "@PostMapping 注解,通常新增时使用";
}
@PutMapping(value = "/modify")
public String modify() {
return "@PutMapping 注解,通常更新数据时使用";
}
@DeleteMapping(value = "/remove")
public String remove() {
return "@DeleteMapping 注解,通常删除数据时使用";
}
}
2.5 SpringBoot实现RestFul
2.6 拓展知识
2.6.1 @RestController和Controller的区别
2.6.2 更换SpringBoot的logo图标
关闭logo标识,在主程序类中加入一下代码
SpringApplication springApplication = new SpringApplication(SpringbootTransactionalApplication.class);
//关闭logo标识
springApplication.setBannerMode(Banner.Mode.OFF);
springApplication.run(args);
更换logo
在 src/main/resources 放入 banner.txt 文件,该文件名字不能随意,文件中的内容就是要输出
的 logo ; 可 以 利 用 网 站 生 成 图 标 :https://www.bootschool.net/ascii 或 者http://patorjk.com/software/taag/,将生成好的图标文字粘贴到 banner.txt 文件中,运行就可以更换。
3. SpringBoot使用拦截器
3.1 Spring MVC自定义拦截器
springMVC拦截器的实现一般有两种方式
第一种方式是要定义的Interceptor类要实现了Spring的HandlerInterceptor 接口
第二种方式是继承实现了HandlerInterceptor接口的类,比如Spring已经提供的实现了HandlerInterceptor接口的抽象类HandlerInterceptorAdapter
HandlerInterceptor 接口中定义了三个方法,我们就是通过这三个方法来对用户的请求进行拦截处理的。
preHandle(): 这个方法在业务处理器处理请求之前被调用,SpringMVC 中的Interceptor 是链式的调用的,在一个应用中或者说是在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
postHandle():这个方法在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行。
afterCompletion():该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
下面来看我们的Interceptor类
第一种方式:
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//编写登录拦截业务逻辑
//返回 true 通过
//返回 false 被拦截
System.out.println("--------登录拦截器---------");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws
Exception {
} }
第二种方式:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class CommonInterceptor extends HandlerInterceptorAdapter{
private final Logger log = LoggerFactory.getLogger(CommonInterceptor.class);
public static final String LAST_PAGE = "lastPage";
/**
* 在业务处理器处理请求之前被调用
* 如果返回false
* 从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链
*
* 如果返回true
* 执行下一个拦截器,直到所有的拦截器都执行完毕
* 再执行被拦截的Controller
* 然后进入拦截器链,
* 从最后一个拦截器往回执行所有的postHandle()
* 接着再从最后一个拦截器往回执行所有的afterCompletion()
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if ("GET".equalsIgnoreCase(request.getMethod())) {
RequestUtil.saveRequest();
}
log.info("==============执行顺序: 1、preHandle================");
String requestUri = request.getRequestURI();
String contextPath = request.getContextPath();
String url = requestUri.substring(contextPath.length()); if ("/userController/login".equals(url)) {
return true;
}else {
String username = (String)request.getSession().getAttribute("user");
if(username == null){
log.info("Interceptor:跳转到login页面!");
request.getRequestDispatcher("/page/index.jsp").forward(request, response);
return false;
}else
return true;
}
}
/**
* 在业务处理器处理请求执行完成后,生成视图之前执行的动作
* 可在modelAndView中加入数据,比如当前时间
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("==============执行顺序: 2、postHandle================");
if(modelAndView != null){ //加入当前时间
modelAndView.addObject("haha", "测试postHandle");
}
}
/**
* 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等
* 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion()
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
log.info("==============执行顺序: 3、afterCompletion================");
}
}
spring-MVC.xml的相关配置
<!-- 对静态资源文件的访问-->
<mvc:resources mapping="/images/**" location="/images/"/>
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/js/**" location="/js/" />
<mvc:resources mapping="/favicon.ico" location="favicon.ico" />
<!--配置拦截器, 多个拦截器,顺序执行 -->
<mvc:interceptors>
<mvc:interceptor>
<!--
/**的意思是所有文件夹及里面的子文件夹
/*是所有文件夹,不含子文件夹
/是web项目的根目录
-->
<mvc:mapping path="/**" />
<!-- 需排除拦截的地址 -->
<!-- <mvc:exclude-mapping path="/userController/login"/> -->
<bean id="commonInterceptor" class="org.shop.interceptor.CommonInterceptor"></bean> <!--这个类就是我们自定义的Interceptor -->
</mvc:interceptor>
<!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->
</mvc:interceptors>
就这么简单SpringMVC拦截器写好了。
也可以在web.xml进行了对静态资源不拦截的配置
<!-- 不拦截静态文件 -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/js/*</url-pattern>
<url-pattern>/css/*</url-pattern>
<url-pattern>/images/*</url-pattern>
<url-pattern>/fonts/*</url-pattern>
</servlet-mapping>
3.2 SpringBoot使用拦截器
案例:
pojo类:
package com.example.pojo;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Controller类:
package com.example.controller;
import com.example.pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
public class IndexController {
/**
* 首页
* @return
*/
@RequestMapping(value = "/index")
public String Index(){
return "首页";
}
@RequestMapping(value = "/user/page/login")
public String LoginPage(){
return "Login Page";
}
/**
*无需用户登录
* @param request
* @return
*/
@RequestMapping(value = "/user/login")
public String Login(HttpServletRequest request){
User user = new User();
user.setId(1);
user.setName("李四");
request.getSession().setAttribute("user",user);
return "Logged";
}
/**
* 需要登录状态
* @return
*/
@RequestMapping(value = "/user/center")
public String Center(){
return "User Center";
}
}
@Configuration 定义配置类-拦截器:
在 项 目 中 创 建 一 个 config 包,创建 一 个 配 置 类SystemConfig , 并 实 现
WebMvcConfigurer 接口,
覆盖接口中的 addInterceptors 方法,并为该配置类添加
@Configuration 注解,标注此类为一个配置类,让 Spring Boot 扫描到,这里的操作就相当
于 SpringMVC 的注册拦截器 ,@Configuration 就相当于一个 applicationContext-mvc.xml。
package com.example.interceptor;
import com.example.pojo.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//拦截规则
//从session中获取用户信息
User user = (User) request.getSession().getAttribute("user");
//判断是否为空
if (null == user){
response.sendRedirect(request.getContextPath()+"/user/page/login");
return false;
}else {
return true;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
package com.example.config;
import com.example.interceptor.UserInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 配置类
*/
@Configuration
public class SystemConfig implements WebMvcConfigurer {
//定义需要拦截的路径
String [] addPathPatterns = {
"/user/**"
};
//定义不需要拦截的路径
String[] excludePathPatterns = {
"/user/login",
"/user/page/login",
};
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加要注册的拦截对象
registry.addInterceptor(new UserInterceptor())
.addPathPatterns(addPathPatterns)
.excludePathPatterns(excludePathPatterns);
}
}
4. SpringBoot使用Servlet
4.1 方式一:通过注解扫描方式实现
package com.example.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/myservlet")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//将请求、响应的编码均设置为UTF-8(防止中文乱码)
resp.setContentType("text/html;character=utf-8");
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().println("hello");
//把输出流立即发送到应答中
resp.getWriter().flush();
//关掉锁占用的资源,避免资源占用内存过多,导致一些内存溢出,或者服务器慢,最后没有响应最终挂掉。
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan(basePackages = "com.example.servlet")
public class SpringbootServlet01Application {
public static void main(String[] args) {
SpringApplication.run(SpringbootServlet01Application.class, args);
}
}
4.2 方式二:SpringBoot配置类实现
servlet类
package com.example.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("Hello SpringBoot Servlet");
resp.getWriter().flush();
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
config类:
package com.example.config;
import com.example.servlet.MyServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
//@Bean 是一个方法级别上的注解,主要用在配置类里
/*
* 相当于一个<beans>
* <bean id="" class=""/>
* </beans>
*
*/
@Bean
public ServletRegistrationBean myServletRegistrationBean(){
//方式一:可以设置对个访问路径
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/servlet1","/servlet2");
//方式二:
registrationBean.addUrlMappings("servlet3");
return registrationBean;
}
}
5. SpringBoot使用Filter
5.1 通过注解扫描方式实现
filter类:
package com.example.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/filter")
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);
}
}
主程序类:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan(basePackages ="com.example.filter")
public class SpringbootFilterApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootFilterApplication.class, args);
}
}
5.2 SpringBoot配置类实现
filter类:
package com.example.filter;
import javax.servlet.*;
import java.io.IOException;
public class MyFilter2 implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("==========通过过滤器============");
filterChain.doFilter(servletRequest,servletResponse);
}
}
config类:
package com.example.config;
import com.example.filter.MyFilter2;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
@Configuration
public class MyConfig {
@Bean
public FilterRegistrationBean myFilterRegistrationBean(){
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.addUrlPatterns("/filter2");
registrationBean.setFilter(new MyFilter2());
return registrationBean;
}
}
6. SpringBoot项目设置字符编码
6.1 使用Spring提供的字符编码过滤器(如果需要改字符编码,推荐使用这种)
servlet类
package com.example.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/servlet1")
public class EncodingServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置浏览器
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().println("张三李四王五");
resp.getWriter().close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
config类:
package com.example.config;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CharacterEncodingFilter;
import javax.servlet.Filter;
@Configuration
public class EncodingConfig {
@Bean
public FilterRegistrationBean myconfig(){
//设置字符编码过滤器
//CharacterEncoding 是由Spring提供的一个字符编码过滤器,在SSM中是配置在web.xml中
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
//强制使用指定字符编码
encodingFilter.setForceEncoding(true);
//设置字符编码
encodingFilter.setEncoding("utf-8");
//创建过滤器注册bean
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
//设置字符编码过滤器
filterRegistrationBean.setFilter(encodingFilter);
//过滤的路径
filterRegistrationBean.addUrlPatterns("/**");
return filterRegistrationBean;
}
}
主程序类:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan(basePackages = "com.example.servlet")
public class SpringbootEncodingApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootEncodingApplication.class, args);
}
}
7. SpringBoot集成Thymeleaf
7.1 简介
Thymeleaf 是一个流行的模板引擎,该模板引擎采用 Java 语言开发
模板引擎是一个技术名词,是跨领域跨平台的概念,在 Java 语言体系下有模板引擎,
在 C#、PHP 语言体系下也有模板引擎,甚至在 JavaScript 中也会用到模板引擎技术,Java 生
态下的模板引擎有 Thymeleaf 、Freemaker、Velocity、Beetl(国产)等。
Thymeleaf 对网络环境不存在严格的要求,既能用于 Web 环境下,也能用于非 Web 环
境下。在非 Web 环境下,他能直接显示模板上的静态数据;在 Web 环境下,它能像 Jsp 一
样从后台接收数据并替换掉模板上的静态数据。它是基于 HTML 的,以 HTML 标签为载体,
Thymeleaf 要寄托在 HTML 标签下实现。
SpringBoot 集成了 Thymeleaf 模板技术,并且 Spring Boot 官方也推荐使用 Thymeleaf 来
替代 JSP 技术,Thymeleaf 是另外的一种模板技术,它本身并不属于 Spring Boot,Spring Boot
只是很好地集成这种模板技术,作为前端页面的数据展示,在过去的 Java Web 开发中,我
们往往会选择使用 Jsp 去完成页面的动态渲染,但是 jsp 需要翻译编译运行,效率低
7.2 第一个程序
- 先创建SpringBoot项目
- 在application.xml核心配置文件中对Thymeleaf进行配置
#设置Thyeleaf页面缓存开关,默认为true为开启缓存,建议关闭
spring.thymeleaf.cache=false
- 创建controller类
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class IndexController {
@RequestMapping(value = "/index")
public String index(Model model){
model.addAttribute("data","SpringBoot集成thymeleaf");
return "index";
}
}
- 创建其index页面,在html标签中加入xmlns:th="http://www.thymeleaf.org",才能使用其tymeleaf模板。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${data}"></h1>
<p th:text="${data}"></p>
<span th:text="${data}"> </span>
</body>
</html>
7.3 Thymeleaf表达式
7.3.1 标准变量表达式
注意 th:text=""是thymeleaf的一个属性,用于文本的显示。
语法:${…}
说明:标准变量表达式用于访问容器(tomcat)上下文环境中的变量,功能和 EL 中的 ${} 相
同。Thymeleaf 中的变量表达式使用 ${变量名} 的方式获取 Controller 中 model 其中的数据
案例分析:
创建pojo包中创建User类
package com.example.pojo;
import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String userName;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
在controller包创建UserController类
package com.example.controller;
import com.example.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
@RequestMapping(value = "/thymeleaf/user")
public String user(Model model){
User user = new User();
user.setId(1001);
user.setUserName("李四");
model.addAttribute("user",user);
return "user";
}
}
**在 templates 目录下创建 user.html 页面获取 User 对象数据
**
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>标准变量表达式和选择变量表达式</title>
</head>
<body>
<h1>标准变量表达式:${...}</h1>
<div>
用户编号: <span th:text="${user.id}"></span><br>
用户姓名: <span th:text="${user.userName}"></span>
</div>
</body>
</html>
7.3.2 选择变量表达式(了解)
语法: *{…}
说明:
选择变量表达式,也叫星号变量表达式,使用 th:object 属性来绑定对象
选择表达式首先使用 th:object 来绑定后台传来的 User 对象,然后使用 * 来代表这个对
象,后面 {} 中的值是此对象中的属性。
选择变量表达式 *{…} 是另一种类似于标准变量表达式
.
.
.
表
示
变
量
的
方
法
<
b
r
/
>
选
择
变
量
表
达
式
在
执
行
时
是
在
选
择
的
对
象
上
求
解
,
而
{...} 表示变量的方法 <br />选择变量表达式在执行时是在选择的对象上求解,而
...表示变量的方法<br/>选择变量表达式在执行时是在选择的对象上求解,而{…}是在上下文的变量 Model 上求
解,这种写法比标准变量表达式繁琐。
案例分析:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>标准变量表达式和选择变量表达式</title>
</head>
<body>
<h1>标准变量表达式:${...}</h1>
<div>
用户编号: <span th:text="${user.id}"></span><br>
用户姓名: <span th:text="${user.userName}"></span>
</div>
<h2>选择变量表达式或者星号表达式:*{...}</h2>
<div th:object="${user}">
用户编号: <span th:text="*{id}"></span><br>
用户姓名: <span th:text="*{userName}"></span>
</div>
</body>
</html>
7.3.3 标准和选择变量表达式混用
案例分析:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>标准变量表达式和选择变量表达式</title>
</head>
<body>
<h1>标准变量表达式:${...}</h1>
<div>
用户编号: <span th:text="${user.id}"></span><br>
用户姓名: <span th:text="${user.userName}"></span>
</div>
<h2>选择变量表达式或者星号表达式:*{...}</h2>
<div th:object="${user}">
用户编号: <span th:text="*{id}"></span><br>
用户姓名: <span th:text="*{userName}"></span>
</div>
<h3>混合使用</h3>
<div>
用户编号: <span th:text="*{user.id}"></span><br>
用户姓名: <span th:text="${user.userName}"></span>
</div>
</body>
</html>
7.3.4 URL表达式
语法:@{…}
说明:主要用于链接、地址的展示,可用于<script src="...">、<link href="...">、<a href="...">、<form action="...">、<img src="">等,可以在 URL 路径中动态获取数据
案例分析:
controller类
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class IndexController {
@RequestMapping(value = "/index")
public String index(Model model){
model.addAttribute("id","8888");
return "index";
}
@RequestMapping(value = "/index2")
public @ResponseBody String index2(Integer id){
return "Hello ,baidu";
}
@RequestMapping(value = "index3")
public @ResponseBody Object index3(){
return "Index3";
}
}
index.html页面:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>URL路径表达式</title>
</head>
<body>
<h1>URL表达式语法: @{...}</h1>
<span>绝对路径</span>
<a href="https://www.baidu.com">传统方式:百度</a>
<a th:href="@{https://www.baidu.com}">绝对路径表达式</a>
<h2>内部路径从后台获取参数</h2>
<a href="">传统方式不能获取</a>
<a th:href="@{'http://localhost:8080/index2?id='+${id}}">使用路径表达式:内部系统的绝对路径(有参数:后台获取)</a>
<h2>相对路径(没有参数)</h2>
<!--如果有上下文根,默认的传统写法会出现问题,而无论有没有,URL表达式都不会出现问题-->
<a href="/index3">传统写法</a>
<a th:href="@{/index3}">URL表达式:相对路径</a>
<h1>相对路径推荐写法(后台获取多个参数为例)</h1>
<!--括号里面填写多个参数,参数之间用逗号隔开-->
<a th:href="@{/index2(id=${id})}"></a>
</body>
</html>
7.4 常见的属性
7.4.1 th:each 遍历
它与
JSTL 中的<c: forEach>类似,此属性既可以循环遍历集合,也可以循环遍历数组及 Map
7.4.1.1 遍历List集合
案例分析:
controller类
package com.example.controller;
import com.example.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.ArrayList;
@Controller
public class IndexController {
@RequestMapping(value = "/each/list")
public String eachList(Model model){
ArrayList<User> userList = new ArrayList<>();
for (int i = 0;i < 10;i++){
User user = new User();
user.setId(100+i);
user.setUsername("张三"+i);
user.setPhone("1357455758"+i);
user.setAddress("广州天河区"+i+"号");
userList.add(user);
}
model.addAttribute("userList",userList);
return "eachList";
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>List集合遍历</title>
</head>
<body>
<div style="color: red">
1.user:当前对象的变量名<br/>
2.userStat:当前对象的状态变量名;自定义变量名,可以不写<br/>
3.${userList}:循环遍历的集合<br/>
4.变量名自定义
</div>
<div th:each="user,UserStat:${userList}">
<span th:text="${UserStat.count}"></span>
<span th:text="${user.id}"></span>
<span th:text="${user.username}"></span>
<span th:text="${user.phone}"></span>
<span th:text="${user.address}"></span>
</div>
</body>
</html>
注意:循环体信息 interStat 也可以不定义,则默认采用迭代变量加上 Stat 后缀,即 userStat
serStat
。
7.4.1.2 遍历Map集合
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>循环遍历Map集合</title>
</head>
<body>
<div th:each="user,UserMapStat:${hashMap}">
Key:<span th:text="${user.key}"></span>
Value: <span th:text="${user.value}"></span>
<p>以下是详细信息</p>
<p th:text="${user.value.id}"></p>
<p th:text="${user.value.username}"></p>
<p th:text="${user.value.phone}"></p>
<p th:text="${user.value.address}"></p>
<br>
</div>
</body>
</html>
7.4.1.3 遍历Array数组
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>遍历数组</title>
</head>
<body>
<div th:each="userArray:${users}">
<span th:text="${userArray.id}"></span>
<span th:text="${userArray.username}"></span>
<span th:text="${userArray.phone}"></span>
<span th:text="${userArray.address}"></span>
</div>
</body>
</html>
7.4.1.4 复杂案例
List里面包含Map,Map里面有List,List里面有User。
Controller类:
@RequestMapping(value = "/each/all")
public String IndexALL(Model model){
//List--》Map--》List--》user
List<Map<Integer, List<User>>> MyList = new ArrayList<>();
for (int i = 0; i < 2; i++){
Map<Integer, List<User>> listHashMap = new HashMap<>();
for (int j = 0;j < 2;j++){
List<User> userArrayList = new ArrayList<>();
for (int k = 0;k < 3;k++){
User user = new User();
user.setId(k);
user.setUsername("刘能"+k);
user.setPhone("1248451251"+k);
user.setAddress("广州市"+i);
userArrayList.add(user);
}
listHashMap.put(j,userArrayList);
}
MyList.add(listHashMap);
}
model.addAttribute("MyList",MyList);
return "eachAll";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>复杂案例</title>
</head>
<body>
<div th:each="myListMaps:${MyList}">
<div th:each="myListMap:${myListMaps}">
<span th:text="${myListMap.key}"></span>
<span th:text="${myListMap.value}"></span>
<div th:each="user:${myListMap.value}">
<p th:text="${user.id}"></p>
<p th:text="${user.username}"></p>
<p th:text="${user.phone}"></p>
<p th:text="${user.address}"></p>
</div>
<br>
</div>
</div>
</body>
</html>
7.4.2 条件判断
controller类
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ConditionController {
@RequestMapping(value = "/condition")
public String Condition(Model model){
model.addAttribute("sex","1");
model.addAttribute("status","2");
return "eachCondition";
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>条件判断</title>
</head>
<body>
<div th:if="${sex == '1'}">男</div>
<h1>th:unless是对th:if结果的取反</h1>
<div th:unless="${sex != '1'}">男</div>
<h2>属性: th:switch</h2>
<div th:switch="${status}">
<span th:case="1">未提交未审核</span>
<span th:case="2">已提交已审核</span>
<!--th:case="*"未找到符合的条件-->
<span th:case="*">状态未知</span>
</div>
</body>
</html>
7.4.3 内敛表达式
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>内敛表达式</title>
</head>
<body>
<h1>内敛文本表达式:th:inline="text"</h1>
<div th:inline="text">
学生编号:[[${student.id}]]<br>
学生姓名:[[${student.stuname}]]
</div>
<script type="text/javascript" th:inline="javascript">
/*内敛脚本表达式*/
alert("学生编号:"+[[${student.id}]]+"学生姓名:"+[[${student.stuname}]])
</script>
</body>
</html>