基本配置
springBoot 版本2.2.4 + web
<!--Thymeleaf,我们都是基于3.x开发-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
A.创建实体类
//部门表
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Department {
private Integer id;
private String departmentName;
}
//员工表
@Data
@NoArgsConstructor
public class Employee {
private Integer id;
private String lastName;
private String email;
private Integer gender;//0:女,1:男
private Department department;
private Date birth;
public Employee(Integer id, String lastName, String email, Integer gender, Department department) {
this.id = id;
this.lastName = lastName;
this.email = email;
this.gender = gender;
this.department = department;
//默认的创建日期
this.birth = new Date();
}
}
B.部门Dao
package com.rgh.dao;
//部门Dao
@Repository
public class DepartmentDao {
//模拟数据库中的数据
private static Map<Integer,Department> departments = null;
static{
departments = new HashMap<>();//创建一个部门表
departments.put(101,new Department(101,"教学部"));
departments.put(102,new Department(102,"市场部"));
departments.put(103,new Department(103,"教研部"));
departments.put(104,new Department(104,"运营部"));
departments.put(105,new Department(105,"后勤部"));
}
//获得所有部门信息
public Collection<Department> getDepartments(){
return departments.values();
}
//通过id得到部门
public Department getDepartmentById(Integer id){
return departments.get(id);
}
}
C. 员工Dao
package com.rgh.dao;
//员工Dao
@Repository
public class EmployeeDao {
//模拟数据库中的数据
private static Map<Integer,Employee> employees = null;
//员工有所属的部门
@Autowired
private DepartmentDao departmentDao;
static{
employees = new HashMap<>();//创建一个部门表
employees.put(1001,new Employee(1001,"AA","A365854987@qq.com",0,new Department(101,"教学部")));
employees.put(1002,new Employee(1002,"BB","B365854987@qq.com",1,new Department(102,"市场部")));
employees.put(1003,new Employee(1003,"CC","C365854987@qq.com",0,new Department(103,"教研部")));
employees.put(1004,new Employee(1004,"DD","D365854987@qq.com",1,new Department(104,"运营部")));
employees.put(1005,new Employee(1005,"EE","E365854987@qq.com",0,new Department(105,"后勤部")));
}
//主键自增
private static Integer initId = 1006;
//增加一个员工
public void save(Employee employee){
if(employee.getId() == null){
employee.setId(initId++);
}
employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));
employees.put(employee.getId(),employee);
}
//查询所有员工
public Collection<Employee> getAll(){
return employees.values();
}
//通过id查询员工
public Employee getEmployeeById(Integer id){
return employees.get(id);
}
//删除员工通过id
public void delete(Integer id){
employees.remove(id);
}
}
1. 配置首页
1.1 自定义视图控制器
package com.rgh.config;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
}
1.2 html导入thymeleaf
<html lang="en" xmlns:th="http://www.thymeleaf.org">
1.3 修改页面中资源路径@{}
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
1.4 application.properties文件配置
# 关闭默认图标
spring.mvc.favicon.enabled=false
# 关闭引擎的缓存
spring.thymeleaf.cache=false
2.国际化
2.1 新建文件夹,配置文件
2.2 全局配置文件
# 我们的配置文件放在的真实位置
spring.messages.basename=i18n.login
2.3 login.properties
login.btn=登陆
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名
<form class="form-signin" action="dashboard.html">
<img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
<input type="text" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
<input type="password" class="form-control" th:placeholder="#{login.password}" required="">
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> [[#{login.remember}]]
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">[[#{login.btn}]]</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<a class="btn btn-sm">中文</a>
<a class="btn btn-sm">English</a>
</form>
2.4 写一个自己的国际化解析器实现LocaleResolver接口
package com.rgh.config;
public class MyLocaleResolver 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 httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
2.5 连接请求
()里面带参数
<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>
2.6 放到Bean里面
package com.rgh.config;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
//自定义的国际化组件就生效了
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}
- 首页配置:
- 注意点,所有页面的静态资源都需要使用thymeleaf接管;
- url:
@{}
- 页面国际化:
- 我们需要配置i18n文件
- 我们如果需要在项目中进行按钮自动切换,我们需要自定义一个组件
LocaleResolver
- 记得将自己写的组件配置到spring容器QBean
#{}
3. 登陆+拦截器
链接
<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){
//具体的业务
if(!StringUtils.isEmpty(username) && "123456".equals(password)){
session.setAttribute("loginUser",username);
return "redirect:/main.html";
}else{
//告诉用户登陆失败
model.addAttribute("msg","用户名或密码错误!");
return "index";
}
}
}
显示错误信息,thymeleaf工具方法判断是否为空
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
增加一个首页映射
package com.rgh.config;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
.....
registry.addViewController("/main.html").setViewName("dashboard");
}
.....
}
写一个登陆拦截器LoginHandlerInterceptor
package com.rgh.config;
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);
return false;
}else {
return true;
}
}
}
配置类中
重写addInterceptors(InterceptorRegistry registry)
方法
添加登陆拦截器和拦截的请求,不拦截的请求
package com.rgh.config;
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
....
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/index.html","/","/user/login","/css/**","/js/**","/img/**");
}
}
获取登陆名
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</a>
4. 员工列表
4.1 侧边栏按钮
<a class="nav-link" th:href="@{/emps}">
4.2 Controller层
package com.rgh.controller;
@Controller
public class EmployeeController {
@Autowired
private EmployeeDao employeeDao;
@RequestMapping("/emps")
public String list(Model model){
Collection<Employee> all = employeeDao.getAll();
model.addAttribute("emps",all);
return "/emp/list";
}
}
4.3 提取公共页面commons
<!DOCTYPE html>
<html lang="en" xmlns:th="http://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>
4.4 公共部分插入
<!--头部-->
<div th:replace="~{commons/commons::topbar}"></div>
<!--侧边栏-->
<div th:replace="~{commons/commons::sidebar}"></div>
4.5 按钮点击高亮
传递参数active
<div th:replace="~{commons/commons::sidebar(active='main.html')}"></div>
通过参数判断是否高亮
<a th:class="${active=='main.html'?'nav-link active':'nav-link'}" th:href="@{/index.html}">
4.6 列表循环展示
<thead>
<tr>
<th>id</th>
<th>lastName</th>
<th>email</th>
<th>gender</th>
<th>department</th>
<th>birth</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="emp:${emps}">
<td th:text="${emp.getId()}"></td>
<td>[[${emp.getLastName()}]]</td>
<td th:text="${emp.getEmail()}"></td>
<td th:text="${emp.getGender()==0?'女':'男'}"></td>
<td th:text="${emp.department.getDepartmentName()}"></td>
<td th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td>
<td>
<button class="btn btn-sm btn-primary">编辑</button>
<button class="btn btn-sm btn-danger">删除</button>
</td>
</tr>
</tbody>
5. 添加员工
5.1 链接
<h2><a class="btn btn-sm btn-success" th:href="@{/emp}">添加员工</a> </h2>
5.2 Controller中下拉框需要查找
package com.rgh.controller;
@Controller
public class EmployeeController {
@Autowired
private EmployeeDao employeeDao;
@Autowired
private DepartmentDao departmentDao;
...
@GetMapping("/emp")
public String toAddpage(Model model){
//查出所有部门的信息
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("departments",departments);
return "emp/add";
}
}
5.3 下拉菜单的获取
注意:提交的是department的id
<select class="form-control" name="department.id">
<option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option>
</select>
5.4 员工生日的日期格式
默认是yyyy/MM/dd
在配置文件application.properties中修改
# 时间日期格式化
spring.mvc.date-format=yyyy-MM-dd
6. 修改员工
6.1 按钮链接
<a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.getId()}">编辑</a>
6.2 Controller层
package com.rgh.controller;
@Controller
public class EmployeeController {
@Autowired
private EmployeeDao employeeDao;
@Autowired
private DepartmentDao departmentDao;
...
//去员工的修改页面
@GetMapping("/emp/{id}")
public String toUpdateEmp(@PathVariable("id") Integer id,Model model){
//查出原来的数据
Employee employeeById = employeeDao.getEmployeeById(id);
model.addAttribute("emp",employeeById);
//查出所有部门的信息
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("departments",departments);
return "emp/update";
}
}
6.3 下拉菜单,单选按钮,日期的回显方式
<input type="hidden" name="id" th:value="${emp.getId()}">
<div class="form-group">
<label>LastName</label>
<input type="text" th:value="${emp.getLastName()}" name="lastName" class="form-control" placeholder="kuangshen">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" th:value="${emp.getEmail()}" name="email" class="form-control" placeholder="24736743@qq.com">
</div>
<div class="form-group">
<label>Gender</label><br/>
<div class="form-check form-check-inline">
<input th:checked="${emp.getGender() == 1}" class="form-check-input" type="radio" name="gender" value="1">
<label th:checked="${emp.getGender() == 0}" class="form-check-label">男</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" value="0">
<label class="form-check-label">女</label>
</div>
</div>
<div class="form-group">
<label>department</label>
<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>Birth</label>
<input type="text" th:value="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}" name="birth" class="form-control" placeholder="kuangstudy">
</div>
6.4 表单提交链接
<form th:action="@{/updateEmp}" method="post">
6.5 Controller层
package com.rgh.controller;
@Controller
public class EmployeeController {
@Autowired
private EmployeeDao employeeDao;
@Autowired
private DepartmentDao departmentDao;
...
@PostMapping("/updateEmp")
public String updateEmp(Employee employee){
employeeDao.save(employee);
return "redirect:/emps";
}
}
7. 删除员工
7.1 删除连接
<a class="btn btn-sm btn-danger" th:href="@{/delemp/}+${emp.getId()}">删除</a>
7.2 Controller层
package com.rgh.controller;
@Controller
public class EmployeeController {
@Autowired
private EmployeeDao employeeDao;
@Autowired
private DepartmentDao departmentDao;
......
@GetMapping("/delemp/{id}")
public String delEmp(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/emps";
}
}
8. 404页面
新建error文件夹把404页面放到里面
9. 注销
9.1 注销连接
<a class="nav-link" th:href="@{/user/logout}">注销</a>
9.2 Controller层
package com.rgh.controller;
@Controller
public class LoginController {
......
@RequestMapping("/user/logout")
public String logout(HttpSession httpSession){
httpSession.invalidate();
return "redirect:/index.html";
}
}