SpringBoot 中不推荐使用 JSP
使用 JSP 需要配置后才能使用
添加处理 jsp 的依赖
<dependency>
<groupId>org.apache.tomcat.embedgroupId>
<artifactId>tomcat-embed-jasperartifactId>
dependency>
若要使用 servlet、jsp 、jstl 等的功能也需要添加相关依赖
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>javax.servlet.jsp-apiartifactId>
<version>2.3.1version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
dependency>
创建存放 jsp 的目录,一般为 webapp,设为项目中 jsp 资源目录
index.jsp在 pom.xml 文件指定 jsp 文件编译后存放的目录
webapp 目录下所有文件编译到 target 目录下 META-INF/resources 目录
<resources>
<resource>
<directory>src/mian/webappdirectory>
<targetPath>META-INF/resourcestargetPath>
<includes>
<include>**/*.*include>
includes>
resource>
resources>
创建 Controller 访问 jsp
方法参数 HttpRequest 或 Model 对象来返回数据
@RequestMapping
public String doOther(Model model){
//将数据放到 request 作用域;等价于 request.setAttribute()
model.addAttribute("data", "废物");
//返回 index.jsp 页面,页面的逻辑名,由视图解析器包装为完整视图
return "index";
}
在 application.properties 文件中配置视图解析器
# 配置视图解析器
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.jsp
通过 Maven 依赖导入 jar 包
/META-INF/resources/webjars 路径找到静态资源WebJars 是将 web 前端资源(如:jQuery、Bootstrap)打成 jar 包文件
加载 staticPathPattern = "/**" 路径
默认到以下四个资源目录中查找静态资源:按优先级顺序排列
"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/":默认生成目录
"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}]
在 SpringBoot 中对 MVC 有默认的支持实现
创建类实现不同的 mvc 组件接口以自定义拓展组件功能
创建 MVC 配置类实现 WebMvcConfigurer 接口,此类就是 mvc 的配置类
@EnableWebMvc 注解
@Import({DelegatingWebMvcConfiguration.class})
WebMvcConfigurationSupportWebAutoMvcConfigurer 自动装配失效
WebMvcAutoConfiguration 自动配置类生效需要所有配置类中不存在 WebMvcConfigurationSupport.class自定义拦截器使用
创建类实现 HandlerInterceptor 接口
在 SpringMVC 配置文件中声明拦截器
<mvc:interceptors>
<mvc:interceptor>
<bean class="拦截器全限定名">
mvc:interceptor>
mvc:interceptors>
HandlerInterceptor 接口WebMvcConfigurer 接口
@Configuration 使此类作为配置类作为配置类addInterceptors 方法注册拦截器
// 拦截器定义
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
MyServlet 类继承 HttpServlet
doGet()、doPost() 方法处理请求servlet 对象
@Configuration 作为配置类使用ServletRegistrationBean 对象ServletRegistrationBean 对象注册 myServlet
@Bean 将对象存放到容器// 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 bean = new ServletRegistrationBean<>();
bean.setServlet(servlet);
bean.addUrlMappings("/myServlet", "/doSome", "/doOther");
return bean;
*/
}
}
Filter 是 Servlet 中的过滤器
可以处理请求:对请求的参数、属性进行调整
常在过滤器中处理字符编码
自定义使用 Filter,类似 servlet 的步骤
Filter
doFilter()@Configuration@BeanFilterRegistratonBean<>filter 对象注册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);
// 添加过滤请求,相当于 标签
bean.addUrlPatterns("/*");
return bean;
}
}
CharacterEncodingFilter:字符集过滤器
ISO-8859-1encoding:当前使用的编码方式forceRequestEncoding:默认 false,不使用当前编码forceResponseEncoding:默认 false,不使用当前编码直接在过滤器配置类中创建 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;
}
}
修改配置文件
# 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@Beantemplates 目录下创建 error 目录Thymeleaf 模板
Thymeleaf、Freemaker、Velocity、Beetl(国产) 等Thymeleaf 对网络环境没有严格要求
SpringBoot 集成了 Thymeleaf 模板技术
创建 SpringBoot 项目添加 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}":标准变量表达式
tx:text="${key}"接收替换数据
th:test="":Thymeleaf 的属性,用于文本显示reque st.setAttribute(key, value); 添加数据model.addAttribute(key, value);
<p th:text="${key}">正常的静态数据p>
<body>
<h1>标准变量表达式 ${} h1>
<h2 th:text="${data}">全部信息h2>
<div>
<h3>id = h3><h3 th:text="${data.id}">idh3><br/>
<h3>name = h3><h3 th:text="${data.name}">idh3><br/>
<h3>age = h3><h3 th:text="${data.getAge()}">idh3><br/>
<h3>date = h3><h3 th:text="${data.getDate()}">idh3><br/>
div>
body>
*{key}th:text="*{}":选择变量表达式
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>
<div th:object="${data}">
<h3>id = h3><h3 th:text="*{id}">idh3><br/>
<h3>name = h3><h3 th:text="*{name}">nameh3><br/>
<h3>age = h3><h3 th:text="*{getAge()}">ageh3><br/>
<h3>date = h3><h3 th:text="*{getDate()}">dateh3><br/>
div>
<h3>ageh3><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>
<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>
th
th 之后经过模板引擎处理 标签的 action 属性<form id="login" th:action="@{/login}" th:method="post">form>
设置请求的方法
<form id="login" th:action="@{/login}" th:method="post">form>
定义超链接,结合 URL 表达式获取动态变量
<a th:href="@{do3/(id=${id})}">单个参数a>
标签的 src 属性、![]()
标签的 src 属性@{} 表达式结合使用static 目录
<script type="text/javascript" th:src="@{/js/jquery-3.4.1.js}">script>
th:value<input type="text" id="reakName" name="realName" th:text="${realName}">
设置样式
<a th:onclick="'fun1(' + ${user.id} + ')'" th:style="'color:red'">点击a>
循环遍历
类似th:each="demo,demoStat:${Demo}"
demo:${Demo},默认循环体信息 demoStatth:text=${demo} 接收循环变量<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>
<tr th:each="demo:${Demo}">
<td th:text="${demo.getId()}">idtd>
<td th:text="${demo.getName()}">nametd>
<td th:text="${demo.age}">agetd>
<td th:text="${demo.date}">datetd>
tr>
tbody>
table>
<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}">
<td th:text="${mapStat.count} + '/' + ${mapStat.size}">td>
<td th:text="${map.key}">td>
<td th:text="${map.value.id}">idtd>
<td th:text="${map.value.name}">nametd>
<td th:text="${map.value.getAge()}">agetd>
<td th:text="${map.value.getDate()}">datetd>
tr>
tbody>
table>
<table th:border="1" th:cellpadding="5" th:cellspacing="0">
<thead>
<tr>
<td> 编号td>
<td> keytd>
<td> idtd>
<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="boolean 条件"
th:“${name}”:name 只要不是 null 就显示内容th:if${name == null}才会显示内容th:unless是 th:if的相反操作<div th:if="true">显示文本内容div>
<div th:unless="false">显示文本内容div>
<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>
<div th:switch="${key}">
<p th:case="value1">结果1p>
<p th:case="value2">结果2p>
<p th:case="*">默认值p>
div>
<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>
text、javascript、none可以让 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>
<head>
<meta charset="UTF-8">
<title>内联 inLinetitle>
<script type="text/javascript" th:inline="javascript">
function fun(){
alert([[${data}]]);
}
script>
head>
<body>
<h2>测试 javascript 使用 inlineh2>
<input type="button" name="btn" value="单机获取数据" onclick="fun()">
body>
在模板文件中直接写,可以正常显示
文本字面量:'' 包围的字符串
null数字、布尔值、null 字面量直接使用
<h2>测试字面量h2>
<div>
<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>
'' 将静态字符串包裹,使用 + 连接动态数据|| 包裹字符串和表达式
<h3 th:text="'正常显示文本字面量' + ';动态数据 name = ' + ${name}">姓名h3>
<h3 th:text="|正常显示,拼接数据 name = ${name}|">姓名h3>
+ - * / %
div(除)、mod(求余)>、<、>=、<=
gt、lt、ge、le==、!=
eq、ne... ? ... : ...<div>
<p th:text="${ 20 > 10}">xtruep>
<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
HttpSessionsession 表示 Map 对象
#session 的简化形式,获取 session 中指定 key 的值session.getSession 等价 session.getAttribute("getSession")param:表示参数对象
application:servletContext//添加数据
@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>
<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/>
name的参数值 <span th:text="${param.name}">span><br/>
参数的数量 <span th:text="${param.size}">span><br/>
# ,一般都以 s 结尾
<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()}">
<p th:text="${#numbers.formatCurrency(doubleNum)}">p>
<p th:text="${#numbers.formatDecimal(doubleNum, 5, 2)}">p>
<p th:text="${#strings.toUpperCase(string)}">
<p th:text="${#strings.indexOf(string, 'gg')}">
<p th:text="${#strings.substring(string, 3, 6)}">
<p th:if="!${#lists.contains(list, demo)}">存在成员p>
<p th:text="${#lists.size(list)}">p>
<p th:text="${#lists.isEmpty(list)}">p>
th:text=“demo?.name”:引用 demo 对应的对象的 name 属性
?:询问前面对象是否为 null
null 时正常处理null 不执行后面的语句
<p th:text="${demo.name}">p>
<p th:text="${demo}">p>
<p th:text="${demo?.name}">p>
name=<p th:text="${demo1.name}">namep>
定义
th:fragment="自定义模板名"
<div th:fragment="demo">
<p>测试模板p>
<p>废物p>
div>
引用
th:include:包含模板
th:insert:插入模板
~{templatename :: selector} 或 templatename :: selector
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>endp>
<p>版权所有p>
div>
body>
html>
<h3>插入模板 th:insert h3>
<div th:insert="head :: head">
两种方式使用模板:插入模板效果相同
div>
<h3>插入模板 th:insert h3>
<div>
<head>
<meta charset="UTF-8">
<title>自定义 head 模板title>
head>
<div>
<p>name:二狗p>
<p>地址:泰国p>
div>
div>
<h3>包含模板 th:include h3>
<div th:include="end :: end">
包含模板使用
div>
<h3>包含模板 th:include h3>
<div>
<p>endp>
<p>版权:二狗所有,盗版必究p>
div>
html 标签引用整个模板
<h3>使用整个文件作为模板h3>
<div th:include="head :: html">
包含模板使用
div>
<div>
<head>
<meta charset="UTF-8">
<title>自定义 head 模板title>
head>
<body>
<div>
<p>name:二狗p>
<p>地址:泰国p>
div>
<div>
<p>endp>
<p>版权所有p>
div>
body>
div>
目录名/文件名 引用其他目录模板
<h3>引用其他目录模板 h3>
<div th:insert="test/head :: head">
两种方式使用模板:插入模板效果相同
div>
- 1
- 2
- 3
- 4
- 5