封面画师:adsuger 封面ID:76462341
0. 前言
本文主要讲述使用 SpringBoot + Thymeleaf 在项目中的基本使用,并 不涉及数据库使用!
1. 首页
1.1 首页跳转
在 templates 目录下的静态资源是无法直接访问的,相当于我们以前的 Web-INF 目录,我们可以使用 Controller 进行访问。
首页的添加有两种方式:直接在 Controller 中编写跳转、使用配置类进行配置。
假设我们的首页名为 index.html,并且放置于 templates 目录下。
直接在 Controller 中编写跳转
1 2 3 4
| @RequestMapping({"/index.html","/"})
public String index(){
return "index";
}
|
使用配置类进行配置
1 2 3 4 5 6 7 8 9
| @Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
registry.addViewController("/main.html").setViewName("dashboard");
}
}
|
1.2 加载首页样式
因为我们使用了 Thymeleaf,因此我们需要将 HTML 中的一些属性改成 Thymeleaf 支持的属性。
添加命名空间:
1
| <html lang="en" xmlns:th="https://www.thymeleaf.org/">
|
引入静态资源(链接前的第一个 / 表示项目的根目录):
1 2
| <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<link th:href="@{/css/signin.css}" rel="stylesheet">
|
❓ 为什么链接前要加一个 “/” 表示根目录?
❗ 因为请求转发涉及到相对路径的问题,所以最前面要加 “/” 表示根路径。
在 Thymeleaf 中,链接(URL)使用 @{ ... } 进行表示。
使用 Thymeleaf 可能会出现因为模板引擎缓存的问题,导致引入静态资源无效,这时我们在配置文件中关闭 Thymeleaf 的缓存即可:
1 2
| #关闭模板引擎缓存
spring.thymeleaf.cache=false
|
2. 页面国际化
所谓国际化,就是可以点击 「中文」、「English」 或其他语言实现切换界面语言。
实现首页的国际化:
-
在 resources 目录下创建目录 i18n
-
在 i18n 目录下创建文件 login.properties、login_en_US.properties、login_zh_CN.properties 分别表示登录界面语言为默认语言、中文、英文
-
点击 IDEA 下方 Resource Bundle,进行可视化配置
-
在配置文件进行配置:
1 2
| #国际化配置文件真实位置
spring.messages.basename=i18n.login
|
-
在界面中使用 Thymeleaf 表达式修改,如:
1 2 3
| <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}"></h1>
<input type="text" name="username" class="form-control"
th:placeholder="#{login.username}">
|
-
编写点击切换的链接:
1 2
| <a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
|
-
编写自定义地区解析器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class MyLocaleResolver implements LocaleResolver {
//解析请求
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
//获取请求中的语言参数
String language = httpServletRequest.getParameter("l");
Locale locale = Locale.getDefault(); //如果没有参数使用默认的
//如果请求的链接携带了国际化的参数
if(!StringUtils.isEmpty(language)){
//zh_CN
String[] split = language.split("_");
//国家,地区
locale = new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
|
-
在配置类中添加 bean 至容器:
1 2 3 4 5 6
| // 自定义国际化组件生效
// 方法名别写错了,SpringMVC中约定Bean的名称必须是localeResolver
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
|
3. 登录设置
3.1 登录失败提示信息
登录的 Controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @RequestMapping("/user/login")
public String login(
@RequestParam("username") String username,
@RequestParam("password") String password,
Model model, HttpSession session) {
// 模拟具体业务
if(!StringUtils.isEmpty(username) && "123456".equals(password)){
session.setAttribute("loginUser",username);
return "redirect:/main.html";
}else{
//通知用户密码错误
model.addAttribute("msg","用户名或密码错误");
return "index";
}
}
|
错误信息:
学会使用表达工具对象( Expression Utility Objects),参考官方文档第 19 项。
官方文档:Expression Utility Objects
1 2
| <!--如果msg为空则不显示-->
<p style="color: #ff0000" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
|
3.2 登录拦截器
编写自定义拦截器类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//登录成功后,应该有用户的session
Object loginUser = request.getSession().getAttribute("loginUser");
// 登录验证
if (loginUser == null){
request.setAttribute("msg","请进行登录查看!");
request.getRequestDispatcher("/index.html").forward(request,response);
// false 不放行
return false;
}else {
// true 放行
return true;
}
}
}
|
在配置类中添加拦截器:
1 2 3 4 5 6
| @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login","/static/*");
}
|
4. 抽取公共资源
公共资源放置于 templates/commons/commons.html 中:
1 2 3 4 5 6 7 8 9 10 11 12
| <!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org/">
<!--顶部导航栏-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">
<!-- 省略中间代码 -->
</nav>
<!--侧边栏 -->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar">
<!-- 省略中间代码 -->
</nav>
</html>
|
公共资源的使用(list.html):
1 2 3 4 5 6 7 8 9
| <!--顶部导航栏-->
<div th:replace="~{commons/commons::topbar}"></div>
<div class="container-fluid">
<div class="row">
<!--侧边栏-->
<!-- 传递一个参数,用于实现高亮 -->
<div th:replace="~{commons/commons::sidebar(active='list.html')}"></div>
</div>
</div>
|
插入公共资源中 th:replace 与 th:insert 的区别:
th:replace 是直接将当前标签替换为对应的公共资源,th:insert 表示插入公共资源,会在公共资源外加一层 <div></div>。
5. 404 与 500
在 SpringBoot 中,404 页面与 500 页面变得异常简单,我们只需要在 templates 目录下创建 error 文件夹,然后在这个文件夹下编写 404.html 和 500.html 即可。当发生 404 或 500 错误时,SpringBoot 会自动引导界面跳转至对应的界面。
6. 其他
Thymeleaf 三元表达式的使用,点击侧边栏跳转至对应的界面,侧边栏对应的字样高亮:
1
| <a th:class="${active=='list.html'?'nav-link active':'nav-link'}" th:href="@{/emps}">
|
Thymeleaf 日期显示格式化:
1
| <td th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td>
|
Thymeleaf 遍历:
1 2
| <option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}"
th:value="${dept.getId()}"></option>
|
SpringBoot 中 MVC 的日期格式是 yyyy/MM/dd,如果我们要进行日期格式化,可以在配置文件中添加:
1 2
| #配置日期格式化
spring.mvc.date-format=yyyy-MM-dd
|
Thymeleaf 中 URL 拼接(RestFul 风格):
1 2 3 4 5
| <a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.getId()}">编辑</a>
<!-- 或者 -->
<a class="btn btn-sm btn-primary" th:href="@{/emp(id=${emp.getId()})}">编辑</a>
<!-- 或者 -->
<a class="btn btn-sm btn-primary" th:href="@{/emp/id=(${emp.getId()})}">编辑</a>
|