• 基于springboot和vue2外卖点餐系统的项目总结



    写在前面

    项目介绍:本项目是一个外卖点餐的系统

    使用的主要技术栈 springboot,mybatis-plus,redis,vue2

    本项目比较基础,对于熟悉写项目的整体架构会有一个比较清晰的认识。

    下面梳理出来的项目中的亮点部分。

    具体的项目的源码以及项目的项目详细介绍在gitte仓库中

    使用过滤器

    过滤器可以对于用户的请求进行拦截,避免了用户在没有登录的情况下访问项目。
    如何使用过滤器,通过一个最基础的springboot项目进行演示,分别为LoginController类,LoginFilter类,以及一个启动类,端口号使用的是8081
    在这里插入图片描述
    LoginFilter.java代码如下
    该类实现了Filter接口,注意是javax.serlet包下的,该接口中有三个方法,而只有doFilter是抽象方法,所以需要重写该方法。需要在该类上面加上注解,@WebFilter(filterName = "LoginFilter",urlPatterns = {"/*"}),表明需要拦截的请求路径,在该演示中使用的是{"/*}表示拦截的所有的请求,因此用户的任何请求,首先都会进入该类进行处理之后,才会进入到controller层。要想让该类其作用,并且要让springboot在启动的时候知道该类的存在,需要在启动类中加上注解@ServletComponentScan

    package com.wjiangquna.filter;
    
    import com.sun.deploy.net.HttpResponse;
    import lombok.extern.slf4j.Slf4j;
    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;
    
    /**
     * filterName过滤器名字
     * urlPatterns拦截的请求,这里是拦截所有的请求
     *
     */
    
    @Slf4j
    @WebFilter(filterName = "LoginFilter",urlPatterns = {"/*"})
    public class LoginFilter implements Filter{
    
        //路径匹配器,支持通配符(spring给我们提供的工具)
        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;
    
            // 获取本次请求的URUI
            String requestURI = request.getRequestURI();    //获取请求的URI
            StringBuffer requestURL = request.getRequestURL(); //获取请求的URL
    
            log.info("拦截到请求:{},请求的URL为:{}",requestURI,requestURL);
    
            // 定义不需要拦截的请求
            String[] urls = new String[]{"/user/login", "/user/logout"};
    
            // 检测请求是否需要处理
            boolean check = check(urls, requestURI);
            if(check){
                log.info("本次请求{}不需要处理",requestURI);
                // 放行
                filterChain.doFilter(request,response);
                return;
            }
            response.getWriter().write("You do not have access rights");
        }
        
        /**
         * 路径匹配,检查本次请求是否需要放行
         * @param requestURI 请求的URI地址
         * @return true说明匹配上了
         */
        public boolean check(String[] urls,String requestURI){
            for (String url:urls){
                boolean match = PATH_MATCHER.match(url, requestURI);
                if(match){
                    return true;
                }
            }
            return false;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    启动类的代码

    package com.wjiangquna;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    
    @SpringBootApplication
    @ServletComponentScan  //这个是注解是让过滤器中那些生效的,可以扫描到过滤器的那些,才能扫描WebFilter这些注解
    @Slf4j
    public class FilterDemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(FilterDemoApplication.class, args);
            log.info("项目启动了");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    LoginController.java

    package com.wjiangquna.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author weijiangquan
     * @date 2022/8/7 -21:12
     * @Description
     */
    @RestController
    @RequestMapping("/user")
    public class LoginController {
    
        @GetMapping("/login")
        public String login() {
            return "success";
        }
    
        @GetMapping("logout")
        public String logout() {
            return "logout";
        }
    
        @GetMapping("/list")
        public String list() {
            return "error";
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    测试过滤器
    启动项目之后进行测试,对于Logincontroller的三个接口进行的测试
    在这里插入图片描述
    在控制台上可以看到该日志信息
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    对于请求http://localhost:8081/user/logouthttp://localhost:8081/user/login由在过滤器中的下面的代码匹配上了之后,就会直接返回,这里的返回的意思就是可以访问LoginController层的相应的接口了

     // 定义不需要拦截的请求
            String[] urls = new String[]{"/user/login", "/user/logout"};
    
            // 检测请求是否需要处理
            boolean check = check(urls, requestURI);
            if(check){
                log.info("本次请求{}不需要处理",requestURI);
                // 放行
                filterChain.doFilter(request,response);
                return;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    对于接口http://localhost:8081/user/list,由于没有匹配上,所以直接通过response对象返回信息给用户
    在这里插入图片描述
    在这里插入图片描述

    总结:
    在本次过滤器的演示的功能中,或许功能比较简单,没有涉及到复杂的逻辑,而是提供了一种在项目中使用过滤器的思路,在不同的情况下可以根据自己的需要和项目的走向进行拓展。而在瑞吉外卖的项目中基于上面也拓展了一些功能,比如在过滤器中判断用户是否登录,也就是检测session
    是否存在唯一的标识,如果没有使用过滤器的化,就需要在controller每一个接口中进行判断,这样的化,就会让代码量变大,维护性更差。

    使用全局异常进行捕获

    在本项目中使用到全局异常的处理,
    在这里插入图片描述
    全局异常可以使整个项目更加的完善

    package com.wjiangquan.whale.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;
    
    /**
     * @author weijiangquan
     * @date 2022/7/23 -23:12
     * @Description 全局异常的处理
     */
    
    @ControllerAdvice(annotations = {RestController.class, Controller.class})
    //拦截加了这个RestController注解的controller 加到了普通的也会拦截
    @ResponseBody   //最终的结果返回json
    @Slf4j
    public class GlobalExceptionHandler {
        /**
         * 进行异常处理的方法
         *
         * @return
         */
        @ExceptionHandler(SQLIntegrityConstraintViolationException.class)  //处理哪些类型的异常
        public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) {
            log.error(ex.getMessage());
            // getMessage的内容为 Duplicate entry 'aaa' for key 'idx_username'
            if (ex.getMessage().contains("Duplicate entry")) {
                String[] split = ex.getMessage().split(" ");
                String msg = split[2] + "已存在";
                return R.error(msg);
            }
            return R.error("未知错误");
        }
    
    
        /**
         * 捕获自定义的异常
         * @return
         */
        @ExceptionHandler(CustomException.class)  //处理哪些类型的异常
        public R<String> exceptionHandler(CustomException ex) {
            log.error(ex.getMessage());
            return R.error(ex.getMessage());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    自定义异常类

    package com.wjiangquan.whale.common;
    
    /**
     * @author weijiangquan
     * @date 2022/7/30 -19:43
     * @Description 自定义业务异常
     */
    public class CustomException extends RuntimeException{
        public CustomException(String message){
            super(message);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    参考视频

    https://www.bilibili.com/video/BV13a411q753?share_source=copy_web&vd_source=1f198fa093790427b60b33b612ecabca

    项目笔记和源码地址

    项目笔记文档截图

    在这里插入图片描述

    下面是做项目的过程中整理的源码和以及笔记的地址。

    https://gitee.com/wei-jiangquan/reggie_take_out/tree/master/

    mybatis-plus的官网

    https://baomidou.com/

    总结:
    平时在项目中要学会处理异常,而全局异常的处理就是一个很好的选择,就异常进行统一出处理,可以处理系统异常以及自定义的异常。可以给整个项目指定一个标准。

  • 相关阅读:
    【AICFD案例教程】汽车外气动-AI加速
    drools中then部分的写法
    asp.net+sqlserver医院体检信息管理系统
    C语言学习笔记02
    Java的集合框架总结
    来自2年前端的面经
    《mSystems》比较宏基因组学探究海洋和陆地生态系统中磷酸盐分解代谢途径
    Dubbo面试系列问题总结
    e.target 原生js 没有 $event的 自定义属性值 传参
    防抖与节流是什么?如何实现?
  • 原文地址:https://blog.csdn.net/weixin_47994845/article/details/126213906