瑞吉外卖-后台系统功能

前言

所有的命名要符合开发规范,本项目中不再解释命名对应的是哪一个模块,以及变量名的意思

后台系统登录功能

需求分析

后台系统登录主要需要实现以下功能

  • 前端传递用户名密码,后端可以接收
  • 后端对用户名密码在数据库中进行校验,发送校验结果给前端
  • 后端发送数据格式需要包含data(处理结果),code(处理结果编码),msg(操作成功或失败的提示)
  • 将员工id放入session,方便之后进行权限验证,防止直接通过网页访问页面跳过登录
  • 员工登录成功后,页面跳转到后台系统首页面(backend/index.html),显示当前登录用户的姓名
    需求分析

代码实现

建议把静态资源backend目录下的js下的request.js目录进行修改

(function (win) {
  axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
  // 创建axios实例
  const service = axios.create({
    // axios中请求配置有baseURL选项,表示请求URL公共部分
    baseURL: '/',
    // 超时
    timeout: 1000000
  })

将timeout尽量改大,这样方便进行调试,不会超时

实体类

创建entity包并在其中创建Employee实体类
如果druid版本太低,时间类不建议使用localDate,改用Date

package com.cjgn.entity;


import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.time.LocalDateTime;

//使用lombok自动生成实体类代码
@Data
//员工实体类
public class Employee {
    private Long id;
    //姓名
    private String name;
    //用户名
    private String username;
    private String password;
    private String phone;
    private String sex;
    //身份证
    private String idNumber;
    private Integer status;
    //如果druid版本太低改用Date
    @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;
}

Mapper层

package com.cjgn.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cjgn.entity.Employee;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
}

Service层

EmployeeService.java

package com.cjgn.service;

import com.cjgn.entity.Employee;

public interface EmployeeService {

    /**
     * 通过用户名密码查询
     * @param employee
     * @return
     */
    public Employee getByEmployee(Employee employee);
}

EmployeeServiceImpl.java

package com.cjgn.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cjgn.entity.Employee;
import com.cjgn.mapper.EmployeeMapper;
import com.cjgn.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

@Service
public class EmployeeServiceImpl implements EmployeeService {
    @Autowired
    private EmployeeMapper employeeMapper;


    @Override
    public Employee getByEmployee(Employee employee) {
        //1、将页面提交的密码password进行md5处理
        String password = employee.getPassword();
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        String username = employee.getUsername();

        //2、根据用户名密码去数据库查询
        LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(null != username, Employee::getUsername, username)
                .eq(null!=password,Employee::getPassword,password);
        Employee employee1 = employeeMapper.selectOne(wrapper);
        return employee1;
    }
}

Controller层

Result.java
记得注入get和set方法

package com.cjgn.contorller;


import lombok.Data;

import java.util.HashMap;
import java.util.Map;

//通用结果类
@Data
public class Result {

    //数据
    private Object data;
    //传递消息
    private String msg;
    //结果代码
    private Integer code;
    //动态数据
    private Map map = new HashMap();

    //三个值都有的构造方法
    public Result(Object data, Integer code,String msg) {
        this.data = data;
        this.msg = msg;
        this.code = code;
    }

    //只有消息和编码的构造方法,用于失败的时候用
    public Result(Integer code,String msg) {
        this.msg = msg;
        this.code = code;
    }

    //无参构造方法
    public Result() {
    }

    public Result add(String key,Object value){
        this.map.put(key,value);
        return this;
    }
}

Code.java

package com.cjgn.contorller;

public class Code {
    //根据前端的代码,成功的编码为1,失败的编码为0
    public static final Integer OK = 1;
    public static final Integer ERR = 0;
}

EmployeeController.java

package com.cjgn.contorller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cjgn.entity.Employee;
import com.cjgn.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.*;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;

@RestController
@RequestMapping("/employee")
public class EmployeeController {
    @Autowired
    private EmployeeService employeeService;


    /**
     * 员工登录功能
     * 使用的post请求
     * @param request
     * @param employee
     * @return
     */
    @PostMapping("/login")
    public Result Login(HttpServletRequest request,@RequestBody Employee employee){
        Employee employee1 = employeeService.getByEmployee(employee);
        //判断对象是否为空,空:查询失败,非空:查询成功
        //code:非空为1,空或者status为0的时候为0
        Integer code;
        String msg;
        //查询为空
        if(null==employee1){
            code = Code.ERR;
            msg = "登录失败";
        }
        //账号已禁用
        else if(employee1.getStatus()==0){
            code = Code.ERR;
            msg = "登录失败";
        }
        //查询不为空且账号启用则登录成功
        else {
            //设置session,把员工的id存入
            request.getSession().setAttribute("employee",employee1.getId());
            code = Code.OK;
            msg = "登录成功";
        }
        //只需要穿是否查询成功的结果就可以,不需要传输data
        return new Result(employee1,code,msg);
    }
}

总结

完成登录功能后,就可以使用账号密码,进行用户登录,并跳转到后台的界面,用户id也被储存到session中。方便之后的使用。 一定要注意Result类中要注入get和set方法,否则会报错


后台系统退出功能

需求分析

后台退出系统主要需要实现以下功能

  • 点击右侧的退出按扭发送请求到后端,删除对应session,然后退出到登录页面

代码实现

EmployeeController.java

    /**
     * 员工退出
     * @param request
     * @return
     */
    @PostMapping("/logout")
    public Result logout(HttpServletRequest request){
        //删除session
        request.getSession().removeAttribute("employee");
        //返回前端数据
        return new Result(Code.OK,"退出成功");
    }

总结

退出功能相对简单,只需对前端发送的ajax请求进行处理,删除登录设置的session,然后返回前端一个退出成功的数据,就可以实现退出和页面的跳转。(这里的页面跳转由前端执行)


后台登录优化

需求分析

  • 问题:之前的登录系统存在一个漏洞,用户如果直接通过url去访问index.html主页是可以访问的,显然这不是我们想要的效果。
  • 优化:使用过滤器或拦截器,判断用户是否进行登录,如果没有登录就跳转到登录界面
  • 效果:用户只有登录后才能访问主页,否则会跳转回登录界面
    过滤器

代码实现

首先在pom文件中导入fastjson依赖

 		<!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>

这里采用两种不同的方法分别实现

方法一:过滤器

  1. 在springboot的运行类中添加@ServletComponentScan注解
  2. 创建filter包并在其下创建类LoginCheckFilter

LoginCheckFilter.java

package com.cjgn.filter;


import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSON;
import com.cjgn.contorller.Code;
import com.cjgn.contorller.Result;
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;

/**拦截器类
 * @author DELL
 */
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
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 requestURI = request.getRequestURI();
        System.out.println("本次拦截路径"+requestURI);

        //定义不需要处理的路径
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**"
        };
        //2、判断本次请求是否需要处理
        boolean check = this.check(urls, requestURI);

        //3、不需要处理直接放行
        if (check){
            System.out.println("不需要处理");
            filterChain.doFilter(servletRequest,servletResponse);
        }
        //4、判断登录状态,如果已经登录则放行
        else if (request.getSession().getAttribute("employee")!=null){
            System.out.println("已登录");
            filterChain.doFilter(servletRequest,servletResponse);
        }
        //5、如果没有登录则跳转到登录页面
        else {
            //使用response传回json数据
            response.getWriter().write(JSON.toJSONString(new Result(Code.ERR,"NOTLOGIN")));
            System.out.println("未登录");
        }


    }

    /**
     * 进行路径匹配,检查本次请求是否需要放心
     * @param requestURI
     * @return
     */
    public boolean check(String[] urls,String requestURI){
        //进行逐个匹配
        for (String url : urls) {
            boolean match = PATH_MATCHER.match(url, requestURI);
            if(match){
                //匹配成功返回true
                return true;
            }
        }
        //匹配失败返回false
        return false;

    }
}

