导入 jquery 依赖
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>jqueryartifactId>
<version>3.6.0version>
dependency>
访问 jquery.js 文件
http://localhost:8080/webjars/jquery/3.6.0/jquery.js
静态资源默认路径(访问优先级由高到低排序)
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/
一般 public 目录存放公共资源,如各模块需要调用的 js;static 目录存放静态资源,如图片;
resources 目录存放上传的文件。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
config 目录下自定义配置类
// 扩展 SpringMvc,不能加 @EnableWebMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Bean
public ViewResolver myViewResolver() {
return new MyViewResolver();
}
// 自定义一个视图解析器
public static class MyViewResolver implements ViewResolver {
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
}
添加 html 国际化按钮
编写组件
public class MyLocaleResover implements LocaleResolver {
// 解析请求
@Override
public Locale resolveLocale(HttpServletRequest request) {
// 获取请求中的语言参数
String language = request.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 request, HttpServletResponse response, Locale locale) {
}
}
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
// 国际化组件注册到Spring
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResover();
}
}
# application.properties
# 配置文件位置
spring.messages.basename=i18n.login
<input type="text" class="form-control" name="username" th:placeholder="#{login.username}" required="" autofocus="">
<input type="password" class="form-control" name="password" th:placeholder="#{login.password}" required="">
<form class="form-signin" th:action="@{/user/login}">
@Controller
public class LoginController {
@RequestMapping("/user/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password,
Model model, HttpSession session) {
// 用户名不为空,密码为 123456
if (!StringUtils.isEmpty(username) && "123456".equals(password)) {
// 向 session 传入登录标识
session.setAttribute("loginUser", username);
// 重定向到面板
return "redirect:/main.html";
} else {
// 向 msg 传入信息
model.addAttribute("msg", "用户名或密码错误");
return "index";
}
}
}
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取登录标识
Object loginUser = request.getSession().getAttribute("loginUser");
// 没有登录
if (loginUser == null) {
// 向 msg 传入信息
request.setAttribute("msg", "没有权限");
// 跳转到 index
request.getRequestDispatcher("/index.html").forward(request, response);
return false;
} else {
return true;
}
}
}
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// / 可访问到 index.html
registry.addViewController("/").setViewName("index");
// index.html 可访问到 index
registry.addViewController("/index.html").setViewName("index");
// /main.html 可访问到 dashboard
registry.addViewController("/main.html").setViewName("dashboard");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加登录拦截器
registry.addInterceptor(new LoginHandlerInterceptor())
// 设置拦截对象
.addPathPatterns("/**")
// 排除拦截对象
.excludePathPatterns("/index.html", "/", "/user/login","/css/**", "/js/**", "/img/**");
}
}
<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>
<div th:replace="~{commons/commons::topbar}">div>
<div th:replace="~{commons/commons::sidebar(active='main.html')}">div>
<div th:insert="~{commons/commons::topbar}">div>
<div th:insert="~{commons/commons::sidebar(active='list.html')}">div>
<a th:class="${active == 'main.html'?'nav-link active':'nav-link'}" th:href="@{/index.html}">
...
a>
<a th:class="${active == 'list.html'?'nav-link active':'nav-link'}" th:href="@{/emps}">
...
a>
@Controller
public class EmployeeController {
@Autowired
EmployeeDao employeeDao;
@Autowired
DepartmentDao departmentDao;
@RequestMapping("/emps")
public String list(Model model) {
Collection<Employee> employees = employeeDao.getAll();
model.addAttribute("emps", employees);
return "emp/list";
}
}
<table class="table table-striped table-sm">
<thead>
<tr>
<th>idth>
<th>lastNameth>
<th>emailth>
<th>genderth>
<th>departmentth>
<th>birthth>
<th>操作th>
tr>
thead>
<tbody>
<tr th:each="emp:${emps}">
<td th:text="${emp.getId()}"/>
<td th:text="${emp.getLastName()}"/>
<td th:text="${emp.getEmail()}"/>
<td th:text="${emp.getGender()==0?'女':'男'}"/>
<td th:text="${emp.getDepartment().departmentName}"/>
<td th:text="${#dates.format(emp.getBirth(),'YYYY-MM-DD HH:mm:ss')}"/>
<td>
<button class="btn btn-sm btn-primary">编辑button>
<button class="btn btn-sm btn-danger">删除button>
td>
tr>
tbody>
table>
<form th:action="@{/emp}" method="post">
<div class="form-group">
<label>LastNamelabel>
<input type="text" name="lastName" class="form-control" placeholder="why">
div>
<div class="form-group">
<label>Emaillabel>
<input type="text" name="email" class="form-control" placeholder="[email protected]">
div>
<div class="form-group">
<label>Genderlabel>
<div class="form-check form-check-inline">
<input type="radio" class="form-check-input" name="gender" value="0">
<label class="form-check-label">女label>
div>
<div class="form-check form-check-inline">
<input type="radio" class="form-check-input" name="gender" value="1">
<label class="form-check-label">男label>
div>
div>
<div class="form-group">
<label>Departmentlabel>
<select class="form-control" name="department.id">
<option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}">option>
select>
div>
<div class="form-group">
<label>Birthlabel>
<input type="text" name="birth" class="form-control" placeholder="2021-01-01">
div>
<button type="submit" class="btn btn-primary">添加button>
form>
form>
@Controller
public class EmployeeController {
@Autowired
EmployeeDao employeeDao;
@Autowired
DepartmentDao departmentDao;
@GetMapping("/emp")
public String toAddPage(Model model) {
// 获取部门数据
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("departments", departments);
return "emp/add";
}
@PostMapping("/emp")
public String addEmp(Employee employee) {
System.out.println("receive_emp ==>" + employee);
// 保存员工数据
employeeDao.save(employee);
return "redirect:/emps";
}
}
<a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.getId()}">编辑a>
// EmployeeController.java
@GetMapping("/emp/{id}")
public String toUpdateEmp(@PathVariable("id") Integer id, Model model) {
// 获取员工数据
Employee employee = employeeDao.getEmployeeById(id);
model.addAttribute("emp", employee);
// 获取部门数据
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("departments", departments);
return "emp/update";
}
<form th:action="@{/updateEmp}" method="post">
<input type="hidden" name="id" th:value="${emp.getId()}">
<div class="form-group">
<label>LastNamelabel>
<input th:value="${emp.getLastName()}" type="text" name="lastName" class="form-control" placeholder="why">
div>
<div class="form-group">
<label>Emaillabel>
<input th:value="${emp.getEmail()}" type="text" name="email" class="form-control" placeholder="[email protected]">
div>
<div class="form-group">
<label>Gender label>
<div class="form-check form-check-inline">
<input th:checked="${emp.getGender() == 0}" type="radio" class="form-check-input" name="gender" value="0">
<label class="form-check-label">女label>
div>
<div class="form-check form-check-inline">
<input th:checked="${emp.getGender() == 1}" type="radio" class="form-check-input" name="gender" value="1">
<label class="form-check-label">男label>
div>
div>
<div class="form-group">
<label>Departmentlabel>
<select class="form-control" name="department.id">
<option th:selected="${dept.getId() == emp.getDepartment().getId()}" th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}">option>
select>
div>
<div class="form-group">
<label>Birthlabel>
<input th:value="${#dates.format(emp.getBirth(), 'yyyy-MM-dd HH:mm')}" type="text" name="birth" class="form-control" placeholder="2021-01-01">
div>
<button type="submit" class="btn btn-primary">修改button>
form>
@PostMapping("/updateEmp")
public String updateEmp(Employee employee) {
employeeDao.save(employee);
return "redirect:/emps";
}
<a class="btn btn-sm btn-danger" th:href="@{/deleteEmp/}+${emp.getId()}">删除a>
@GetMapping("/deleteEmp/{id}")
public String deleteEmp(@PathVariable("id") Integer id) {
employeeDao.deleteEmp(id);
return "redirect:/emps";
}
templates 下添加 error 路径
将错误页面以错误代码命名放入 error 目录下
<a class="nav-link" th:href="@{/user/logout}">注销a>
// LoginController.java
@RequestMapping("/user/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/index.html";
}