Springboot实战:员工管理系统

发布于:2022-11-01 ⋅ 阅读:(561) ⋅ 点赞:(0)

目录

(一)准备工作

1.1 导入资源

 1.2 编写pojo层

1.3 编写dao层

0x01 部门dao

0x02 员工dao

(二)、首页实现

2.1 引入Thymeleaf

2.2 编写MyMvcConfig

 2.3 测试首页

 2.4 小结

(三)、页面国际化

3.1 File Encodings设置

3.2 配置文件编写

配置文件生效探究

配置页面国际化值

小结

(四)、登录+拦截器

4.1、登录

0x01 禁用模板缓存

0x02 登录

4.2 登录拦截器

1、在LoginController添加serssion

2、自定义一个拦截器:

3、然后将拦截器注册到我们的SpringMVC配置类当中

4、我们然后在后台主页,获取用户登录的信息

(五)展示员工列表

5.1 员工列表页面跳转

5.2 Thymeleaf 公共页面元素抽取

0x01 步骤:

0x02 实现:

 5.3 员工信息页面展示

(六)、添加员工实现

6.1、表单及细节处理

6.2 具体添加功能

(七)修改员工信息

0x01 逻辑分析:

0x02 实现

(八)删除员工实现

(九)404及注销

404

注销


(一)准备工作


1.1 导入资源


  • css,js等放在static文件夹下
  • html 放在 templates文件夹下

Spring | SpringBoot项目员工管理系统静态资源链接_-BoBooY-的博客-CSDN博客

 1.2 编写pojo层


员工表

//员工表
@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();
    }
}

部门表

//部门表
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
    private int id;  //部门id
    private String departmentName;  //部门名字
}

添加lombok依赖

<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

1.3 编写dao层


这里模拟数据库

0x01 部门dao


import com.kuang.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<Integer, Department>(); //创建一个部门表
 
        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);
    }
}

0x02 员工dao


import com.kuang.pojo.Department;
import com.kuang.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;
 
//员工dao
@Repository //被string托管
public class EmployeeDao {
 
    //模拟数据库中的数据
    private static Map<Integer, Employee> employees= null;
    //员工所属的部门
    @Autowired
    private DepartmentDao departmentDao;
    static {
        employees = new HashMap<Integer,Employee>(); //创建一个部门表
 
        employees.put(1001,new Employee(  1001,"AA","1622840727@qq.com",1,new Department(101,"教学部")));
        employees.put(1002,new Employee(  1002,"BB","2622840727@qq.com",0,new Department(102,"市场部")));
        employees.put(1003,new Employee(  1003,"CC","4622840727@qq.com",1,new Department(103,"教研部")));
        employees.put(1004,new Employee(  1004,"DD","5628440727@qq.com",0,new Department(104,"运营部")));
        employees.put(1005,new Employee(  1005,"FF","6022840727@qq.com",1,new Department(105,"后勤部")));
    }
    //主键自增
    private static Integer ininId = 1006;
    //增加一个员工
    public void save(Employee employee){
        if(employee.getId() == null){
            employee.setId(ininId++);
        }
        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);
    }
}

(二)、首页实现


2.1 引入Thymeleaf


<!--thymeleaf-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

2.2 编写MyMvcConfig


import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
//扩展使用SpringMVC
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
    }
}

所有的静态资源都需要使用thymeleaf接管:@{}

application.properties 修改:

 2.3 测试首页


 2.4 小结


  • 所有页面的静态资源都需要使用thymeleaf接管
  • url: @{}

(三)、页面国际化


3.1 File Encodings设置

先在IDEA中统一设置properties的编码问题

 

3.2 配置文件编写


1、我们在resources资源文件下新建一个i18n目录,存放国际化配置文件

2、建立一个login.properties文件,还有一个login_zh_CN.properties;发现IDEA自动识别了我们要做国际化操作;文件夹变了。

  •  login.properties :默认
login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名
  • 英文:
