前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Boot 实现员工信息管理demo

Spring Boot 实现员工信息管理demo

作者头像
LCyee
发布2020-08-05 17:18:39
1.5K0
发布2020-08-05 17:18:39
举报

员工管理系统DEMO

一、安装lombok插件

这里我们使用lombok帮助我们自动生成pojo包的getter和setter等函数结构

在IDEA中安装lombok插件

等待插件安装完成后,在项目pom中导入lombok

代码语言:javascript
复制
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

二、构建数据库(模拟)

在整合mybets之前,我们手动构建pojo和dao层进行模拟数据库

使用相应的注解来完善pojo结构

  • @Data 注解用于生成属性的getter与setter
  • @AllArgsConstructor 用于生成有参构造函数
  • @NoArgsConstructor 用于生成无参构造函数

0x01 pojo层

Department.java

代码语言:javascript
复制
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
    private Integer id;
    private String departmentName;
}

Employee.java

代码语言:javascript
复制
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;
    private Department department;
    private Date birth;
}

0x02 dao层

二、登录页面实现

在自定义MVC配置中重写一个 addViewControllers ,用来添加一些基本的视图控制器

代码语言:javascript
复制
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
        registry.addViewController("/index/").setViewName("index");
    }
}

测试访问 http://localhost:8080/index

三、页面国际化配置(多语言)

0x01 添加配置文件

设置IDEA的文件编码

在 resources 目录下创建 i18n 目录,用来存放多语言的配置文件,并创建如下文件结构

login.properties 是我们的主配置文件, login_en_XX.properties 是我们的指定的各个语言的配置文件

点击可视化配置 Resource Bundle ,添加一个配置键值对,这里我们命名login.tip

在编辑器的右边输入对 login.tip 进行各个语言的配置,会分别映射到我们刚才创建好的几个语言的配置文件中

按照如上步骤,我们把页面的几个标签对应的也配置好

在配置文件 application.properties 中绑定多语言配置文件位置

代码语言:javascript
复制
spring.messages.basename=i18n.login

0x02 替换HTML中的标签

使用 thymeleaf 模板语法中的 th:XX="#{}" 对各个标签进行接管,例如

代码语言:javascript
复制
<label class="sr-only" th:text="#{login.username}">Username</label>

#{} 中填写刚才我们在配置文件中添加的键

0x03 自定义一个转换器

在config中自定义一个转换器 MyLocaleResolver ,根据用户请求的参数进行设置页面的语言

代码语言:javascript
复制
public class MyLocaleResolver implements LocaleResolver {

    //解析请求
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        //获取请求中的语言参数
        String language = request.getParameter("lang");
        Locale locale = Locale.getDefault(); //如果没有就使用默认的

        //如果请求的链接携带了国际化的参数
        if (!StringUtils.isEmpty(language)){
            //分割字符串
            String[] lang_split = language.split("_");
        	locale = new Locale(lang_split[0], lang_split[1]);
    	}
        return locale;
}

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}

在我们之前自定义的mvc类中,使用 @Bean 注解将我们的转换器 MyLocaleResolver 配置到spring容器内

代码语言:javascript
复制
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
        registry.addViewController("/index/").setViewName("index");
    }

    //将自定义的国际化组件注册到spring bean中
    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}

接下来在HTML模板中使用thymeleaf模板语法中的 th:href="@{xxx.html(key=value)}",设置跳转请求

代码语言:javascript
复制
<a class="btn btn-sm" th:href="@{/index.html(lang='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(lang='en_US')}">English</a>

重新启动项目,查看效果

成功实现多语言的切换

四、登录功能实现

0x01 接口测试

创建一个Controller,我这里命名为 LoginController ,编写基本的结构,返回一个字符串进行测试

代码语言:javascript
复制
@Controller
public class LoginController {
    @RequestMapping("/user/login")
    public String Login(){
        return "OK";
    }
}

在HTML中提交的表单中修改请求url

代码语言:javascript
复制
   <form class="form-signin" action="/user/login" method="POST">

测试

0x02 编写登录逻辑

代码语言:javascript
复制
@Controller
public class LoginController {

