一、完善登錄功能
1.1 問題分析
1.2 代碼實現
package com.itheima.reggie.filter;//這是一個過濾器類
//登錄檢查過濾器import com.alibaba.fastjson.JSON;
import com.itheima.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.AntPathMatcher;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** 檢查用戶是否已經完成登錄*/
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {//路徑匹配器,支持通配符寫法(專門用來路徑比較的)public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();/*** 過濾的方法* @param servletRequest* @param servletResponse* @param filterChain* @throws IOException* @throws ServletException*/@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;/*** 1、獲取本次請求的URI* 2、判斷本次請求是否需要處理(是否需要檢查用戶已經登錄了)【檢查登錄狀態】* 3、如果不需要處理,則直接放行* 4、判斷登錄狀態,如果已登錄,則直接放行* 5、如果未登錄則返回未登錄結果*///1、獲取本次請求的URIString requestURI = request.getRequestURI();//日志:攔截到的請求log.info("攔截到的請求:{}", requestURI);//2、判斷本次請求是否需要處理(是否需要檢查用戶已經登錄了)【檢查登錄狀態】//定義一些不需要處理的請求路徑(直接放行),只攔截針對Controller的請求String[] urls = new String[]{"/employee/login","/employee/logout","/backend/**","/front/**"};//判斷是否需要處理boolean check = check(urls, requestURI);//3、如果不需要處理,則直接放行//check = true時不需要處理if (check) {log.info("本次請求{}不需要處理", requestURI);//放行filterChain.doFilter(request, response);return;}//4、判斷登錄狀態,如果已登錄,則直接放行if (request.getSession().getAttribute("employee") != null) {log.info("用戶已登錄,用戶id為{}", request.getSession().getAttribute("employee"));//放行filterChain.doFilter(request, response);return;}log.info("用戶未登錄");//5、如果未登錄則返回未登錄結果,通過輸出流方式向客戶端頁面響應數據response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));return;}/*** 路徑匹配,檢查本次請求是否需要放行* @param urls* @param requestURI* @return*///封裝方法public boolean check(String[] urls,String requestURI) {for (String url : urls) {boolean match = PATH_MATCHER.match(url, requestURI);if (match) {return true;}}//整個for循環都遍歷完了都沒有匹配上,就返回falsereturn false;}
}
1.3 功能測試
二、新增員工
2.1 需求分析
2.2 數據模型
2.3 代碼開發
package com.itheima.reggie.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.Employee;
import com.itheima.reggie.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {//自動裝配@Autowiredprivate EmployeeService employeeService;/*** 員工登錄* @param request* @param employee* @return*///前端發送的請求是 post 請求@PostMapping("/login")//接收json數據//requset對象可以getpublic R<Employee> login(HttpServletRequest request, @RequestBody Employee employee){/*** 1、將頁面提交的密碼password進行md5的加密處理* 2、根據頁面提交的用戶名username查詢數據庫* 3、如果沒有查詢到則返回登錄失敗的結果* 4、密碼比對,如果不一致則返回登錄失敗結果* 5、查看員工狀態,如果為已禁用狀態,則返回員工已禁用結果* 6、登錄成功,將員工id存入Session并返回登錄成功結果*/// 1、將頁面提交的密碼password進行md5的加密處理//從employee中把password拿到String password = employee.getPassword();//調用工具類中的md5加密的方法password = DigestUtils.md5DigestAsHex(password.getBytes());//2、根據頁面提交的用戶名username查詢數據庫LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();//添加查詢條件queryWrapper.eq(Employee::getUsername, employee.getUsername());//數據庫已經對user_name做了唯一約束Employee emp = employeeService.getOne(queryWrapper);//3、如果沒有查詢到則返回登錄失敗的結果if(emp == null){return R.error("登錄失敗");}//4、密碼比對,如果不一致則返回登錄失敗結果if(!password.equals(emp.getPassword())){//密碼匹配不成功return R.error("登錄失敗");}//登錄成功//5、查看員工狀態,如果為已禁用狀態,則返回員工已禁用結果if (emp.getStatus() == 0){return R.error("賬號已經被禁用");}//6、登錄成功,將員工id存入Session并返回登錄成功結果request.getSession().setAttribute("employee", emp.getId());//這是我們從數據庫中查出來的對象return R.success(emp);}/*** 退出方法*//*** 員工退出* @param request* @return*/@PostMapping("/logout")public R<String> logout(HttpServletRequest request){//清理Session中保存的當前登錄員工的idrequest.getSession().removeAttribute("employee");return R.success("退出成功");}/*** 新增員工* @param employee* @return*/@PostMappingpublic R<String> save(HttpServletRequest request,@RequestBody Employee employee){log.info("新增員工,員工信息:{}",employee.toString());//設置初始密碼:123456,需要進行md5加密處理。getBytes():設置成getBytes()數組employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));//登錄時間和更新時間employee.setCreateTime(LocalDateTime.now());employee.setUpdateTime(LocalDateTime.now());//獲得當前登錄用戶的idLong empId = (Long) request.getSession().getAttribute("employee");employee.setCreateUser(empId);employee.setUpdateUser(empId);//保存對象employeeService.save(employee);//新增員工成功return R.success("新增員工成功");}
}
package com.itheima.reggie.common;import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;import java.sql.SQLIntegrityConstraintViolationException;/*** 全局異常捕獲處理* RestController.class, Controller.class:只有有這兩個注解的類都會被我們這個類來處理*/
@ControllerAdvice(annotations = {RestController.class, Controller.class}) //通知
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {/*** 異常處理方法* @return*/@ExceptionHandler(SQLIntegrityConstraintViolationException.class)public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) {log.error(ex.getMessage());//判斷異常獲取信息中是否有:Duplicate entry(重復條目)if(ex.getMessage().contains("Duplicate entry")){//根據空格進行分割,把異常信息存儲到 split數組中String[] split = ex.getMessage().split(" ");//獲取數組中已經用戶名信息(唯一約束)String msg = split[2] + "已存在";//輸出錯誤信息(賬戶已存在的信息)//return 把錯誤信息輸出到頁面上return R.error(msg);}//顯示到頁面的信息return R.error("未知錯誤");}
}
?
2.4 功能測試
2.5 總結
1、根據產品原型明確業務需求
2、重點分析數據的流轉過程和數據格式
3、通過debug斷點調試跟蹤程序執行過程
三、員工信息分頁查詢
3.1 需求分析
在后臺顯示界面,一頁顯示出所有員工信息不利于查看。
解決方法:將員工信息進行分頁展示
- 輸入框:可以添加過濾條件,在添加過濾條件的同時進行分頁處理
- 頁碼展示、可以跳轉到相應的頁碼、也可直接點擊相應的頁碼
3.2 代碼開發
3.2.1 梳理程序執行流程
- 頁面發送 ajax 請求,將分頁查詢參數(page、pageSize、name)提交到服務器
- 服務端 Controller 接收頁面提交的數據并調用 Service 查詢數據
- Service 調用 Mapper 操作數據庫,查詢分頁數據
- Controller 將查詢到的分頁數據轉成 JSON 響應給頁面
- 頁面接收到分頁數據并通過 ElementUI 的 Table 組件展示到頁面上
分頁插件的使用:
MyBatisPlus 給我們提供了一個分頁插件。
package com.itheima.reggie.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** 配置MybatisPlus 的分頁插件,配置類要加 @Configuration 注解*/
@Configuration
public class MyBatisPlusConfig {//攔截器@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());return mybatisPlusInterceptor;}
}
服務端 Controller 接收頁面提交的數據并調用 Service 查詢數據
//返回泛型Page,這個是MyBatisPlus 封裝的類//方法中的形參指的是:前端頁面傳遞給我們的值/*** 員工信息的分頁查詢* @param page* @param pageSize* @param name* @return*/@GetMapping("/page")public R<Page> page(int page, int pageSize, String name){log.info("page = {},pageSize = {},name = {}",page,pageSize,name);return null;}
分頁查詢設置
//返回泛型Page,這個是MyBatisPlus 封裝的類//方法中的形參指的是:前端頁面傳遞給我們的值/*** 員工信息的分頁查詢* @param page* @param pageSize* @param name* @return*/@GetMapping("/page")public R<Page> page(int page, int pageSize, String name){log.info("page = {},pageSize = {},name = {}",page,pageSize,name);//底層是基于MyBatisPlus提供的分頁插件進行分頁//1、構建分頁構造器(分頁條件:告訴MyBatisPlus我要查第幾頁,第幾條)Page pageInfo = new Page(page, pageSize);//2、構造條件構造器(封裝過濾分頁條件)LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper();//添加過濾條件,like查詢//判斷name是否為null,然后再來添加條件queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);//添加排序條件(就是相當于在SQL語句中加一個OrderBy)queryWrapper.orderByDesc(Employee::getUpdateTime);//3、執行查詢employeeService.page(pageInfo,queryWrapper);return R.success(pageInfo);}
3.3 功能測試
四、啟動 / 禁用員工賬號
4.1 需求分析
- 只有管理員(admin 用戶)可以對其他普通用戶進行啟用、禁用操作
- 普通用戶登錄系統后啟用、禁用按鈕不顯示
- 賬戶禁用的員工不能登錄系統
- 賬戶啟用的員工可以正常登錄
- 如果某個員工賬戶狀態為正常,則按鈕顯示為 “禁用”
- 如果員工賬戶狀態為已禁用,則按鈕顯示為 “啟用”
4.2 代碼開發
在開發代碼之前,需要梳理一下整個程序的執行流程:
- 頁面發送 ajax 請求,將參數(id、status)提交到服務端
- 服務端 Controller 接收頁面提交的數據并調用 Service 更新數據
- Service 調用 Mapper 操作數據庫
本質:是一個更新操作(Update),修改狀態碼
啟用、禁用(或者是編輯)員工賬號,本質上就是一個更新操作,也就是對 status 狀態字段進行操作。
在 Controller 中創建 update 方法,此方法是一個通用的修改員工信息的方法。
4.3 功能測試
4.4 代碼修復
五、編輯員工信息
5.1 需求分析
在員工管理列表頁面點擊編輯按鈕,跳轉到編輯頁面,在編輯頁面回顯員工信息并進行修改,最后點擊保存按鈕完成編輯操作。
5.2 代碼開發
在開發代碼之前需要梳理一下操作過程喝對應的程序的執行流程:
- 點擊編輯按鈕時,頁面跳轉到 add.html ,并在 url 中攜帶參數【員工 id】
- 在 add.html 頁面獲取 url 中的參數【員工 id】
- 發送 ajax 請求,請求服務端,同時提交員工 id 參數
- 服務端接收請求,根據員工 id 查詢員工信息,將員工信息以 json 形式響應給頁面
- 頁面接收服務端響應的 json 數據,通過 VUE 的數據綁定進行員工信息回顯
- 點擊保存按鈕,發送 ajax 請求,將頁面中的員工信息以 json 方式提交給服務端
- 服務端接收員工信息,并進行處理,完成后給頁面響應
- 頁面接收到服務端響應信息后進行相應處理