login.btn=Sign in
login.password=Password
login.remember=Remember me
login.tip=Please sign in
login.username=Username
  • 中文:
login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名

OK,配置文件步骤搞定。

配置文件生效探究


  • 我们去看一下SpringBoot对国际化的自动配置!这里又涉及到一个类:MessageSourceAutoConfiguration
  • 里面有一个方法,这里发现SpringBoot已经自动配置好了管理我们国际化资源文件的组件 ResourceBundleMessageSource;
// 获取 properties 传递过来的值进行判断
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    if (StringUtils.hasText(properties.getBasename())) {
        // 设置国际化文件的基础名(去掉语言国家代码的)
        messageSource.setBasenames(
            StringUtils.commaDelimitedListToStringArray(
                                       StringUtils.trimAllWhitespace(properties.getBasename())));
    }
    if (properties.getEncoding() != null) {
        messageSource.setDefaultEncoding(properties.getEncoding().name());
    }
    messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
    Duration cacheDuration = properties.getCacheDuration();
    if (cacheDuration != null) {
        messageSource.setCacheMillis(cacheDuration.toMillis());
    }
    messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
    messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
    return messageSource;
}

我们真实的情况是放在了i18n目录下,所以我们要去配置这个messages的路径;

spring.messages.basename=i18n.login

配置页面国际化值


去页面获取国际化的值,查看Thymeleaf的文档,找到message取值操作为:#{…}。我们去页面测试下: 

  • 我们可以去启动项目,访问一下,发现已经自动识别为中文的了

 

小结

  • 需要配置 i18n 文件
  • 如果需要在项目中进行按钮自动切换,则要自定义一个组件 LocalReasolver
  • 记得将自己的组件配置到 Spring 容器 @Bean
  • #{}

(四)、登录+拦截器


4.1、登录

0x01 禁用模板缓存


页面存在缓存,所以我们需要禁用模板引擎的缓存

#禁用模板缓存 
spring.thymeleaf.cache=false

模板引擎修改后,想要实时生效。页面修改完毕后,IDEA小技巧 : Ctrl + F9 重新编译。

0x02 登录


我们这里就先不连接数据库了,输入任意用户名都可以登录成功

  • 我们把登录页面index.html的表单提交地址写一个controller
<form class="form-signin" th:action="@{/user/login}" method="post">
 //这里面的所有表单标签都需要加上一个name属性 
 
</form>
  • 去编写对应的controller
@Controller
public class LoginController {
    @RequestMapping("/user/login")
    public String login(
            @RequestParam("username") String username ,
            @RequestParam("password") String password,
            Model model){
        //具体的业务
        if(!StringUtils.isEmpty(username)&&"123456".equals(password)){
            return "redirect:/main.html";
        }
        else{
            //告诉用户,你登录失败
            model.addAttribute("msg","用户名或者密码错误!");
            return "index";
        }
    }
}

OK ,测试登录成功.

  •  登录失败的话,我们需要将后台信息输出到前台,可以在首页标题下面加上判断
<!--判断是否显示,使用if, ${}可以使用工具类,可以看thymeleaf的中文文档--> 
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"> 
</p>
  • 我们再添加一个视图控制映射,在我们的自己的MyMvcConfifig中:
registry.addViewController("/main.html").setViewName("dashboard");
  • 将 Controller 的代码改为重定向:
//登录成功!防止表单重复提交,我们重定向 
return "redirect:/main.html";

4.2 登录拦截器


但是又发现新的问题,我们可以直接登录到后台主页,不用登录也可以实现。明显的逻辑漏洞,我们可以使用拦截器机制,实现登录检查。

1、在LoginController添加serssion

 session.setAttribute("loginUser",username);

 

2、自定义一个拦截器:

//自定义拦截器
public class LoginHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取 loginUser 信息进行判断
        Object user = request.getSession().getAttribute("loginUser");
        if(user == null){//未登录,返回登录页面
            request.setAttribute("msg","没有权限,请先登录");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else{
            //登录,放行
            return true;
        }
    }
}