    @RequestMapping("/user/login")
    public String Login(
            @RequestParam("username") String username,
            @RequestParam("password") String password,
            Model model
    ){
        if(("admin".equals(username) && "123123".equals(password))){
            session.setAttribute("loginUser", username);
            //重定向至main页面
            return "redirect:/main";
        }else{  
            model.addAttribute("msg", "用户名或密码错误");  //将错误信息渲染至页面
            return "index";
        }
    }
}

这里暂时没有整合数据库,所以直接判断页面提交的值是否等于预定义的值,如果等于则重定向到main页面,否则返回登录页并渲染错误信息

前端页面新增一个p标签用于显示错误信息,使用 thymeleaf 模板引擎进行渲染

代码语言:javascript
复制
<!--如果msg值为空则不显示错误信息-->
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>

添加一个main页面的路由,这里我在自定义的mvc配置类中重写了一个视图控制器,也可以自己新增一个controller进行路由

代码语言:javascript
复制
registry.addViewController("/main").setViewName("dashboard");

0x03 添加登录拦截器

自定义一个拦截器LoginHandlerInterceptor,并实现 HandlerInterceptorpreHandle方法,自定义拦截的逻辑

代码语言:javascript
复制
public class LoginHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //拦截逻辑
        Object loginUser = request.getSession().getAttribute("loginUser");
        if(loginUser == null){
            //设置提示信息
            request.setAttribute("msg","没有权限,请先登录");
            //跳转回到主页
            request.getRequestDispatcher("/").forward(request, response);
            return false;
        }
        return true;
    }
}

在我们自定义的springmvc配置类中注册我们的拦截器 LoginHandlerInterceptor

代码语言:javascript
复制
//注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
    //设置拦截的黑名单和白名单
    //我们还要给静态资源设置白名单,不然显示不出来
    registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
            .excludePathPatterns("/", "/index*","/user/login", "/css/**", "/img/**", "/js/**");
}

登录成功后取session中的用户名显示到main页面

代码语言:javascript
复制
<a>[[${session.loginUser}]]</a>

0x04 测试

测试拦截器、登录验证、主页显示

五、展示员工信息

0x01 定义页面模板

我们从main页面种可以看出,页面的顶部栏和侧边栏的样式的固定的,所以我们可以将这两个部分独立成模块,在创建新的页面时我们可以直接复用预定义好的模块,减少代码量

我们新建一个 base.html 的页面,用于定义我们模块的代码,使用 th:fragment 标签定义模块的名称,在其他页面使用 th:insertth:replace 引用模板

  • th:insert :保留自己的主标签,保留th:fragment的主标签。
  • th:replace :不要自己的主标签,保留th:fragment的主标签。

定义模板

代码语言:javascript
复制
<!--顶部栏-->
<nav th:fragment="topBar" class="navbar"></nav>
代码语言:javascript
复制
<!--侧边栏-->
<nav th:fragment="leftBar" class="col-md-2"></nav>

引用模板

代码语言:javascript
复制
<!--顶部栏-->
<div th:replace="~{commons/dashboard_base :: topBar}"></div>
代码语言:javascript
复制
<!--侧边栏-->
<div th:replace="~{commons/dashboard_base :: leftBar}"></div>

0x02 侧边栏高亮

需求

在点击侧边栏的功能时候,需要在跳转页面后将指定的项高亮显示,例如下图

具体实现

在引用模板时候增加一个页面变量作为标识,如下代码

代码语言:javascript
复制
<div th:replace="~{commons/dashboard_base :: leftBar(barType='emps')}"></div>

在上面的代码当中,我们定义了一个barType的变量,作为页面类型的标识

接下来我们在base模板中对页面传递过来的变量进行识别

代码语言:javascript
复制
<li class="nav-item">
     <a th:class="${barType == 'main'? 'nav-link active': 'nav-link'}" th:href="@{/main}"></a>
 </li>
<li class="nav-item">
   <a th:class="${barType == 'emps'? 'nav-link active': 'nav-link'}" th:href="@{/emps/info}"></a>
</li>

在上面的代码当中,我们使用了thymeleaf 的三元运算符进行渲染,如果传递过来的barType 符合预期设定的值,则在标签的class中增加active实现高亮

0x03 控制器

