瑞吉外卖02-后台功能
本次功能代码实现(免费)
瑞吉外卖02-后台功能
后台登入功能
需求分析
1. 登入页面
2. 点击登入跳转至主页
3. 当前项目状态
此时我们还什么都没有做,项目开发还在初始阶段!
只是配置的了SpringBoot静态资源放行路径
4. 查看登录请求
可以看到我们点击登入按钮的时候,请求的路径是:http://localhost:8080/employee/login
并且是post请求
我们的后台代码还没有编写,所以这里就报404
故我们现在应该按照三层架构的方式来构建后台逻辑
5. 前端页面分析
在上述的前端代码中, 大家可以看到, 发送登录的异步请求之后, 获取到响应结果, 在响应结果中至少包含三个属性: code、data、msg
代码开发
登录逻辑分析
1. 创建实体类Employee
所在的包:com.harmony.reggie.entity
@Data
@Setter
@Getter
public class Employee {
// serialVersionUID用作Serializable类中的版本控件
// JavaBean规范中要实现java.io.Serializable接口实现序列化!!!
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String name;
private String password;
private String phone;
private String sex;
// 数据库里面是id_number 在application.yml配置即可,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
private String idNumber;
private Long status;
// LocalDateTime : JDK8 线程安全
private LocalDateTime createTime;
private LocalDateTime updateTime;
// MP中用于标识非主键的字段。将数据库列与 JavaBean 中的属性进行映射,
// fill 字段填充标记,表示在插入时自动填充
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
serialVersionUID:用作Serializable类中的版本控件,表示该类为可序列化类!JavaBean规范中要实现java.io.Serializable接口实现序列化(序列化serialVersionUID解释说明)
idNumber:数据库里面是id_number 在application.yml配置即可,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
@TableField(fill = FieldFill.INSERT):MP中用于标识非主键的字段。将数据库列与 JavaBean 中的属性进行映射,fill 字段填充标记,表示在插入时自动填充。
2. 定义通用结果类R
此类是一个通用结果类,服务端响应的所有结果最终都会包装成此种类型返回给前端页面。
所在的包:com.harmony.reggie.common
/**
* 通用返回结果,服务端返回的数据最终会封装成此对象
* @param <T>
*/
@Data
public class R<T> {
private Integer code; //编码:1成功,0和其它数字为失败
private String msg; //错误信息
private T data; //数据
private Map map = new HashMap(); //动态数据
public static <T> R<T> success(T object) {
R<T> r = new R<T>();
r.data = object;
r.code = 1;
return r;
}
public static <T> R<T> error(String msg) {
R r = new R();
r.msg = msg;
r.code = 0;
return r;
}
public R<T> add(String key, Object value) {
this.map.put(key, value);
return this;
}
}
3. 定义Controller层
所在的包:com.harmony.reggie.controller
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
/**
* 员工登入
* @param request
* @param employee
* @return
*/
@PostMapping("/login")
public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee) {
// @RequestBody : 用来接收前端传递给后端的json字符串中的数据的
return employeeService.login(request,employee);
}
}
4. 定义Mapper接口
所在的包:com.harmony.reggie.mapper
在MybatisPlus中, 自定义的Mapper接口, 需要继承自 BaseMapper
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
}
5. Service接口
所在的包:com.harmony.reggie.service
本项目的Service接口, 在定义时需要继承自MybatisPlus提供的Service层接口 IService, 这样就可以直接调用 父接口的方法直接执行业务操作, 简化业务层代码实现。
public interface EmployeeService extends IService<Employee> {
R<Employee> login(HttpServletRequest request, Employee employee);
}
6. Service实现类
该功能的业务逻辑都在这里了!
①. 将页面提交的密码password进行md5加密处理, 得到加密后的字符串
②. 根据页面提交的用户名username查询数据库中员工数据信息
③. 如果没有查询到, 则返回登录失败结果
④. 密码比对,如果不一致, 则返回登录失败结果
⑤. 查看员工状态,如果为已禁用状态,则返回员工已禁用结果
⑥. 登录成功,将员工id存入Session, 并返回登录成功结果
所在的包:com.harmony.reggie.service.impl
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
@Override
public R<Employee> login(HttpServletRequest request, Employee employee) {
// 1. 将页面提交的密码password进行md5加密处理, 得到加密后的字符串
String password = employee.getPassword();
password = DigestUtils.md5DigestAsHex(password.getBytes());
// 2. 根据页面提交的用户名username查询数据库中员工数据信息
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
// Employee::getUsername 查询SQL表里面的用户名
// employee.getUsername() 获取JavaBean的用户名
// eq()表示查询符合条件的数据
queryWrapper.eq(Employee::getUsername,employee.getUsername());
Employee emp = employeeMapper.selectOne(queryWrapper);
// 3. 如果没有查询到, 则返回登录失败结果 || 密码比对,如果不一致, 则返回登录失败结果
if(emp == null || !emp.getPassword().equals(password)){
return R.error("登入失败");
}
// 4. 查看员工状态,如果为已禁用状态,则返回员工已禁用结果
if(emp.getStatus() == 0) {
return R.error("账号已禁用");
}
// 6. 登录成功,将员工id存入Session, 并返回登录成功结果
request.getSession().setAttribute("employee",emp.getId());
return R.success(emp);
}
}
但是这里面有几个点需要注意一下!
queryWrapper.eq(Employee::getUsername,employee.getUsername());
Employee::getUsername :用于获取对象属性名,即获取到的值就是employee类的 “username”属性名。
eq():第一个参数为表列名,第二个为你的条件
后台退出功能
需求分析
1. 退出页面展示
2. 前端页面分析
代码开发
在登入功能里面有一些公用的类已经写了,这里有不重复说明了!
1. Controller层
所在的包:com.harmony.reggie.controller
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
/**
* 员工退出
* @param request
* @return
*/
@PostMapping("/logout")
public R<String> logout(HttpServletRequest request) {
return employeeService.logout(request);
}
}
2. service接口
所在的包:com.harmony.reggie.service
public interface EmployeeService extends IService<Employee> {
R<String> logout(HttpServletRequest request);
}
3. service实现类
所在的包:com.harmony.reggie.service.impl
@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
@Override
public R<String> logout(HttpServletRequest request) {
request.getSession().removeAttribute("employee");
return R.success("退出成功");
}
}
后台功能存在问题及优化
问题描述
前面我们已经完成了后台系统的员工登录功能开发,但是目前还存在一个问题,如下图所示:
上述这种设计并不合理,我们希望看到的效果应该是,只有登录成功后才可以访问系统中的页面,如果没有登录, 访问系统中的任何界面都直接跳转到登录页面。
实现思路
A. 获取本次请求的URI
B. 判断本次请求, 是否需要登录, 才可以访问
C. 如果不需要,则直接放行
D. 判断登录状态,如果已登录,则直接放行
E. 如果未登录, 则返回未登录结
代码实现
定义登录校验过滤器
所在的包:com.harmony.reggie.filter
/**
* 检查用户是否已经完成登入
*
* @WebServlet : 声明一个自定义的 Servlet
* @WebFilter : 声明一个Servlet 过滤器
* @WebListener : 声明一个类为 Servlet 监听器
*/
@WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {
//路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 1. 获取本次请求的URI
String requestURL = request.getRequestURI();
log.info("拦截到的请求: {}", requestURL);
// 定义可以放行的资源
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};
// 2. 判断本次请求, 是否需要登录, 才可以访问
boolean check = check(urls, requestURL);
// 3. 如果不需要,则直接放行
if (check) {
log.info("不需要处理的请求: {}", requestURL);
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")));
}
/**
* 路径匹配,检查本次请求是否需要放行
*
* @param urls
* @param requestURI
* @return
*/
public boolean check(String[] urls, String requestURI) {
for (String url : urls) {
// URL匹配
boolean match = PATH_MATCHER.match(url, requestURI);
if (match) {
return true;
}
}
return false;
}
}
给启动类添加注解@ServletComponentScan
只有给启动类添加了这个注解上面配置的过滤器类才会交给Spring容器管理!
@Slf4j
@SpringBootApplication
@ServletComponentScan
public class ReggieApplication {
public static void main(String[] args) {
SpringApplication.run(ReggieApplication.class);
log.info("项目启动成功...");
}
}
@ServletComponentScan、@WebServlet、@WebFilter、@WebListener
本次功能代码实现(免费)
注意是在这个分支里面哦!!!
master是项目的主线,即项目最新的功能点实现情况!
可以的话请给个免费的star哦~~~谢谢
reggie_v2_BackendLogin