SpringBoot3---核心特性---2、Web开发III(模板引擎、国际化、错误处理)

星光下的赶路人star的个人主页
夏天就是吹拂着不可预期的风
文章目录
- 1、模板引擎
- 1.1 Thymeleaf
- 1.2 基础语法
- 1.3 属性设置
- 1.4 遍历
- 1.5 判断
- 1.6 属性优先级
- 1.7 行内写法
- 1.8 变量选择
- 1.9 模板布局
- 1.10 devtools
- 2、国家化
- 3、错误处理
- 3.1 默认机制
- 3.2 自定义错误响应
- 3.3 最佳实战
1、模板引擎
- 由于SpringBoot使用了嵌入式Servlet容器。所以JSP默认是不能使用的。
- 如果需要服务端页面渲染,优先考虑使用模板引擎。

模板引擎页面默认放在src/main/resources/templates
SpringBoot包含以下模板引擎的自动配置
- FreeMarker
- Groovy
- Thymeleaf
- Mustache
Thymeleaf官网:https://www.thymeleaf.org/
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><title>Good Thymes Virtual Grocery</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><link rel="stylesheet" type="text/css" media="all" th:href="@{/css/gtvg.css}" />
</head>
<body><p th:text="#{home.welcome}">Welcome to our grocery store!</p>
</body
</html>
1.1 Thymeleaf
导入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
自动配置原理
1、开启了org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration 自动配置。
2、属性绑定在ThymeleafProperties中,对应配置文件spring.thymeleaf内容
3、所以的模板页面默认在classpath:/templates文件夹下
4、默认效果
-
- a、所有的模板页面在/classpath:/templates/下面找
-
- b、找后缀名为.html的页面
1.2 基础语法
1、核心用法
th:xxx:动态渲染指定的html标签属性值、或者th指令(遍历、判断等)
- th:text:标签体内文本值渲染
-
- thutext:不会转义,显示为html原本的样子
- th:属性:标签指定属性渲染
- th:attr:标签任意属性渲染
- th:if、th:each、…:其他th指令
- 例如
<p th:text="${content}">原内容</p>
<a th:href="${url}">登录</a>
<img src="../../images/gtvglogo.png" th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />
表达式:用来动态取值
- ${}:变量取值:使用model共享给页面的值都直接用${}
- @{}:url路径
- #{}:国际化消息
- ~{}:片段引用
- *{}:变量选择:需要配置th:object不到对象
系统工具&内置对象:详细文档
● param:请求参数对象
● session:session对象
● application:application对象
● #execInfo:模板执行信息
● #messages:国际化消息
● #uris:uri/url工具
● #conversions:类型转换工具
● #dates:日期工具,是java.util.Date对象的工具类
● #calendars:类似#dates,只不过是java.util.Calendar对象的工具类
● #temporals: JDK8+ java.time API 工具类
● #numbers:数字操作工具
● #strings:字符串操作
● #objects:对象操作
● #bools:bool操作
● #arrays:array工具
● #lists:list工具
● #sets:set工具
● #maps:map工具
● #aggregates:集合聚合工具(sum、avg)
● #ids:id生成工具
2、语法示例
表达式:
- 变量取值:${…}
- url取值:@{…}
- 国际化消息:#{…}
- 变量选择:*{…}
- 片段引用:~{…}
常见:
- 文本:‘one text’,‘another one’…
- 数字:0,34,…
- 布尔:true,false
- null:null
- 变量名:one,sometext,main,…
文本操作:
- 拼串:+
- 文本替换:|The name is ${name}|
布尔操作
- 二进制运算:and,or
- 取反:!,not
比较运算
- 比较:>,<,<=,>=(gt,lt,ge,le)
- 等值运算:=,!=
条件运算
- if-then :(if)?(then)
- if-then-else:(if)?(then):(else)
特殊操作
- 无操作
所有以上都可以嵌套组合
'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))
1.3 属性设置
- th:href=“@{/product/list}”
- th:attr=“class=${active}”
- th:attr=“src=@{/images/gtvglogo.png},title=${logo},alt=#{logo}”
- th:checked=“${user.active}”
<p th:text="${content}">原内容</p>
<a th:href="${url}">登录</a>
<img src="../../images/gtvglogo.png" th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />
1.4 遍历
语法:th:each=“元素名,迭代状态:${集合}”
<tr th:each="prod : ${prods}"><td th:text="${prod.name}">Onions</td><td th:text="${prod.price}">2.41</td><td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr><tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'"><td th:text="${prod.name}">Onions</td><td th:text="${prod.price}">2.41</td><td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
iterStat有以下属性:
● ndex:当前遍历元素的索引,从0开始
● count:当前遍历元素的索引,从1开始
● size:需要遍历元素的总数量
● current:当前正在遍历的元素对象
● even/odd:是否偶数/奇数行
● first:是否第一个元素
● last:是否最后一个元素
1.5 判断
th:if
<ahref="comments.html"th:href="@{/product/comments(prodId=${prod.id})}"th:if="${not #lists.isEmpty(prod.comments)}">view</a
th:switch
<div th:switch="${user.role}"><p th:case="'admin'">User is an administrator</p><p th:case="#{roles.manager}">User is a manager</p><p th:case="*">User is some other thing</p>
</div>
1.6 属性优先级
- 判断
- 遍历
- 判断
<ul><li th:each="item : ${items}" th:text="${item.description}">Item description here...</li>
</ul>
Order Feature Attributes
1 片段包含 th:insert th:replace
2 遍历 th:each
3 判断 th:if th:unless th:switch th:case
4 定义本地变量 th:object th:with
5 通用方式属性修改 th:attr th:attrprepend th:attrappend
6 指定属性修改 th:value th:href th:src …
7 文本值 th:text th:utext
8 片段指定 th:fragment
9 片段移除 th:remove
1.7 行内写法
[[…]] or [(…)]
<p>Hello, [[${session.user.name}]]!</p>
1.8 变量选择
<div th:object="${session.user}"><p>Name: <span th:text="*{firstName}">Sebastian</span>.</p><p>Surname: <span th:text="*{lastName}">Pepper</span>.</p><p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
</div>
等同于
<div><p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p><p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p><p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p>
</div
1.9 模板布局
- 定义模板:th:fragment
- 引用模板:~{templatename::selector}
- 插入模板:th:insert、th:replace
<footer th:fragment="copy">© 2011 The Good Thymes Virtual Grocery</footer><body><div th:insert="~{footer :: copy}"></div><div th:replace="~{footer :: copy}"></div>
</body>
<body>结果:<body><div><footer>© 2011 The Good Thymes Virtual Grocery</footer></div><footer>© 2011 The Good Thymes Virtual Grocery</footer></body>
</body>
1.10 devtools
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency>
修改页面后;ctrl+F9刷新效果;
java代码的修改,如果devtools热启动了,可能会引起一些bug,难以排查
2、国家化
国际化的自动配置参照MessageSourceAutoConfiguration
实现步骤:
1、Spring Boot在类路径根下查找messages资源绑定文件。文件名为:message.properties.
2、多语言可以定义多个消息文件,命名为message_区域代码.properties。如:
- messages.properties:默认
- messages_zh_CN.properties:中文环境
- messages_en_US.properties:英文环境
3、在程序中自动注入MessageSource组件,获取国际化的配置项值
4、在页面中可以使用表达式#{}获取国际化的配置项值
@Autowired //国际化取消息用的组件MessageSource messageSource;@GetMapping("/haha")public String haha(HttpServletRequest request){Locale locale = request.getLocale();//利用代码的方式获取国际化配置文件中指定的配置项的值String login = messageSource.getMessage("login", null, locale);return login;}
3、错误处理
3.1 默认机制
错误处理的自动配置都在ErrorMvcAutoConfiguration中,两大核心机制:
- SpringBoot会自适应处理错误,响应页面或JSON数据
- SpringMVC的错位处理机制依然保留,MVC处理不了,才会交给Boot进行处理