方法二:拦截器

  1. 在controller包下创建LoginInterceptor类
  2. 创建config包并在其中创建WebMvcConfig类

LoginInterceptor.java

package com.cjgn.contorller;

import com.alibaba.fastjson.JSON;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 使用拦截器实现过滤器功能
 */
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        System.out.println("本次拦截路径" + requestURI);


        //4、判断登录状态,如果已经登录则放行
        if (request.getSession().getAttribute("employee") != null) {
            System.out.println("已登录");
            return true;
        }
        //5、如果没有登录则跳转到登录页面
        else {
            //使用response传回json数据
            response.getWriter().write(JSON.toJSONString(new Result(Code.ERR, "NOTLOGIN")));
            System.out.println("未登录");
            return false;
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

WebMvcConfig.java

要注意这个类最好去实现WebMvcConfigurer接口。最好不要继承WebMvcConfigurationSupport类,虽然功能大致相同,但采用继承的话可能导致静态资源SpringMvc拦截,即使放在static目录下也没用。

package com.cjgn.comfig;

import com.cjgn.contorller.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


import java.util.ArrayList;
import java.util.List;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;


    /**
     * 加入拦截路径和放行的路径
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //使用列表去装放行的路径
        List<String> urls = new ArrayList<>();
        urls.add( "/employee/login");
        urls.add( "/employee/logout");
        urls.add( "/backend/**");
        urls.add( "/front/**");
        urls.add("/error");
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns(urls);
    }
}

总结

添加拦截器或过滤器后,当前端发送请求时,会在拦截器或过滤器中进行处理,通过一系列判断,来决定是否放行这个请求。一般来说如果完成登录则不拦截请求,如果未登录就访问,则跳转回登录界面。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值