• 【JAVA后端开发】Part1--瑞吉外卖项目


    文章目录

    1,项目环境搭建

    开发语言

    Java

    开发工具

    IDEA

    数据库

    MYSQL/8.0

    使用框架

    springboot+vue

    用到的技术栈

    MybatisPlus,lombok,fastjson,druid数据库

    JDK版本

    jdk1.8

    1.1 数据库环境搭建

    创建数据库:reggie,并执行sql文件导入11张表,每张表对应信息如下:

    在这里插入图片描述

    1.2 maven环境搭建

    创建maven项目,并命名为reggie_take_out。检查项目设置中的maven仓库是否正确以及Runner中JRE是否正确,最后检查项目设置中的JKD是否正确。详细步骤见下图:

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    2,项目开发

    2.1 项目框架搭建

    2.1.1,导入依赖pom文件,以及编写配置文件application.yml。

    pom文件

    
    
        4.0.0
        
            org.springframework.boot
            spring-boot-starter-parent
            2.4.5
             
        
        com.wang
        reggie_take_out
        1.0-SNAPSHOT
        
            1.8
        
    
        
        
    
            
                org.springframework.boot
                spring-boot-starter
            
    
            
                org.springframework.boot
                spring-boot-starter-test
                test
            
    
            
                org.springframework.boot
                spring-boot-starter-web
                compile
            
    
            
                com.baomidou
                mybatis-plus-boot-starter
                3.4.2
            
    
            
                org.projectlombok
                lombok
                1.18.20
            
    
            
                com.alibaba
                fastjson
                1.2.76
            
    
            
                commons-lang
                commons-lang
                2.6
            
    
            
                mysql
                mysql-connector-java
                runtime
            
    
            
                com.alibaba
                druid-spring-boot-starter
                1.1.23
            
    
        
    
        
            
                
                    org.springframework.boot
                    spring-boot-maven-plugin
                    2.4.5
                
            
        
    
    
    
    • 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
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    application.yml配置文件:

    server:
      port: 8080
    spring:
      application:
        name: reggie_take_out
      datasource:
        druid:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/reggie?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
          username: root
          password: root
    mybatis-plus:
      configuration:
        #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
        map-underscore-to-camel-case: true
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      global-config:
        db-config:
          id-type: ASSIGN_ID
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.1.2 编写项目启动类

    将依赖注入后,我们需要写一个springboot的项目启动类ReggieApplication,代码如下:

    @Slf4j//日志注解
    @SpringBootApplication
    public class ReggieApplication {
        public static void main(String[] args) {
            SpringApplication.run(ReggieApplication.class,args);
            log.info("项目启动成功。。。");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这一步,一个空空的springboot就搭建完成了,大家可以点击启动类,看看项目能不能正常运行。可以的话,就可以进行下一步操作了!!

    2.1.3 导入静态资源,并进行静态资源映射。

    1,将该项目对应的静态资源(静态资源的获取方式见文末)赋值到resource目录下面。又因为正常情况下只有在资源resource的目录statictemplates下的静态资源,项目才可以直接访问到,所以这里我们需要写一个能够让我们访问静态资源的配置类,进行资源映射。

    2,创建config目录,存放我们的配置类,并编写WebMvcConfig.java文件:

    @Slf4j
    @Configuration
    public class WebMvcConfig extends WebMvcConfigurationSupport {
        /**
         *@Author wjq
         *@Date 2022/6/23
         *@Version v1.0
         *@Description 设置静态资源映射
         */
        @Override
        protected void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
            registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");
            log.info("开始静态资源映射。。。");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    到这一步项目的基本大框架就已经搭建好了,接下来就要进行具体功能的需求分析和开发了。

    2.2 后台登录功能开发

    按照视频讲解,完整功能开发一般要分为需求分析—>代码开发—>功能测试,三个步骤。但是我们在学习的过程中,功能测试其实就是查看代码是否能实现对应的功能并且无Bug。因此本文不再赘述这一步骤。

    在这里插入图片描述

    2.2.1 需求分析

    1,查看登录页面 s r c / m a i n / r e s o u r c e s / b a c k e n d / p a g e / l o g i n / l o g i n . h t m l src/main/resources/backend/page/login/login.html src/main/resources/backend/page/login/login.html,获取登录页面需要信息,以及执行流程。

    2,查看登录所用到的信息

    在这里插入图片描述

    3,对数据Employee的模型进行分析,查看我们登录用到的信息。

    2.2.2 代码开发


    1. 导入实体类Employee,与表Employee进行映射。(登录必须要有用户,对应的就是数据表中的表一Employee)

    2. 使用MybatisPlus,编写mapper文件EmployeeMapper。

      @Mapper
      public interface EmployeeMapper  extends BaseMapper {
      }
      
      • 1
      • 2
      • 3
    3. 使用MybatisPlus,编写service接口以及接口实现类。

    4. 导入最终结果返回类R。

      /**
       *@Author wjq
       *@Date 2022/6/23
       *@Version v1.0
       *@Description 通用返回结果类,服务端相应的数据最终都会封装成该类
       */
      @Data
      public class R {
      
          private Integer code; //编码:1成功,0和其它数字为失败
      
          private String msg; //错误信息
      
          private T data; //数据
      
          private Map map = new HashMap(); //动态数据
      
          public static  R success(T object) {
              R r = new R();
              r.data = object;
              r.code = 1;
              return r;
          }
      
          public static  R error(String msg) {
              R r = new R();
              r.msg = msg;
              r.code = 0;
              return r;
          }
      
          public R add(String key, Object value) {
              this.map.put(key, value);
              return this;
          }
      
      }
      
      • 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
    5. 编写Controller文件,在controller类中编写登录方法,登录方法的处理逻辑。

      a, 将页面提交的密码password进行md5加密处理

      b,根据页面提交的用户名username查询数据库

      c,如果没有查询到则返回登录失败结果

      d, 密码比对,如果不一致则返回登录失败结果

      e, 查看员工状态,如果为已禁用状态,则返回员工已禁用结果

      f, 登录成功,将员工id存入Session并返回登录成功结果

      在这里插入图片描述

      @Slf4j
      @RestController
      @RequestMapping(“/employee”)
      public class EmployeeController {

      @Autowired
      private EmployeeService employeeService;
      
      /**
       *@Author wjq
       *@Date 2022/6/24
       *@Version v1.0
       *@Description 管理元登录功能
       */
      @PostMapping("/login")
      public R login(HttpServletRequest request, @RequestBody Employee employee){
      
          //1、将页面提交的密码password进行md5加密处理
          String password = employee.getPassword();
          password = DigestUtils.md5DigestAsHex(password.getBytes());
      
          //2、根据页面提交的用户名username查询数据库
          LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
          queryWrapper.eq(Employee::getUsername,employee.getUsername());
          Employee emp = employeeService.getOne(queryWrapper);
      
          //3、如果没有查询到则返回登录失败结果
          if(emp == null){
              return R.error("登录失败");
          }
      
          //4、密码比对,如果不一致则返回登录失败结果
          if(!emp.getPassword().equals(password)){
              return R.error("登录失败");
          }
      
          //5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
          if(emp.getStatus() == 0){
              return R.error("账号已禁用");
          }
      
          //6、登录成功,将员工id存入Session并返回登录成功结果
          request.getSession().setAttribute("employee",emp.getId());
          return R.success(emp);
      }
      
      • 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

      }

    2.3 后台退出功能开发


    2.3.1 需求分析

    在这里插入图片描述

    1,登录上去后,点击退出图标,要返回到登录页面。

    2,打开 s r c / m a i n / r e s o u r c e s / b a c k e n d / i n d e x . h t m l src/main/resources/backend/index.html src/main/resources/backend/index.html文件,看到推出按键会触发方法logout。

     退出
    
    • 1

    3,分析logout方法,其中会调用函数logoutApi()。打开该函数发现其会post到 / e m p l o y e e / l o g o u t /employee/logout /employee/logout,因此我们只要在controller中编写退出方法,并返回一个通用类R就行了。

              logout() {
                logoutApi().then((res)=>{
                  if(res.code === 1){
                    localStorage.removeItem('userInfo')
                    window.location.href = '/backend/page/login/login.html'
                  }
                })
              },
    
    
    function logoutApi(){
      return $axios({
        'url': '/employee/logout',
        'method': 'post',
      })
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.3.2 代码开发

    1,清理Session中保存的当前登录员工的id。

    2,返回通用类R。

        /**
         * 员工退出
         * @param request
         * @return
         */
        @PostMapping("/logout")
        public R logout(HttpServletRequest request){
            //清理Session中保存的当前登录员工的id
            request.getSession().removeAttribute("employee");
            return R.success("退出成功");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2.4 完善登录功能

    2.4.1 需求分析

    1,当我们直接访问 h t t p : / / l o c a l h o s t : 8080 / b a c k e n d / i n d e x . h t m l http://localhost:8080/backend/index.html http://localhost:8080/backend/index.html页面时,不需要账号和密码就可以直接登录上去,这是不符合实际需求的。实际需求是:只有用户输入正确账号和密码才能完成登录!

    2,实现该功能有两种方式:用过滤器和拦截器,在过滤器和拦截器中判断用户是否已经完成登录,如果没有登录则跳转到登录页面。

    如下图展示:第一次我们用账号密码登录属于正常需求。但是当我们推出了,直接访问index页面,竟然也能直接访问,这就是很严重的问题了。

    在这里插入图片描述

    2.4.2 代码开发

    1. 创建自定义过滤器LoginCheckFilter实现Filter,并重写doFilter方法

      @WebFilter(filterName = “loginCheckFilter”,urlPatterns = “/*”)
      @Slf4j
      public class LoginCheckFilter implements Filter {
      @Override
      public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
      }

      }

    2. 在启动类上加入注解@ServletComponentScan,相当于打开过滤器的开关。

    3. 完善过滤器的处理逻辑
      a, 获取本次请求的URI。
      b,定义不需要处理的请求路径,并放在String数组中。
      c,判断本次请求是否需要处理,在函数check中实现,利用了AntPathMatcher类。如果不需要处理,则直接放行。

        //路径匹配器,支持通配符
      public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();  
      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

    d,判断登录状态,如果已登录,则直接放行。
    e,如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据。

    4,在我们写完过滤器后,前端页面中,通过文件 j r e q u e s t . j s jrequest.js jrequest.js中的下面方法来响应过滤器,阅读代码可以发现,其最后仍需要获取一个通用类型R,这正好对应了步骤3中流程e,需要我们向客户端即前端页面响应数据。

      service.interceptors.response.use(res => {
          if (res.data.code === 0 && res.data.msg === 'NOTLOGIN') {// 返回登录页面
            console.log('---/backend/page/login/login.html---')
            localStorage.removeItem('userInfo')
            window.top.location.href = '/backend/page/login/login.html'
          } else {
            return res.data
          }
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    整合后的过滤器代码,LoginCheckFilter类如下:

    /**
     * 检查用户是否已经完成登录*/
    
    
    @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 requestURI = request.getRequestURI();// /backend/index.html
    
            log.info("拦截到请求:{}",requestURI);
    
            //定义不需要处理的请求路径
            String[] urls = new String[]{
                    "/employee/login",
                    "/employee/logout",
                    "/backend/**",
                    "/front/**"
            };
    
    
            //2、判断本次请求是否需要处理
            boolean check = check(urls, requestURI);
    
            //3、如果不需要处理,则直接放行
            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;
                }
            }
            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
    • 67
    • 68
    • 69
    • 70

    3,总结

    到此,项目的整体框架以及基础的登录推出功能已经完成了,看看自己搭建的项目的详细目录,对每个模块以及其作用是不是一目了然,接下来的功能开发也是按照上述的流程逐步完成。

    在这里插入图片描述

    注意:本博客为跟随《黑马程序员》学习,并搭建项目的详细流程记录。文中所需要的数据库sql文件以及静态资源文件和详细代码,都可以通过关注公众号黑马程序员,回复”瑞吉外卖“获得。

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    社区版idea找不到Test
    Adobe Acrobat 编辑器软件下载安装,Acrobat 轻松编辑和管理各种PDF文件
    Spire.Doc 10.11.9 支持设置形状填充颜色的透明度
    1 随机事件与概率
    支持向量机:原理与python案例
    vue 生成二维码的两种方式
    Python单元测试
    45、DVGO
    数字电路和模拟电路-10时序逻辑电路的分析和设计
    MJ 种的摄影提示词关键字
  • 原文地址:https://blog.csdn.net/m0_67401761/article/details/126080586