定义一个Controller,使用Autowired 标识将EmployeeDao注入到当前Controller中,用于实现对employee的pojo的一些操作,调用了getEmpsInfo函数获取所有员工信息的值,并将所有员工信息作为model传递到页面中,代码如下

EmployeeController.java

代码语言:javascript
复制
@Controller
public class EmployeeController {

    @Autowired
    EmployeeDao employeeDao;    //注入

    @GetMapping("/emps/info")
    public String showInfo(Model model){
        Collection<Employee> empsInfo = employeeDao.getEmpsInfo();
        model.addAttribute("empsInfo", empsInfo);
        return "employee/info";
    }
}

在info页面中定义一个table标签,使用 th:each 对controller传递到页面的员工信息进行遍历,并渲染到页面,代码实现如下

emps/info.html

代码语言:javascript
复制
<table class="table table-hover">
    <thead>
        <tr>
            <th>ID</th>
            <th>姓名</th>
            <th>邮箱</th>
            <th>性别</th>
            <th>部门</th>
            <th>生日</th>
            <th>操作</th>
        </tr>
    </thead>
    <tr th:each="emp:${empsInfo}">
        <th th:text="${emp.id}"></th>
        <td th:text="${emp.lastName}">2</td>
        <td th:text="${emp.email}">3</td>
        <td th:text="${emp.gender}">4</td>
        <td th:text="${emp.department.departmentName}">5</td>
        <!--格式化日期-->
        <td th:text="${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm')}"></td>
        <td>
            <button type="button" class="btn btn-primary btn-sm">编辑</button>
            <button type="button" class="btn btn-danger btn-sm">删除</button>
        </td>
    </tr>
</table>

0x05 实现效果

六、添加员工信息

0x01 实现思路

  1. 点击添加员工按钮,提交GET请求至控制器,并携带部门信息渲染至add页面
  2. 用户填写信息,提交POST请求至controller
  3. 控制器将表单提交的employee对象保存至对象数据中

0x02 提交GET请求

/emps/info.html

代码语言:javascript
复制
<h2><a style="color: white;" class="btn btn-sm btn-info" th:href="@{/emps/add}">添加员工</a></h2>

控制器返回add页面,并携带部门名称信息

代码语言:javascript
复制
@Autowired
EmployeeDao employeeDao;    //注入Dao
@Autowired
DepartmentDao departmentDao;

@GetMapping("/emps/add")
    public String addEmp(Model model){
        Collection<Department> departments = departmentDao.getDepartments();    //传递部门信息到前端
        model.addAttribute("departments", departments);
        return "employee/add";
}

add.html页面主体数据

代码语言:javascript
复制
<!--添加员工表单-->
<form th:action="@{/emps/add}" th:method="POST">
   <div class="form-group">
      <label>LastName</label>
      <input name="lastName" type="text" class="form-control" placeholder="b5ck">
   </div>
   <div class="form-group">
      <label>Email</label>
      <input name="email" type="email" class="form-control" placeholder="XXXXX@qq.com">
   </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" checked="true">
         <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="dep:${departments}" th:value="${dep.getId()}" th:text="${dep.getDepartmentName()}"></option>
      </select>
   </div>
   <div class="form-group">
      <label>Birth</label>
      <input NAME="birth" type="text" class="form-control date-cell" placeholder="2020-01-01">
   </div>
   <button type="submit" class="btn btn-primary">添加</button>

页面效果

0x03 提交POST请求

携带用户填写的数据,控制器接收请求

代码语言:javascript
复制
   @PostMapping("/emps/add")
    public String addEmpPost(Employee employee, RedirectAttributes model){
        employeeDao.save(employee);
        model.addFlashAttribute("add",true);
        return "redirect:/emps/info";
//        return "employee/info";
    }

在上述代码中,接收到了用户提交表单的数据,转换为Employee对象,并调用前面代码中注入的employeeDao中的save函数将对象写入现有的数据中。

写入成功后,我们传递一个名称为add的model值至页面,用于标识添加成功,在页面添加相应的提示,因为这里使用的是redirect进行重定向页面,所以需要使用RedirectAttributes对象来传递model值至页面。

在info页面中添加一个提示框标签

代码语言:javascript
复制
<!--添加成功提示框-->
<div th:if="${add == true}" class="alert alert-success alert-dismissable">
   <button type="button" class="close" data-dismiss="alert"
         aria-hidden="true">
      &times;
   </button>
   员工信息添加成功!
