封面画师:adsuger 封面ID:76462341
0. 前言
本文主要讲述使用 SpringBoot + Thymeleaf 在项目中的基本使用,并 不涉及数据库使用!
1. 首页
1.1 首页跳转
在 templates 目录下的静态资源是无法直接访问的,相当于我们以前的 Web-INF 目录,我们可以使用 Controller 进行访问。
首页的添加有两种方式:直接在 Controller 中编写跳转、使用配置类进行配置。
假设我们的首页名为 index.html,并且放置于 templates 目录下。
直接在 Controller 中编写跳转
@RequestMapping({"/index.html","/"})
public String index(){
return "index";
}
使用配置类进行配置
@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 支持的属性。
添加命名空间:
<html lang="en" xmlns:th="https://www.thymeleaf.org/">
引入静态资源(链接前的第一个 / 表示项目的根目录):
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
<link th:href="@{/css/signin.css}" rel="stylesheet">
❓ 为什么链接前要加一个 ”/” 表示根目录?
❗ 因为请求转发涉及到相对路径的问题,所以最前面要加 ”/” 表示根路径。
在 Thymeleaf 中,链接(URL)使用 @{ ... } 进行表示。
使用 Thymeleaf 可能会出现因为模板引擎缓存的问题,导致引入静态资源无效,这时我们在配置文件中关闭 Thymeleaf 的缓存即可:
#关闭模板引擎缓存
spring.thymeleaf.cache=false
2. 页面国际化
所谓国际化,就是可以点击 「中文」、「English」 或其他语言实现切换界面语言。
实现首页的国际化:
-
在 resources 目录下创建目录 i18n
-
在 i18n 目录下创建文件 login.properties、login_en_US.properties、login_zh_CN.properties 分别表示登录界面语言为默认语言、中文、英文
-
点击 IDEA 下方 Resource Bundle,进行可视化配置
-
在配置文件进行配置:
#国际化配置文件真实位置 spring.messages.basename=i18n.login -
在界面中使用 Thymeleaf 表达式修改,如:
<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}"> -
编写点击切换的链接:
<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> -
编写自定义地区解析器:
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 至容器:
// 自定义国际化组件生效 // 方法名别写错了,SpringMVC中约定Bean的名称必须是localeResolver @Bean public LocaleResolver localeResolver(){ return new MyLocaleResolver(); }
3. 登录设置
3.1 登录失败提示信息
登录的 Controller:
@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
<!--如果msg为空则不显示-->
<p style="color: #ff0000" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
3.2 登录拦截器
编写自定义拦截器类:
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;
}
}
}
在配置类中添加拦截器:
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login","/static/*");
}
4. 抽取公共资源
公共资源放置于 templates/commons/commons.html 中:
<!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):
<!--顶部导航栏-->
<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 三元表达式的使用,点击侧边栏跳转至对应的界面,侧边栏对应的字样高亮:
<a th:class="${active=='list.html'?'nav-link active':'nav-link'}" th:href="@{/emps}">
Thymeleaf 日期显示格式化:
<td th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td>
Thymeleaf 遍历:
<option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}"
th:value="${dept.getId()}"></option>
SpringBoot 中 MVC 的日期格式是 yyyy/MM/dd,如果我们要进行日期格式化,可以在配置文件中添加:
#配置日期格式化
spring.mvc.date-format=yyyy-MM-dd
Thymeleaf 中 URL 拼接(RestFul 风格):
<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>