Spring Boot:实现一个简单的员工管理系统

2023-12-25 12:34:22

Spring Boot - 03

员工管理系统

一、准备工作

  1. 准备静态资源(包括 css、img、js)和 html 页面点此获取资源提取码:3285;
  2. 编写对应的实体类
  3. 编写 Dao 层(暂时不涉及到数据库,因此,数据是随便生成的,也没有 Service 层)。

提示:新建项目时,要导入 thymeleaf 和 web 的启动器以及 lombok 依赖。

1. 第一部分:导入静态资源和 html 页面

静态资源和 html 页面的放置位置

  • 静态资源(包括 css、img、js)放在 static 目录下
  • html 页面放在 templates 目录下只能通过 controller 来跳转。

使用 Thymeleaf 模板引擎:

  • 在头文件中导入约束xmlns:th="http://www.thymeleaf.org"
  • 使用 Thymeleaf 表达式或语法时,在该位置的 html 标签元素前加 th:让 Thymeleaf 替换接管

Thymeleaf 表达式:Link URL Expressions :@{/URL}一定注意:路径要以斜杠开头

2. 第二部分:实体类

编写两个实体类:Department 和 Employee。

3. 第三部分:Dao 层

一个实体类对应一个 Dao,编写两个 Dao:DepartmentDao 和 EmployeeDao。

@Repository
public class DepartmentDao {

    // 模拟数据库中的数据
    private static Map<Integer, Department> departments = new HashMap<>();

    static {
        departments.put(1001, new Department(1001, "教学部"));
        departments.put(1002, new Department(1002, "研发部"));
        departments.put(1003, new Department(1003, "市场部"));
        departments.put(1004, new Department(1004, "后勤部"));
    }

    // 查询所有的部门
    public Collection<Department> selectAllDepartments() {
        return departments.values();
    }

    // 根据 ID 查询部门
    public Department selectDepartmentById(int id) {
        return departments.get(id);
    }

    // 根据部门名称查询部门 ID 
    public Integer selectIdByDepartName(String departmentName) {
        Collection<Department> values = departments.values();
        for (Department value : values) {
            if (departmentName.equals(value.getDepartmentName())) {
                return value.getId();
            }
        }
        return 0;
    }
}
@Repository
public class EmployeeDao {

    @Autowired
    private DepartmentDao departmentDao;
    // 模拟数据库中的数据
    private static Map<Integer, Employee> employees = new HashMap<>();

    static {
        employees.put(1, new Employee(1, "小明", "123456@qq.com", 1, new Department(1001, "教学部")));
        employees.put(2, new Employee(2, "小强", "100211@qq.com", 1, new Department(1002, "研发部")));
        employees.put(3, new Employee(3, "大杜", "789456@qq.com", 0, new Department(1003, "市场部")));
        employees.put(4, new Employee(4, "张三", "000111@qq.com", 0, new Department(1004, "后勤部")));
        employees.put(5, new Employee(5, "月光", "448833@qq.com", 1, new Department(1002, "研发部")));
    }

    private int initIndex = 6;
    // 增加员工
    public boolean addEmployee() {
        int index = initIndex++;
        employees.put(index, new Employee(index, "员工" + index, "111222@qq.com",
                        new Random().nextInt(2),
                        departmentDao.selectDepartmentById(1001 + (new Random().nextInt(4)))));
        return true;
    }

    // 修改员工信息
    public boolean updateEmployee(Employee employee) {
        // 使员工的部门 id 与部门名称对应起来
        employee.setDepartment(new Department(
                departmentDao.selectIdByDepartName(employee.getDepartment().getDepartmentName()),
                employee.getDepartment().getDepartmentName())
                );
        // 覆盖原来的数据
        employees.put(employee.getId(), employee);
        System.out.println(employees.get(employee.getId()));
        return true;
    }

    // 查询全部员工
    public Collection<Employee> selectAllEmployees() {
        return employees.values();
    }

    // 根据 ID 查询员工
    public Employee selectEmployeeById(int id) {
        return employees.get(id);
    }

    // 删除员工
    public boolean deleteEmployee(int id) {
        employees.remove(id);
        return true;
    }
}

二、首页实现

方式一:可以在 controller 中配置

@RequestMapping({"/", "/index.html"})
public String index() {
    return "index";
}

说明:访问 //index.html 都会跳转到首页。

方式二:可以在扩展配置类中配置,使 url 与要跳转的页面一一映射

说明:配置首页时,一般用扩展配置类进行配置。

运行结果


三、登录功能

设置前端页面

编写后端代码

结果显示

注意:可以看到登录成功和失败都可以达到想要的效果,但是两种情况的 url 都一样,接下来进行一点改进。

改进:登录成功时,重定向到 /main.html 请求,再通过配置,使得 /main.html 请求与登录成功页面相映射。

效果

总结

  1. 提交表单需要 name 属性,并且提交方式 method 要与 controller 中方法的请求方式一致
  2. 为了安全,提交方式用 post,这样 url 中不会显示表单中提交的参数;
  3. 相同的 url 请求地址,使用不同的请求方法,得到的结果也不同,浏览器默认为 get 请求方法
  4. 如果直接在地址栏输入 http://localhost:8080/Sun/main.html ,也可以直接跳转到成功页面,因此需要增加拦截器
  5. 可以在 Spring Boot 核心配置文件中:关闭模板引擎的缓存,设置项目虚拟路径