</div>

该标签中使用th:if语句对model对象add进行判断,值为true时才对该div标签进行渲染,页面效果如下

controller全部代码

代码语言:javascript
复制
@Controller
public class EmployeeController {
    @Autowired
    EmployeeDao employeeDao;    //注入Dao
    @Autowired
    DepartmentDao departmentDao;

    @GetMapping("/emps/info")
    public String showInfo(Model model){
        Collection<Employee> empsInfo = employeeDao.getEmpsInfo();
        model.addAttribute("empsInfo", empsInfo);
        return "employee/info";
    }

    @GetMapping("/emps/add")
    public String addEmp(Model model){
        Collection<Department> departments = departmentDao.getDepartments();    //传递部门信息到前端
        model.addAttribute("departments", departments);
        return "employee/add";
    }

    @PostMapping("/emps/add")
    public String addEmpPost(Employee employee, RedirectAttributes model){
        employeeDao.save(employee);
        model.addFlashAttribute("add",true);
        return "redirect:/emps/info";
    }
}

七、删除员工信息

0x01 实现思路

  1. 用户点击删除按钮,触发模态框再次确认
  2. 点击删除,发送删除请求,请求路径中包含员工ID值

0x02 实现过程

确认框

代码语言:javascript
复制
<!-- 模态框(Modal) -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
   <div class="modal-dialog">
      <div class="modal-content">
         <div class="modal-header">
            <h4 class="modal-title" id="myModalLabel">确定要删除该员工的信息吗?</h4>
         </div>
         <div class="modal-body">
            <label>员工ID</label>
            <input th:value="${emp.id}" disabled="true" class="form-control" type="text" name="" >
            <label style="margin-top: 10px">员工姓名</label>
            <input th:value="${emp.lastName}"  disabled="true" class="form-control" type="text" name="">
         </div>
         <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
            <a class="btn btn-danger btn-default" th:href="@{/emps/delete/}+${emp.id}">确定删除</a>
         </div>
      </div><!-- /.modal-content -->
   </div><!-- /.modal -->
</div>

点击删除按钮,触发模态框

代码语言:javascript
复制
<button class="btn btn-danger btn-sm" data-target="#myModal" data-toggle="modal">删除</button>

控制器

代码语言:javascript
复制
//删除员工信息
@GetMapping("/emps/delete/{id}")
public String toDelete(@PathVariable("id") Integer id, RedirectAttributes model) {
    String lastName = employeeDao.getEmployeeById(id).getLastName();
    employeeDao.delete(id);
    model.addFlashAttribute("msg",  "员工 " + lastName + " 信息已被删除");
    return "redirect:/emps/info";
}

测试删除

八、更新员工信息

0x01 实现思路

  1. 修改编辑按钮:INFO页面在渲染时修改编辑按钮的a标签链接,链接包含该行数据的ID值
  2. 渲染update页面:页面包含该id对应的员工信息数据
  3. 提交update请求

0x02 实现过程

修改编辑按钮

使用th:herf渲染链接,并携带当前行的员工的id号

代码语言:javascript
复制
<a class="btn btn-primary btn-sm" th:href="@{/emps/update/}+${emp.id}">编辑</a>
渲染update页面

控制器代码如下

代码语言:javascript
复制
@GetMapping("/emps/update/{id}")
public String updateEmpInfo(@PathVariable("id") Integer id, Model model){
    Employee employeeById = employeeDao.getEmployeeById(id);
    Collection<Department> departments = departmentDao.getDepartments();    //获取所有部门信息
    System.out.println(employeeById);
    model.addAttribute("emp", employeeById);
    model.addAttribute("deps", departments);
    return "employee/update";
}

使用{}在请求路径中取id值,通过@PathVariable 将id值赋值给变量

根据员工id获取该员工的所有信息,获取所有部门的信息,并渲染至页面中;

update.html页面主体代码如下

