这个项目没有使用service层和数据库。
1.首先先使用java模拟数据库
首先是两个pojo类
Department.java
package com.aiguigu.springboot3web.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Department {
private Integer id;
private String departmentName;
}
Employee.java
package com.aiguigu.springboot3web.pojo;
import lombok.*;
import java.util.Date;
@Data
@NoArgsConstructor
@Setter @Getter
@ToString
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();
}
}
然后是两个Dao
departmentDao.java
package com.aiguigu.springboot3web.dao;
import com.aiguigu.springboot3web.pojo.Department;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/*部门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);
}
}
employeeDao.java
package com.aiguigu.springboot3web.dao;
import com.aiguigu.springboot3web.pojo.Department;
import com.aiguigu.springboot3web.pojo.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@Repository
public class employeeDao {
/*模拟数据库中的数据*/
private static Map<Integer, Employee> employees = null;
@Autowired
departmentDao departmentDao;
static {
employees = new HashMap<>();
employees.put(1001,new Employee(1001,"A","A202516@qq.com",1,new Department(101,"教学部")));
employees.put(1002,new Employee(1002,"B","B202516@qq.com",0,new Department(102,"运营部")));
employees.put(1003,new Employee(1003,"C","C202516@qq.com",1,new Department(103,"后勤部")));
employees.put(1004,new Employee(1004,"D","D202516@qq.com",0,new Department(104,"小卖部")));
employees.put(1005,new Employee(1005,"E","E202516@qq.com",1,new Department(105,"教研部")));
}
/*主键自增!*/
private static Integer init_id = 1006;
/*增加员工*/
public void save(Employee employee){
if(employee.getId()==null)
{
employee.setId(init_id++);
}
employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));
employees.put(employee.getId(),employee);
}
/*查询所有的员工*/
public Collection<Employee> getAllEmployees(){
return employees.values();
}
/*通过id查询员工*/
public Employee getEmployeeById(Integer id){
return employees.get(id);
}
/*删除员工*/
public void deleteEmployee(Integer id){
employees.remove(id);
}
}
2.设置首页跳转
1.我们将首页放在templates文件下,不能够直接访问,必须我们进行跳转
跳转有两种方式:
1.第一种是使用controller进行跳转,但是一般不这样做
2.第二种是使用spring扩展配置文件进行跳转,即在config文件下创建配置文件,实现WebMvcConfigurer接口,然后使用视图控制器进行跳转
@Configuration
public class myMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
}
3.首页配置
敲重点!
- thymleaf中,href需要使用@在目录前,@后的 / 表示该程序的根目录,static是静态目录,所以在写css路径的时候,不需要写static目录。
敲重点!
- 所以有的静态资源交给thymleaf接管,href,src @{}
1.先导入thymeleaf的头文件
<html lang="en" xmlns:th="http://www.thymeleaf.org">
css路径**@后的 / 表示该程序的根目录,static是静态目录,所以在写css路径的时候,不需要写static目录。**
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
th:src="@{/js/jquery-3.2.1.slim.min.js}"
<script type="text/javascript" th:src="@{/js/popper.min.js}" ></script>
4.页面国际化
1.我们首先需要在resources目录下创建 i18n(国际化的简称) 文件
- 在 i18n 目录下创建login.properties login_en_US.properties login_zh_CN.properties
- 在login里选择 Resource Bundle,点击 + 进行添加property key ,将页面中的中英文写进去。
- 帮我们做自动化国际转化的类MessageSourceAutoConfiguration
2.我们要在yml文件中添加我们配置文件的真实位置
# 我们的配置文件的真实位置
messages:
basename: i18n.login
3.在页面中,对应需要国际化的地方添加thymeleaf语句
取值有两种方式
国际化使用[[#{}]]
国际化使用 #{}来取
//这些login.username都是我们在login.properties文件中创建的键值对
<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
一些展示在外边的标签,在标签内部使用 **th:text="#{}"取,可能会出问题,所以可以在外使用[[#{}]]**来取值
<label >
<input type="checkbox" value="remember-me" >[[#{login.remember}]]
</label>
如果是text框中的placeholder的话,使用**th:placeholder="#{login.password}"**来取
<input type="password" class="form-control" th:placeholder="#{login.password}" required="" >
4.如何在点击的时候进行国际化转换
首先我们在进行国际化转换的地方,添加请求
使用thymeleaf发送请求,使用@,参数使用括号括起来 (l=‘zh_CN’)、(l=‘en_US’)
<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>
spring内部,使用了视图解析器(locale Resolver)来解析我们的请求,进而判断是英文还是中文。
在这里我们自己写一个视图解析器(在webMvcAutoConfiguration中),卸载config目录下,实现LocaleResolver接口。
1.我们自己重写的视图解析器
public class MyLocaleResolver implements LocaleResolver {
@Override
/*解析请求*/
public Locale resolveLocale(HttpServletRequest request) {
/*1.获取发送的请求*/
String lanuage = request.getParameter("l");
/*2.获取默认的视图 , 发送的请求为空的话, 我们就用默认的视图*/
Locale locale = Locale.getDefault();
if(!StringUtils.isEmpty(lanuage)){
/*3.对请求进行分割 用 ‘_’ 分割我们的请求 请求是l='zh_CN' l='en_US'*/
String[] split = lanuage.split("_");
/*4.如果我们的请求不为空*/
locale = new Locale(split[0], split[1]);
}
/*5.最后返回locale即可*/
return locale;
}
2.重写完之后,还需要把他放在Bean里交给Spring管理
**敲重点!**在注入Bean的时候,我们要确定Bean的名称是使用方法的名称,在Bean的底层源码中可以看到,否则注入不进去。
在这里,方法的名称为“LocaleResolver”,所以bean的名称为“localeResolver”
我们在config目录下的MyMvcConfig.java文件里写
@Configuration
public class myMvcConfig implements WebMvcConfigurer {
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
}
5.登录功能的实现
1.拦截登录请求
1.在登录页面,写form表单提交的请求**/user/login**
<form class="form-signin" action="/user/login">
2.创建一个loginController,拦截登录的请求
**@RequestParam:**将请求参数绑定到你控制器的方法参数上
**Model:**用于数据回显
@RequestMapping("/user/login")
public String login(
@RequestParam("username") String username,
@RequestParam("password") String password,
Model model ){
if(!StringUtils.isEmpty(username) && "123".equals(password)){
return "dashboard";
}else{
model.addAttribute("msg","用户名或密码错误!");
return "index";
}
}
3.如果登录失败的话在返回了首页,我们要在首页取出登陆失败的信息
使用thymeleaf取
th:if="${not #strings.isEmpty(msg)} 判断 如果msg不为空的话,才显示msg信息
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
**敲重点!**thymeleaf中有许多和java类似的语法,用的是 # 开头 在文档中可以多查看
2.进行登录的验证
在步骤1中
3.回显登录成功 或 登录失败
在步骤1的3中
4.将页面跳转修改为重定向
1.我们在登录的时候,如果直接使用controller中,return "dashboard"的话,我们的请求中会带有我们的密码和用户名,不符合开发
所以我们在进行页面跳转的时候使用重定向
return “redirect:/main.html”;
@RequestMapping("/user/login")
public String login(
@RequestParam("username") String username,
@RequestParam("password") String password,
Model model ){
if(!StringUtils.isEmpty(username) && "123".equals(password)){
return "redirect:/main.html";
}else{
model.addAttribute("msg","用户名或密码错误!");
return "index";
}
}
2.然后我们在我们的MyMvcConfig.java文件中配置视图控制
将main.html 跳到 首页中
@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");
}
}
5.登录拦截
说明 :如果我们没有登录的话,需要拦截请求,不能进入欢迎页面,只能在首页
我们可以自己定义一个拦截器:LoginHandlerIntercepter 让他实现拦截器接口 HandlerInterceptor
1.我们只需要覆盖里边的 preHandle 方法
我们需要在loginController中,添加一个HttpSession参数,向session中存储用户名,来根据这个用户名是否为空,来判断是否已经登录,return false 拦截。
public class LoginHandlerIntercepter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object loginUser = request.getSession().getAttribute("loginUser");
if(loginUser == null){
/*如果loginUser为空,则没有登录,进行拦截*/
request.setAttribute("msg","没有权限,请先登录!");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else {
return true;
}
}
}
2.将我们配置的拦截器 配置到 Bean里
还是在config目录下的 myMvcConfiguration.java 文件里
@Configuration
public class myMvcConfig implements WebMvcConfigurer {
@Override
/*拦截器*/
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerIntercepter())
.addPathPatterns("/**")
.excludePathPatterns("/","/index.html","/user/login","/css/**","/img/**","/js/**");
}
}
使用registy来添加拦截器, 有两个属性
敲重点! 一定要记得静态资源的请求不可以拦截。
- addPathPatterns:添加需要拦截的请求路径
- excludePathPatterns:排除一些请求(哪些请求不会被拦截)
在页面中取session中的用户名: [[${session.loginUser}]]
6.员工列表展示
1.可以将公共的页面提取出来 (放在commons文件下的commons.html中)
1.th:fragment=“sidebar” (侧边栏)
2.th:replace="~{commons/commons::topbar}"
topbar就是我们写的fragment的名称, 我们在需要提取的内容中写fragment
3.还有就是标签高亮
<!--侧边栏-->
<div th:replace="~{/commons/commons::sidebar(active='list.html')}"></div>
我们在使用公共页面的时候,添加参数
在公共页面中判断 参数, 使用三元运算符。
<a th:class="${active == 'list.html' ? 'nav-link active' : 'nav-link'}" th:href="@{list.html}">
员工管理
</a>
2.员工页面的数据,使用遍历来取出
1.首先使用控制器,将数据库中的员工信息发送给员工也米娜
@Controller
public class employeeController {
@Autowired
employeeDao dao;
/*查询出所有员工 返回给员工页面*/
@RequestMapping("/emps")
public String getAllEmployees(Model model){
Collection<Employee> allEmployees = dao.getAllEmployees();
model.addAttribute("emps",allEmployees);
return "emp/list";
}
}
2.在员工页面使用遍历,取出员工的信息
敲重点!
在取性别的时候,使用三元运算符
在取日期的使用,可以使用datae工具类,对日期进行格式化
还可以添加两个按钮,添加样式
<tr th:each="emp:${emps}">
<td th:text="${emp.getId()}"></td>
<td th:text="${emp.getLastName()}"></td>
<td th:text="${emp.getEmail()}"></td>
<td th:text="${emp.getGender()==0? '女':'男'}"></td>
<td th:text="${emp.getDepartment().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>
3.员工添加页面,直接复制主页,将中间部分改为form表单即可
在form表单中接受信息的时候需要注意:
!: 接收性别信息的时候,记得加上value (1 或 0)
!: 接受部门信息的时候,在controller中,先查出部门名称,在form表单中遍历出来即可,记得加上部门的value值,(th:value="${dept.getId()}"),也就是部门的ID
<h2><a class="btn btn-sm btn-success" th:href="@{emp}">添加员工</a></h2>
这里是Get请求
controller: **敲重点!**这是使用GetMapping,只获取get请求,这里拦截emp
下边form表单 提交的信息的请求 也是 emp , 但是form表单的提交方式是Post请求,所以这里不会拦截
@GetMapping("/emp")
/*添加员工*/
public String empAdd(Model model) {
Collection<Department> departments = deptDao.getDepartments();
model.addAttribute("departments",departments);
return "emp/add";
}
4.完成员工添加操作
1.拦截form表单提交的请求(将form表单中的属性都添加上name)
这里的请求是post请求,在控制器中可以使用PostMapping来拦截。
敲重点! 注意部门的name,部门我们使用的值是Id,所以写name的时候要写(name=“department.id”)
<form th:action="@{emp}" method="post">
<div class="form-group">
<label>LastName</label>
<input type="text" class="form-control" placeholder="kuangshen" name="lastName">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" placeholder="24736743@qq.com" name="email">
</div>
<div class="form-group">
<label>Gender</label><br/>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="gender" value="1">
<label 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:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}" ></option>
</select>
</div>
<div class="form-group">
<label>Birth</label>
<input type="text" class="form-control" placeholder="kuangstudy" name="birth">
</div>
<button type="submit" class="btn btn-primary">添加</button>
</form>
Controller进行拦截:
@PostMapping("emp")
/*保存员工信息*/
public String save(Employee employee){
System.out.println(employee);
dao.save(employee);
return "redirect:/emps";
}
5.注意我们传到后台保存的格式
在yml配置文件中,输入spring.mvc.data.format,可以点进源码,可查看到日期默认的格式是“ dd/MM/yyyy ”
但是显示出来的确实“dd-MM-yyyy”
所以我们可以用配置文件修改日期格式:
spring:
mvc:
date-format: yyyy-MM-dd
6. 员工编辑
1.在员工编辑页面的按钮改为a标签,使用rest风格传参
<a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.getId()}">编辑</a>
这个没有什么难的
2.接受rest风格参数,使用@PathVariable接受参数,并绑定,并查出数据传到编辑页面
敲重点!这里后边的参数要用 “{}”括起来,并且下边@PathVariable里边的参数要和**“{}”**中的参数保持一致
/*编辑员工信息*/
@GetMapping("/emp/{id}")
public String toUpdate(@PathVariable("id")Integer id, Model model){
Employee employee = dao.getEmployeeById(id);
Collection<Department> departments = deptDao.getDepartments();
model.addAttribute("departments",departments);
model.addAttribute("emp",employee);
return "/emp/update";
}
然后,使用model存储数据,传给update
3.在编辑页面回显数据
update页面进行数据回显:
1.input标签的数据回显
这个没什么难的,唯一注意的也就是:回显的时候使用的是value , 而不是text
<input th:value="${emp.getLastName()}" type="text" class="form-control" placeholder="kuangshen" name="lastName">
2.下拉框的数据回显
要使用selected , 当部门的id和传过来的用户的部门的id相等,则被选中
单选框使用checked
<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>
3.单选框的数据回显
当性别为0,则是男。
<input th:checked="${emp.getGender()==0}" class="form-check-input" type="radio" name="gender" value="0">
4.日期的回显
要使用dates工具类进行格式化一下。
<input th:value="${#dates.setFormat(emp.getBirth(),'yyyy-MM-dd HH:mm')}" type="text" class="form-control" placeholder="kuangstudy" name="birth">
**敲重点!**这样的话,编辑操作就完成了,但是我们发现,每编辑一次就会多一条数据,这时我们可以加上一个隐藏域id,这样就不会重复添加了
<input th:value="${emp.getId()}" name="id" type="hidden">
7.404、500处理
404、500在Spring Boot中处理非常方便,只需要在templates文件夹下建立一个error文件下,将404.html 500.html放在下边即可。!!!
8.注销
<a class="nav-link" th:href="@{/user/logout}">注销</a>
@RequestMapping("/user/logout")
public String loginout(HttpSession session){
session.invalidate();
return "index";
}
注销使用session.invalidate() ,最后返回首页即可。
session.invalidate()是将session设置为失效,一般在退出时使用,但要注意的是:session失效的同时 浏览器会立即创建一个新的session