- 发送错误以后,转发给/error路径,SpringBoot在底层写好应该BasicErrorController,专门处理这个请求
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE) //返回HTMLpublic ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {HttpStatus status = getStatus(request);Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));response.setStatus(status.value());ModelAndView modelAndView = resolveErrorView(request, response, status, model);return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);}@RequestMapping //返回 ResponseEntity, JSONpublic ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {HttpStatus status = getStatus(request);if (status == HttpStatus.NO_CONTENT) {return new ResponseEntity<>(status);}Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));return new ResponseEntity<>(body, status);}
- 错误页面是这么解析的
//1、解析错误的自定义视图地址
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
//2、如果解析不到错误页面的地址,默认的错误页就是 error
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
容器中专门有一个错误视图解析器
@Bean
@ConditionalOnBean(DispatcherServlet.class)
@ConditionalOnMissingBean(ErrorViewResolver.class)
DefaultErrorViewResolver conventionErrorViewResolver() {return new DefaultErrorViewResolver(this.applicationContext, this.resources);
}
SpringBoot解析自定义错误页的默认规则
@Overridepublic ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);}return modelAndView;}private ModelAndView resolve(String viewName, Map<String, Object> model) {String errorViewName = "error/" + viewName;TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,this.applicationContext);if (provider != null) {return new ModelAndView(errorViewName, model);}return resolveResource(errorViewName, model);}private ModelAndView resolveResource(String viewName, Map<String, Object> model) {for (String location : this.resources.getStaticLocations()) {try {Resource resource = this.applicationContext.getResource(location);resource = resource.createRelative(viewName + ".html");if (resource.exists()) {return new ModelAndView(new HtmlResourceView(resource), model);}}catch (Exception ex) {}}return null;}
容器中有一个默认的名为error的view;提供了默认白页功能
@Bean(name = "error")
@ConditionalOnMissingBean(name = "error")
public View defaultErrorView() {return this.defaultErrorView;
}
封装了JSON格式的错误信息
@Bean@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)public DefaultErrorAttributes errorAttributes() {return new DefaultErrorAttributes();}
规则:
1、解析一个错误页
(1)如果发生了500、404、503、403这些错误
- 如果有模板引擎,默认在classpath:/templates/error/精确码.html
- 如果没有模板引擎,在静态资源文件夹下找精确码.html
(2)如果匹配不到精确码.html这些精确的错误页,就去找5xx.html,4xx.html模糊匹配 - 如果有模板引擎,默认在classpath:/template/error/5xx.html
- 如果没有模板引擎,在静态资源目录下找5xx.html
2、如果模板引擎路径templates下有error.html页面,就直接去渲染
3.2 自定义错误响应
1、自定义json响应
使用@ControllerAdvice+@ExceptionHandler进行统一异常处理
2、自定义页面响应
根据boot的错误页面规则,自定义页面模板
3.3 最佳实战
- 前后分离
-
- 后台发生的所有错误,@ControllerAdvice+@Exceptionhandler进行统一异常处理
- 服务端页面渲染
-
- 不可预知的一些,HTTP码表示的服务器或客户端错误
-
-
- 给classpath:/templates/error/下面,放常用精确的错误码页面。500.html,404.html
-
-
- 发生业务错误
-
-
- 核心业务,每一种错误,都应该代码控制,跳转到自己定制的错误页
-
-
-
- 通用业务,classpath:/templates/error.html页面,显示错误信息
-
页面,JSON,可用的Model数据如下