代码语言:javascript
复制
<!--更新员工表单-->
<form th:action="@{/emps/update/} + ${emp.id}" th:method="POST">
   <div class="form-group">
      <label>LastName</label>
      <input th:value="${emp.lastName}" name="lastName" type="text" class="form-control" placeholder="b5ck">
      </div>
      <div class="form-group">
         <label>Email</label>
         <input th:value="${emp.email}" name="email" type="email" class="form-control" placeholder="123@qq.com">
      </div>
      <div class="form-group">
         <label>Gender</label><br/>
         <div class="form-check form-check-inline">
            <input th:checked="${emp.gender == 1}" class="form-check-input " type="radio" name="gender"  value="1" checked="true">
            <label class="form-check-label">男</label>
      </div>
      <div class="form-check form-check-inline">
          <!-- 自动选中lable -->
         <input th:checked="${emp.gender == 0}" 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="dep:${deps}" th:selected="${emp.department.id == dep.getId()}" th:value="${dep.getId()}" th:text="${dep.getDepartmentName()}"></option>
      </select>
   </div>
   <div class="form-group">
      <label>Birth</label>
      <input th:value="${#dates.format(emp.birth, 'yyyy-MM-dd HH:mm:ss')}" NAME="birth" type="text" class="form-control date-cell" placeholder="2020-01-01">
   </div>
   <button type="submit" class="btn btn-primary">更新</button>
</form>

前端代码与add.html页面相似,不同的是表单中的值使用th:value从控制器中传递的model取出赋值搭到对应的位置供用户修改;

性别lable中使用th:checked="${emp.gender == 1}"gender值进行判断,使得lable标签能自动选中,而部门select下拉框使用th:selected对当前emp对象的部门ID值与dep值相比较,使得option标签能被自动选择。

实现效果

定义一个用于接收修改请求的控制器

代码语言:javascript
复制
@PostMapping("/emps/update/{id}")
public String toUpdateEmpInfo(@PathVariable("id") Integer id, Employee employee, RedirectAttributes model){
     //由于前端传递过来的只有部门ID号,需要重新将部门名称赋值
    employee.setDepartment(departmentDao.getDepartmentsById(employee.getDepartment().getId()));
    employeeDao.updateInfo(id, employee);
    model.addFlashAttribute("msg", employee.getLastName() +" 信息更新成功");
    return "redirect:/emps/info";
}

同样的从URL中取ID值,调用employeeDao中的updateInfo方法进行员工信息的更新。

修改用户AA的邮箱为123@qq.com,部门为后勤部,点击更新。

更新成功!

九、注销

0x01 实现思路

  1. 定义控制器,获取用户session并清空
  2. 在模板页面内添加一个注销按钮
  3. 重定向页面至index

0x02 实现过程

添加控制器

Controller/LoginController.java

代码语言:javascript
复制
@RequestMapping("/user/logout")
public String Logout(HttpSession session){
    session.invalidate();   //清除该session会话信息
    return "redirect:/index";
}

在模板页面 dashboard_base.html 中添加注销按钮样式,并提交请求

模板路径
模板路径
代码语言:javascript
复制
<a th:href="@{/user/logout}" class="btn btn-warning">Sign out</a>

十、错误页面配置

templates目录下创建一个error目录,创建一个404.html页面,当请求发生404状态时,springboot会自动重定向到404.html页面中

测试404

其他错误状态也是如此,例如500.html403.html

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 员工管理系统DEMO
    • 一、安装lombok插件
      • 二、构建数据库(模拟)
        • 0x01 pojo层
        • 0x02 dao层
      • 二、登录页面实现
        • 三、页面国际化配置(多语言)
          • 0x01 添加配置文件
          • 0x02 替换HTML中的标签
          • 0x03 自定义一个转换器
        • 四、登录功能实现
          • 0x01 接口测试
          • 0x02 编写登录逻辑
          • 0x03 添加登录拦截器
          • 0x04 测试
        • 五、展示员工信息
          • 0x01 定义页面模板
          • 0x02 侧边栏高亮
          • 0x03 控制器
          • 0x05 实现效果
        • 六、添加员工信息
          • 0x01 实现思路
          • 0x02 提交GET请求
          • 0x03 提交POST请求
        • 七、删除员工信息
          • 0x01 实现思路
          • 0x02 实现过程
        • 八、更新员工信息
          • 0x01 实现思路
          • 0x02 实现过程
        • 九、注销
          • 0x01 实现思路
          • 0x02 实现过程
        • 十、错误页面配置
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档