# 关闭模板引擎的缓存
spring.thymeleaf.cache=false
# 设置项目虚拟路径
server.servlet.context-path=/Sun

四、登录拦截器实现

拦截器进行拦截操作的依据就是:是否进行了登录操作。因此,在登录成功后,在 session 中存放指定信息

实现拦截器的方法

  1. 自定义一个拦截器,实现 HandlerInterceptor 接口;
  2. 重写 preHandle 方法,判断是否拦截,以及进行拦截操作
  3. 在 WebMvc 扩展配置类中重写 addInterceptors 方法,进行配置。

如果未经登录,直接在地址栏输入 http://localhost:8080/Sun/main.html ,会被拦截,效果


五、增删改查

1. 查询员工

后端

@Controller
public class MyController {

    @Autowired
    private EmployeeDao employeeDao;

    // 查询全部员工
    @RequestMapping("/select")
    public String select(Model model) {
        Collection<Employee> employees = employeeDao.selectAllEmployees();
        model.addAttribute("employees", employees);
        return "list";
    }
}

注意

  • 注解 @RequestMapping 中的路径会改变 url
  • model 对象将数据存放在 request 域中,所以在请求转发时会携带 model 对象的数据;
  • 这里的 return "list"请求转发,会经过视图解析器。

前端

效果

2. 增加员工

后端

// 增加员工
@RequestMapping("/add")
public String add() {
    employeeDao.addEmployee();
    return "redirect:/select";
}

前端

效果

3. 修改员工信息

后端

// 跳转到修改员工信息页面
@RequestMapping("/update/{employeeId}")
public String update(@PathVariable("employeeId") int id, Model model) {
    Employee employee = employeeDao.selectEmployeeById(id);
    model.addAttribute("employee", employee);
    return "update";
}

// 修改员工信息
@PostMapping("/update")
public String updateEmployee(Employee employee) {
    employeeDao.updateEmployee(employee);
    return "redirect:/select";
}

前端:展示信息页面

前端:修改员工信息页面

说明

  • 跳转到修改员工信息页面时,会携带该员工的所有信息,通过 value 属性可以显示初始值
  • 后端接收的参数为 Employee 对象,但是员工的 id 不需要被修改,因此,将 id 属性放在隐藏域中
  • 前端在提交属性的值时,如果该属性是一个对象,无法直接提交,必须提交的是对象的单个属性,如:department.departmentName

效果

4. 删除员工

后端

// 删除员工
@RequestMapping("/delete/{employeeId}")
public String delete(@PathVariable("employeeId") int id) {
    employeeDao.deleteEmployee(id);
    return "redirect:/select";
}

前端

效果


六、退出登录

通过在 session 中移除登录信息,实现退出登录的功能。

后端

// 注销
@RequestMapping("/user/logout")
public String logout(HttpSession session) {
    session.removeAttribute("loginUser");
    return "redirect:/index.html";
}

前端

效果


七、总结

  1. 在修改员工信息后提交表单时,出现 Failed to convert from type [java.lang.String] to type [java.util.Date] 错误:

    • 原因:前端表单提交的时间字段是 String 类型,后端无法将其解析为 Date 类型的数据;
    • 解决方法:在实体类时间字段上加注解 @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") 声明。
  2. 请求转发重定向区别:

    区别请求转发重定向
    行为服务端行为客户端行为
    速度
    请求个数一个请求两个不同的请求
    URL 地址不改变改变
    Request 域的信息可以访问(因为是同一个请求)不能访问
    WEB-INF 文件夹可以访问不能访问

    说明

    • 请求转发:客户端 – 请求 – 服务端(请求转发) – 同一个请求 – 目标页面;
    • 重定向:客户端 – 请求 – 服务端 – 重定向响应 – 客户端(重定向) – 新的请求 – 服务端 – 目标页面。
  3. 前端在提交属性的值时,如果该属性是一个对象,无法直接提交,必须提交的是对象的单个属性

  4. Spring 用自动装配(从容器中取对象)代替了 new 对象。因此,创建对象时,可以 new 对象,也可以自动装配对象;

  5. 自动装配 @Autowired 不能在静态变量上使用,因为当创建类,类加载器加载静态变量时,Spring 上下文尚未加载,所以类加载器不会在 bean 中正确注入静态类,注入结果为 null ;

  6. 定制错误界面的方法:在 templates 包下新建 error 文件夹,将错误界面如 404.html500.html 放到 error 文件夹下即可。

  1. 编写一个网站,需要先分析需求,设计数据库,然后设计前端页面,前端需要能够独立运行后端接收数据,完成功能的实现
    • 前端:用模板(别人已经写好的)或者框架(组件,需要自己手动组合拼接);
    • 后端:要有一套自己熟悉的后台模板

注意:

  1. 获取本项目点此进入提取码:3285;
  2. 学习时,多问几个为什么,刨根问底,看源码,但也不能钻牛角尖,适度。

文章来源:https://blog.csdn.net/taiyang3285/article/details/135195421
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。