这个项目没有使用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