3、然后将拦截器注册到我们的SpringMVC配置类当中

@Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册拦截器,及拦截请求和要剔除哪些请求!
        // 我们还需要过滤静态资源文件,否则样式显示不出来
        registry.addInterceptor(new LoginHandlerInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/index.html","/user/login","/","/css/*","/img/**","/js/**");
}

4、我们然后在后台主页,获取用户登录的信息

<!--后台主页显示登录用户的信息-->
[[${session.loginUser}]] <!--$取EL表达式-->

(五)展示员工列表


5.1 员工列表页面跳转

我们在主页点击Customers,就显示列表页面;我们去修改下

  1. 将首页的侧边栏Customers改为员工管理
  2. a链接添加请求
<a class="nav-link" th:href="@{/emps}">员工管理</a>

  3. 将list放在emp文件夹下

  4. 编写处理请求的controller

//员工列表
@Controller
public class EmployeeController {
 
    @Autowired
    EmployeeDao employeeDao;
 
    @RequestMapping("/emps")
    public String list(Model model){
        Collection<Employee> employees = employeeDao.getALL();
        model.addAttribute("emps",employees);
        return "emp/list";
    }
}

我们启动项目,测试一下看是否能够跳转,测试成功。我们只需要将数据渲染进去即可,但是发现了一个问题,侧边栏和顶部都相同,我们是不是应该将它抽取出来?(文件包含漏洞)

5.2 Thymeleaf 公共页面元素抽取


0x01 步骤:

  1. 抽取公共片段 th:fragment 定义模板名
  2. 引入公共片段 th:insert 插入模板名

0x02 实现:

  • 1、我们来抽取一下,使用list列表做演示。我们要抽取头部nav标签,我们在dashboa rd中将nav部分定义一个模板名;
<!--顶部导航栏-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">
    <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</a> <!--$取EL表达式-->
    <input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
    <ul class="navbar-nav px-3">
        <li class="nav-item text-nowrap">
            <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">注销</a>
        </li>
    </ul>
</nav>

  • 2、然后我们在list页面中去引入,可以删掉原来的nav
<!--引入抽取的topbar--> 
<!--模板名 : 会使用thymeleaf的前后缀配置规则进行解析 使用~{模板::标签名}-->
<!--顶部导航栏-->
<div th:insert="~{dashboard::topbar}"></div
  • 3、启动再次测试,可以看到已经成功加载过来了

说明:


除了使用insert插入,还可以使用replace替换,或者include包含,三种方式会有一些小区别,可以见名知义;

我们使用replace替换,可以解决div多余的问题,可以查看thymeleaf的文档学习,侧边栏也是同理

  • 定义模板:
<!--侧边栏-->
<nav th:fragment="sidebar" class="col-md-2 d-none d-md-block bg-light sidebar">
  • 然后我们在list页面中去引入:
<!--侧边栏-->
<div th:insert="~{dashboard::sidebar}"></div>

启动再试试,看效果

 5.3 员工信息页面展示


现在我们来遍历我们的员工信息,顺便美化一些页面,增加添加,修改,删除的按钮。

<thead>
    <tr>
        <th>id</th>
        <th>lastName</th>
        <th>email</th>
        <th>gender</th>
        <th>department</th>
        <th>birth</th>
    </tr>
</thead>
<tbody>
    <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.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>

(六)、添加员工实现


6.1、表单及细节处理

  • 1、将添加员工信息改为超链接
<h2><a class="btn btn-sm btn-success" th:href="@{/emp}">添加员工</a></h2>
  • 2、编写对应的controller
//to员工添加页面 
@GetMapping("/emp") 
public String toAddPage(){ 
    return "emp/add"; 
}
  • 3、添加前端页面;复制list页面,修改即可

bootstrap官网文档 : Forms · Bootstrap v4 中文文档 v4.6 | Bootstrap 中文网

<form th:action="@{/emp}" method="post" >
    <div class="form-group" ><label>LastName</label>
        <input class="form-control" placeholder="kuangshen" type="text" name="lastName">
    </div>
    <div class="form-group" ><label>Email</label>
        <input class="form-control" placeholder="24736743@qq.com" type="email" name="email">
    </div>
    <div class="form-group"><label>Gender</label><br/>
        <div class="form-check form-check-inline">
            <input class="form-check-input" name="gender" type="radio" value="1">
            <label class="form-check-label">男</label>
        </div>
        <div class="form-check form-check-inline">
            <input class="form-check-input" name="gender" type="radio" 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 class="form-control" placeholder="kuangstudy" type="text" name="birth">
    </div>
    <button class="btn btn-primary" type="submit">添加</button>
</form>
  • 4、部门信息下拉框应该选择的是我们提供的数据,所以我们要修改一下前端和后端

Controller

@GetMapping("/emp")
public String toAddPage(Model model){
    //查询所有的部门信息
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments",departments);
    return "emp/add";
}

前端

<select class="form-control" name="department.id">
    <option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option>
</select>

6.2 具体添加功能


1、修改add页面form表单提交地址和方式

<form th:action="@{/emp}" method="post">

2、编写controller

//员工添加功能
//接收前端传递的参数,自动封装成为对象[要求前端传递的参数名,和属性名一致]
@PostMapping ("/emp")
public String addEmp(Employee employee){
    //保存员工的信息
    System.out.println(employee);
    employeeDao.save(employee);
    // 回到员工列表页面,可以使用redirect或者forward,就不会被视图解析器解析
    return "redirect:/emps";
}

(七)修改员工信息


0x01 逻辑分析:

我们要实现员工修改功能,需要实现两步:

  1. 点击修改按钮,去到编辑页面,我们可以直接使用添加员工的页面实现
  2. 显示原数据,修改完毕后跳回列表页面

0x02 实现


1、我们去实现一下,首先修改跳转链接的位置

<a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.getId()}">编辑</a>

2、编写对应的controller

//员工修改页面
@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";
}

3、我们需要在这里将add页面复制一份,改为update页面;需要修改页面,将我们后台查询数据回显

<form th:action="@{/emp}" method="post" >
    <input type="hidden" name="id" th:value="${emp.getId()}">
    <div class="form-group" ><label>LastName</label>
        <input th:value="${emp.getLastName()}" class="form-control" placeholder="kuangshen" type="text" name="lastName">
    </div>
    <div class="form-group" ><label>Email</label>
        <input th:value="${emp.getEmail()}" class="form-control" placeholder="24736743@qq.com" type="email" name="email">
    </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" name="gender" type="radio" value="1">
            <label class="form-check-label">男</label>
        </div>
        <div class="form-check form-check-inline">
            <input th:checked="${emp.getGender()==0}" class="form-check-input" name="gender" type="radio" 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.id==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 th:value="${#dates.format(emp.birth,'yyyy-MM-dd HH:mm')}" class="form-control" placeholder="2022-02-02" type="text" name="birth">
    </div>
    <button class="btn btn-primary" type="submit">修改</button>
</form>

(八)删除员工实现


1、list页面,编写提交地址

<a class="btn btn-sm btn-danger"  th:href="@{/delEmp/}+${emp.getId()}">删除</a>

2、编写Controller

//删除员工
@GetMapping("/delEmp/{id}")
public String delEmp(@PathVariable("id") Integer id){
    employeeDao.delete(id);
    return "redirect:/emps";
}

(九)404及注销


404

我们只需要在模板目录下添加一个error文件夹,文件夹中存放我们相应的错误页面;

比如404.html 或者 4xx.html 等等,SpringBoot就会帮我们自动使用了!

注销


1、注销请求

<a class="nav-link" th:href="@{/user/logout}">注销</a>

2、对应的controller

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

本文含有隐藏内容,请 开通VIP 后查看