用springboot+mybatis-plus,开发后台系统登录、登出功能
用springboot+mybatis-plus,开发后台系统登录、登出功能
后台系统登录功能
1.需求分析
1.1页面原型展示
1.2查看登录请求
通过浏览器调试工具( F12 ),可以发现,点击登录按钮时,页面会发送请求( 并提交参数 username 和 password, 请求参数为 json 格式数{"username":"admin","password":"123456"} 。
此时报 404 ,是因为我们的后台系统还没有响应此请求的处理器,所以我们需要创建相关类来处理登录请求 ;
1.3分析数据模型
在上述的前端代码中 , 大家可以看到 , 发送登录的异步请求之后 , 获取到响应结果 , 在响应结果中至少包含三个属性: code 、 data 、 msg 。由前端代码,我们也可以看到,在用户登录成功之后,服务端会返回用户信息,而前端是将这些用户信息,存储在客户端的 localStorage 中了。
2.2 根据数据库的数据表,在entity包下,创建对应的实体类
package com.ning.reggie.entrty;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
private Long id;
/**
* 姓名
*/
private String username;
/**
* 用户名,登录名
*/
private String name;
/**
* 密码
*/
private String password;
/**
* 手机号
*/
private String phone;
/**
* 性别
*/
private String sex;
/**
* 身份证号码
*/
private String idNumber;
/**
* 状态
* 1:正常
* 0:禁用
*/
private Integer status;
/**
* 创建时间
* //@TableField:该注解用于标识非主键的字段。将数据库列与 JavaBean 中的属性进行映射
* 在这里主要是通过fill属性,来指定字段的填充策略为 插入填充字段
*/
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 更新时间
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
/**
* 创建人
*/
@TableField(fill = FieldFill.INSERT)
private Long createUser;
/**
* 修改人
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
创建时间、修改时间、创建人、修改人
这几个字段为公共字段,在建表时,建议加入这几个字段,主要是用于做数据追溯
2.3 在mapper包下,创建Mapper持久层接口
建议在定义接口时,在类名前加上大写i,增强代码的规范性和可阅读性
在 MybatisPlus 中 , 自定义的 Mapper 接口 , 需要继承自 BaseMapper,并把实体类传入所属包 : com.itheima.reggie.mapper
注:记得在类上加@Mapper注解
package com.ning.reggie.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ning.reggie.entrty.Employee;
import org.apache.ibatis.annotations.Mapper;
/**
* 员工mapper
*
* @author ning
* @since 2022/10/31 20:03
*/
@Mapper
public interface IEmployeeMapper extends BaseMapper<Employee> {
}
2.4 在service包下,创建service业务层接口
本项目的 Service 接口 , 在定义时需要继承自 MybatisPlus 提供的 Service 层接口 IService,并把实体类传入, 这样就可以直接调用 父接口的方法直接执行业务操作, 简化业务层代码实现。所属包 : com.itheima.reggie.service
package com.ning.reggie.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ning.reggie.entrty.Employee;
/**
* 员工service接口
*
* @author ning
* @since 2022/10/31 20:04
*/
public interface IEmployeeService extends IService<Employee> {
}
2.5 在service包下,先创建一个impl的包,然后在impl包下创建service业务层接口的实现类
实现ServiceImpl,并把实体类的Mapper和实体类传入,并继承对应的service接口
注:记得在类上加@Service注解
package com.ning.reggie.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ning.reggie.entrty.Employee;
import com.ning.reggie.mapper.IEmployeeMapper;
import com.ning.reggie.service.IEmployeeService;
import org.springframework.stereotype.Service;
/**
* 员工业务实现
*
* @author ning
* @since 2022/10/31 20:09
*/
@Service
public class EmployeeServiceImpl extends ServiceImpl<IEmployeeMapper, Employee> implements IEmployeeService{
}
2.6 在controller包下,创建controller表示层类
注:记得在类上加上@RestController、@RequestMapping注解
package com.ning.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ning.reggie.common.GlobalConstant;
import com.ning.reggie.common.R;
import com.ning.reggie.entrty.Employee;
import com.ning.reggie.service.IEmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
/**
* 员工控制器
*
* @author ning
* @since 2022/10/31 20:01
*/
/**
* 日志
*/
@Slf4j
/**
* //@RestController = @RequestBody + @Controller
* //@RequestBody:注解就可以将对象进行反序列化
* //@Controller:用来表示Spring某个类是否可以接受HTTP请求,她通常与@ResponseBody绑定使用。
*/
@RestController
/**
* 用来处理请求地址映射的注解,可用于类或方法上。
* 用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
*/
@RequestMapping("/employee")
public class EmployeeController {
//获取employeeService
@Autowired
private IEmployeeService employeeService;
2.7 导入通用结果类
2.8 登录逻辑分析
建议:在设计数据表保存比较敏感的信息,例如密码,应该使用加密技术,加密之后存入,当需要调取数据,比对时接收到的数据按照同样的加密技术之后,再比较
处理逻辑如下:① . 将页面提交的密码 password 进行 md5 加密处理 , 得到加密后的字符串② . 根据页面提交的用户名 username 查询数据库中员工数据信息③ . 如果没有查询到 , 则返回登录失败结果④ . 密码比对,如果不一致 , 则返回登录失败结果⑤ . 查看员工状态,如果为已禁用状态,则返回员工已禁用结果⑥ . 登录成功,将员工 id 存入 Session, 并返回登录成功结果
2.9 代码实现
技术点说明 :A. 由于需求分析时 , 我们看到前端发起的请求为 post 请求 , 所以服务端需要使用注解@PostMappingB. 由于前端传递的请求参数为 json 格式的数据 , 这里使用创建的实体类 对象接收 , 但是将 json 格式数据封装到实体类中, 在形参前需要加注解 @RequestBody
package com.ning.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ning.reggie.common.GlobalConstant;
import com.ning.reggie.common.R;
import com.ning.reggie.entrty.Employee;
import com.ning.reggie.service.IEmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
/**
* 员工控制器
*
* @author ning
* @since 2022/10/31 20:01
*/
/**
* 日志
*/
@Slf4j
/**
* //@RestController = @RequestBody + @Controller
* //@RequestBody:注解就可以将对象进行反序列化
* //@Controller:用来表示Spring某个类是否可以接受HTTP请求,她通常与@ResponseBody绑定使用。
*/
@RestController
/**
* 用来处理请求地址映射的注解,可用于类或方法上。
* 用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
*/
@RequestMapping("/employee")
public class EmployeeController {
//获取employeeService
@Autowired
private IEmployeeService employeeService;
/**
* 登录
*/
//判断前端的请求路径
//判断前端的请求方式
//判断前端的请求参数
//判断返回值
@PostMapping("/login")
public R<Employee> login(@RequestBody Employee employeeParam, HttpServletRequest request) {
//前端传入的所有参数都是不可靠的,
//用户名和密码的参数校验
//用户名和密码,不能为空
//参数校验
if (StringUtils.isBlank(employeeParam.getUsername()) ||
StringUtils.isBlank(employeeParam.getPassword())) {
return R.error(GlobalConstant.FAILURE);
}
//判断一下是否可以接收到前端的参数
log.info("前后端连接 ===> {}", employeeParam.toString());
//将页面提交的密码password进行md5加密处理, 得到加密后的字符串
//因为存入数据库中的密码就是经过md5加密过的,为了保证数据的安全性
String md5p = DigestUtils.md5DigestAsHex(employeeParam.getPassword().getBytes());
//根据页面提交的用户名username查询数据库中员工数据信息
//创建LambdaQueryWrapper条件构造器对象,用来拼接查询语句
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
//拼接查询语句
queryWrapper.eq(Employee::getUsername, employeeParam.getUsername());
//调用service查询
Employee employee = this.employeeService.getOne(queryWrapper);
//如果没有查询到, 则返回登录失败结果
if (employee == null) {
return R.error(GlobalConstant.FAILURE);
}
//密码比对,如果不一致, 则返回登录失败结果
if (!(employee.getPassword().equals(md5p))) {
return R.error(GlobalConstant.FAILURE);
}
//查看员工状态,如果为已禁用状态,则返回员工已禁用结果
//1:正常,0:禁用
if (employee.getStatus() == 0) {
return R.error(GlobalConstant.DISABLE);
}
//登录成功,将员工id存入Session, 并返回登录成功结果
request.getSession().setAttribute(GlobalConstant.EMPLOYEE_ID, employee.getId());
//返回员工信息
return R.success(employee);
}
2.10 功能测试
代码实现完毕后 , 启动项目 , 访问 url , 进行登录测试。在测试过程中, 可以通过 debug 断点调试的方式来跟踪程序的执行过程,并且可以查看程序运行时各个对象的具体赋值情况。而且需要注意, 在测试过程中,需要将所有的情况都覆盖到。
2.11 可能会出现的问题
问题说明当我们在进行 debug 端点调试时 , 前端可能会出现如下问题 : 前端页面的控制台报出错误 - 超时 ;
解决方案
前端进行异步请求时 , 默认超时 10000ms , 可以将该值调大一些。
注意:
由于修改了JS文件,需要手动清理一下浏览器缓存,避免缓存影响,JS不能及时生效。
应该完善的操作:
登录的时候应该加入鉴权的操作
判断是否已经登陆,如果没有登录,不能访问任何界面,直接跳转到登录界面
如何实现?
加入拦截器或者过滤器,拦截从浏览器或客户端发起的请求,进行业务判断
后台系统退出功能
3. 1需求分析
在后台管理系统中,管理员或者员工,登录进入系统之后,页面跳转到后台系统首页面,此时会在系统的右上角显示当前登录用户的姓名。如果员工需要退出系统,直接点击右侧的退出按钮即可退出系统,退出系统后页面应跳转回登录页面。
3.2 前端页面分析
A. 发起 post 请求 , 调用服务端接口 /employee/logout 执行退出操作 ;
3.3代码实现
需要在Controller中创建对应的处理方法, 接收页面发送的POST请求 /employee/logout ,具
体的处理逻辑:A. 清理 Session 中的用户 idB. 返回结果
/**
* 退出登录
*/
//判断前端的请求路径
//判断前端的请求方式
//判断前端的请求参数
//判断返回值
@PostMapping("/logout")
public R<String> logout(HttpServletRequest request) {
//清理session
request.getSession().removeAttribute(GlobalConstant.EMPLOYEE_ID);
//返回操作成功
return R.success(GlobalConstant.SUCCESSFUL);
}
3.4 功能测试
更多推荐
所有评论(0)