![]()
您的支持是我创作的无限动力
![]()
希望我能为您的未来尽绵薄之力
![]()
如有错误,谢谢指正;若有收获,谢谢赞美
相关文章:
SpringBoot3---核心特性---2、Web开发III(模板引擎、国际化、错误处理)
星光下的赶路人star的个人主页 夏天就是吹拂着不可预期的风 文章目录 1、模板引擎1.1 Thymeleaf1.2 基础语法1.3 属性设置1.4 遍历1.5 判断1.6 属性优先级1.7 行内写法1.8 变量选择1.9 模板布局1.10 devtools 2、国家化3、错误处理3.1 默认机制3.2 自定义错误响应3.3 最佳实战 …...
MemFire教程|FastAPI+MemFire Cloud+LangChain开发ChatGPT应用-Part2
基本介绍 上篇文章我们讲解了使用FastAPIMemFire CloudLangChain进行GPT知识库开发的基本原理和关键路径的代码实现。目前完整的实现代码已经上传到了github,感兴趣的可以自己玩一下: https://github.com/MemFire-Cloud/memfirecloud-qa 目前代码主要…...
C# File.Exists与Directory.Exists用法
File.Exists: 用于检查给定文件路径是否存在。如果文件存在,则返回true,否则返回false。 string path“D:\\test\\example.txt” bool exists File.Exists(path); if (exists) {Console.WriteLine("File exists."); } else {Con…...
(深度学习,自监督、半监督、无监督!!!)神经网络修改网络结构如何下手???
修改神经网络结构,我们可以根据这个进行添加: 卷积层(Convolutional Layers):标准的卷积层用于提取特征并进行特征映射。 池化层(Pooling Layers):用于减少特征图的空间维度&…...
Codejock Task Panel ActiveX Crack
Codejock Task Panel ActiveX Crack ActiveX COM的Codejock任务面板为Windows开发人员提供了一个复杂的Office任务面板,类似于在Microsoft Office和Windows资源管理器中看到的内容。TaskPanel甚至可以用作Visual Studio风格的工具箱。 功能概述 ActiveX COM的Codejo…...
LeetCode 热题 100 JavaScript--141. 环形链表
给你一个链表的头节点 head ,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(…...
文字转语音
键盘获取文字,转化为语音后保存本地 from win32com.client import Dispatch from comtypes.client import CreateObject from comtypes.gen import SpeechLib speakerDispatch(SAPI.SpVoice) speaker.Speak(请输入你想转化的文字) datainput(请输入:)#s…...
让ELK在同一个docker网络下通过名字直接访问
1. docker网络 参考https://blog.csdn.net/lihongbao80/article/details/108019773 https://www.freecodecamp.org/chinese/news/how-to-get-a-docker-container-ip-address-explained-with-examples/ 默认网络有三种,分别是 1、bridge模式,–netbridge(…...
EventBus 开源库学习(一)
一、概念 EventBus是一款在 Android 开发中使用的发布-订阅事件总线框架,基于观察者模式,将事件的接收者和发送者解耦,简化了组件之间的通信,使用简单、效率高、体积小。 一句话:用于Android组件间通信的。 二、原理…...
车载以太网SOME/IP的个人总结
如何实现CAN-SOME/IP通信路由测试 (qq.com) AutoSAR SOMEIP与SOC vsomeip通讯 (qq.com) 利用commonAPI和vSomeip对数据进行序列化 (qq.com) Vector - CANoe - VCDL与SomeIP (qq.com) 使用Wireshark 查看SOMEIP的方法 (qq.com) 基于AutoSAR的车载以太网测试 - SOMEIP之ECU做…...
vue2.29-Vue3跟vue2的区别
1、vue3介绍 更新(和重写)Vue的主要版本时,主要考虑两点因素:首先是新的JavaScript语言特性在主流浏览器中的受支持水平;其次是当前代码库中随时间推移而逐渐暴露出来的一些设计和架构问题。 相较于vue2,vu…...
【深度学习】分类和分割常见损失函数
分类 分类是一种监督机器学习任务,其中训练模型来预测给定输入数据点的类或类别。分类旨在学习从输入特征到特定类或类别的映射。 有不同的分类任务,例如二元分类、多类分类和多标签分类。 二元分类是一项训练模型来预测两个类别之一的任务,…...
Redhat Linux 安装MySQL安装手册
Redhat安装MySQL安装手册 1 下载2 上传服务器、解压并安装3 安装安装过程1:MySQL-shared-5.6.51-1.el7.x86_64.rpm安装过程2:MySQL-shared-compat-5.6.51-1.el7.x86_64.rpm安装过程3:MySQL-server-5.6.51-1.el7.x86_64.rpm安装过程4ÿ…...
题目:2303.计算应缴税款总额
题目来源: leetcode题目,网址:2303. 计算应缴税款总额 - 力扣(LeetCode) 解题思路: 按要求计算即可。注意最多产生 n1 个不同区间内的税款即可。 解题代码: class Solution {public doub…...
Kotlin 1.9.0 发布:带来多项新特性,改进 Multiplatform/Native 支持
新特性 Kotlin 的最新版本引入了许多新的语言特性,包括用于开放范围的…<操作符、扩展正则表达式等。此外,它还改进了 Kotlin Multiplatform 和 Kotlin/Native 支持。 Kotlin 1.9 稳定了与枚举类关联的 entries 属性,它会返回所定义的枚…...
接口测试——认知(一)
目录 引言 环境准备 1. 为什么要进行接口测试 2. 什么是接口 3. 接口测试与功能测试的区别 引言 为什么要做接口自动化测试? 在当前互联网产品迭代频繁的背景下,回归测试的时间越来越少,很难在每个迭代都对所有功能做完整回归。 但接…...
剑指 Offer 10- I. 斐波那契数列
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下: F(0) 0, F(1) 1 F(N) F(N - 1) F(N - 2), 其中 N > 1. 斐波那契数列由 0 和 1 开始&am…...
洪水填充算法详解
😜作 者:是江迪呀✒️本文关键词:算法、前端、JavaScript、HTML、洪水填充算法☀️每日 一言:不以物喜,不以己悲 一、前言 当象一个容器中注水时,无论容器的结构如何复杂,注入的水…...
ubuntu18.04安装docker及docker基本命令的使用
官网安装步骤:https://docs.docker.com/desktop/install/ubuntu/ docker快速入门教程 Ubuntu-Docker安装和使用 docker官网 docker-hub仓库 1、常用指令 (1)镜像操作 # ############################# 以nginx为例 docker images docker p…...
DataWhale 机器学习夏令营第二期——AI量化模型预测挑战赛 学习记录
DataWhale 机器学习夏令营第二期 学习记录一 (2023.08.06)1. 问题建模1.1 赛事数据数据集情况数据中缺失值类别和数值特征的基本分布 1.2 评价指标中间价的计算方式价格移动方向说明 1.3 线下验证 DataWhale 机器学习夏令营第二期 ——AI量化模型预测挑战赛 已跑通baseline&…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...
C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...
接口 RESTful 中的超媒体:REST 架构的灵魂驱动
在 RESTful 架构中,** 超媒体(Hypermedia)** 是一个核心概念,它体现了 REST 的 “表述性状态转移(Representational State Transfer)” 的本质,也是区分 “真 RESTful API” 与 “伪 RESTful AP…...
