项目实战——苍穹外卖(Day1)

目录

1.项目介绍

1.项目整体效果展示

2.软件开发整体介绍

3.苍穹外卖项目介绍

2.开发环境搭建

2.1前端环境搭建

2.2后端环境搭建

2.2.1熟悉项目结构

2.2.2Git版本控制

2.2.3数据库环境搭建

2.2.4前后端联调

2.2.5nginx反向代理和负载均衡

2.3完善登陆功能

3.导入接口文档

3.1前后端分离开发流程

3.2 操作步骤

4.Swagger

4.1介绍

4.2使用步骤

4.3常用注解


1.项目介绍

分三个模块进行开发:

基础数据模块

  • 项目概述
  • 环境搭建
  • 员工管理
  • 分类管理
  • 菜品管理
  • 套餐管理实战

点餐业务模块

  • 店铺营业状态设置
  • 微信登录
  • 缓存商品
  • 购物车
  • 用户下单
  • 订单支付和管理
  • 历史订单
  • 订单状态定时处理
  • 来单提醒和客户催单

统计报表模块

  • 图形报表统计
  • Excel报表统计

1.项目整体效果展示

项目实战——苍穹外卖(Day1)_第1张图片

2.软件开发整体介绍

软件开发流程:

项目实战——苍穹外卖(Day1)_第2张图片

角色分工:

  • 项目经理:对整个项目负责,任务分配、把控进度
  • 产品经理:进行需求调研,输出需求调研文档、产品原型等
  • UI设计师:根据产品原型输出界面效果图
  • 架构师:项目整体架构设计、技术选型等
  • 开发工程师:代码实现
  • 测试工程师:编写测试用例,输出测试报告
  • 运维工程师:软件环境搭建、项目上线

软件环境:

  • 开发环境(development):开发人员在开发阶段使用的环境,一般外部用户无法访问
  • 测试环境(testing):专门给测试人员使用的环境,用于测试项目,一般外部用户无法访问
  • 生产环境(production):即线上环境,正式提供对外服务的环境

项目实战——苍穹外卖(Day1)_第3张图片

3.苍穹外卖项目介绍

《苍穹外卖》项目的定位是一款为餐饮企业(餐厅、饭店)定制的软件产品。该项目是一个在线外卖订购系统,顾客可以通过网站或者手机 App 订购餐点。

 该项目可以提供以下的功能:

用户可以注册和登录账号,浏览餐厅列表,选择菜单,并下单和支付;
餐厅可以注册账号并进行菜单管理,接收和处理订单;
后台管理员可以管理餐厅和用户账号信息,处理订单和投诉,生成销售报表等。

苍穹外卖项目需要具备以下的技术要求:

网站和手机 App 的设计和开发;
数据库管理系统的设计和实现;
支付系统的接入和开发;
与第三方配送公司的对接和管理;
安全性和隐私保护的考虑,如防止 SQL 注入、XSS 攻击和数据泄露。

功能架构:业务功能模可划分为管理端和用户端两大模块

项目实战——苍穹外卖(Day1)_第4张图片

产品原型:用于展示项目的业务功能,一般由产品经理进行设计

项目实战——苍穹外卖(Day1)_第5张图片

技术选型:展示项目中使用到的技术框架和中间件等

项目实战——苍穹外卖(Day1)_第6张图片

2.开发环境搭建

2.1前端环境搭建

项目实战——苍穹外卖(Day1)_第7张图片

        开发环境搭建主要包含前端环境后端环境两部分。作为服务端开发工程师, 我们课程学习的重心应该放在后端的业务代码上, 前端的页面我们只需要导入资料中的nginx。

         前端工程基于 nginx,找到前端运行环境的nginx,移动到非中文目录下。双击 nginx.exe 即可启动 nginx 服务,如果端口号冲突可以将nginx的访问端口号修改为8081等。

项目实战——苍穹外卖(Day1)_第8张图片

访问浏览器地址【http://localhost:8081】

项目实战——苍穹外卖(Day1)_第9张图片

如果打开不了,查看nginx日志中有如下错误,按照报错信息里的路径在nginx的文件夹下新建temp文件夹 -> 新建client_body_temp文件夹,启动nginx,解决问题。

2.2后端环境搭建
2.2.1熟悉项目结构

后端工程基于 maven 进行项目构建,并且进行分模块开发。

项目实战——苍穹外卖(Day1)_第10张图片

序号 名称 说明
1 sky-take-out maven父工程,统一管理依赖版本,聚合其他子模块
2 sky-common 子模块,存放公共类,例如:工具类、常量类、异常类等
3 sky-pojo 子模块,存放实体类、VO、DTO等
4 sky-server 子模块,后端服务,存放配置文件、Controller、Service、Mapper等
  • sky-common: 模块中存放的是一些公共类,可以供其他模块使用

项目实战——苍穹外卖(Day1)_第11张图片

名称 说明
constant 存放相关常量类
context 存放上下文类
enumeration 项目的枚举类存储
exception 存放自定义异常类
json 处理json转换的类
properties 存放SpringBoot相关的配置属性类
result 返回结果类的封装
utils

常用工具类

  • sky-pojo: 模块中存放的是一些 entity、DTO、VO

项目实战——苍穹外卖(Day1)_第12张图片

名称 说明
Entity 实体,通常和数据库中的表对应
DTO 数据传输对象,通常用于程序中各层之间传递数据
VO 视图对象,为前端展示数据提供的对象
POJO 普通Java对象,只有属性和对应的getter和setter
  • sky-server: 模块中存放的是 配置文件、配置类、拦截器、controller、service、mapper、启动类等

项目实战——苍穹外卖(Day1)_第13张图片

名称 说明
config 存放配置类
controller 存放controller类
interceptor 存放拦截器类
mapper 存放mapper接口
service 存放service类
SkyApplication 启动类
2.2.2Git版本控制

使用Git进行项目代码的版本控制,具体操作:

(1)创建Git本地仓库

项目实战——苍穹外卖(Day1)_第14张图片

当Idea中出现:

说明本地仓库创建成功。

(2) 创建Git远程仓库

        访问Gitee - 企业级 DevOps 研发效能平台,新建仓库,点击新建

项目实战——苍穹外卖(Day1)_第15张图片

(3)将本地文件推送到Git远程仓库

1.提交文件至本地仓库

项目实战——苍穹外卖(Day1)_第16张图片

2.添加Git远程仓库地址

复制远程地址:

添加地址:

项目实战——苍穹外卖(Day1)_第17张图片

3.推送

项目实战——苍穹外卖(Day1)_第18张图片

成功推送至远程仓库

项目实战——苍穹外卖(Day1)_第19张图片

2.2.3数据库环境搭建

通过该sql文件直接可创建数据库,所以不需要提前创建数据库,直接导入该文件执行即可。

项目实战——苍穹外卖(Day1)_第20张图片项目实战——苍穹外卖(Day1)_第21张图片

执行完成后,共创建出11张表

项目实战——苍穹外卖(Day1)_第22张图片

序号 表名 中文名
1 employee 员工表
2 category 分类表
3 dish 菜品表
4 dish_flavor 菜品口味表
5 setmeal 套餐表
6 setmeal_dish 套餐菜品关系表
7 user 用户表
8 address_book 地址表
9 shopping_cart 购物车表
10 orders 订单表
11 order_detail 订单明细表

对于具体的表结构, 以及表结构中的字段, 可以参考资料中的《数据库设计文档》

2.2.4前后端联调

初始工程中已经实现了登录功能,直接进行前后端联调测试。

实现思路:

项目实战——苍穹外卖(Day1)_第23张图片

(1)Controller层

/**
     * 登录
     *
     * @param employeeLoginDTO
     * @return
     */
    @PostMapping("/login")
    public Result login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {
        log.info("员工登录:{}", employeeLoginDTO);
        //调用service方法查询数据库
        Employee employee = employeeService.login(employeeLoginDTO);

        //登录成功后,生成jwt令牌
        Map claims = new HashMap<>();
        claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getAdminSecretKey(),
                jwtProperties.getAdminTtl(),
                claims);

        EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()
                .id(employee.getId())
                .userName(employee.getUsername())
                .name(employee.getName())
                .token(token)
                .build();

        return Result.success(employeeLoginVO);
    }

(2)Service层

/**
     * 员工登录
     *
     * @param employeeLoginDTO
     * @return
     */
    public Employee login(EmployeeLoginDTO employeeLoginDTO) {
        String username = employeeLoginDTO.getUsername();
        String password = employeeLoginDTO.getPassword();

        //1、根据用户名查询数据库中的数据
        Employee employee = employeeMapper.getByUsername(username);

        //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
        if (employee == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        //密码比对
        if (!password.equals(employee.getPassword())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        if (employee.getStatus() == StatusConstant.DISABLE) {
            //账号被锁定
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }

        //3、返回实体对象
        return employee;
    }

(3)Mapper层

package com.sky.mapper;

import com.sky.entity.Employee;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface EmployeeMapper {

    /**
     * 根据用户名查询员工
     * @param username
     * @return
     */
    @Select("select * from employee where username = #{username}")
    Employee getByUsername(String username);

}
2.2.5nginx反向代理和负载均衡

项目实战——苍穹外卖(Day1)_第24张图片

两个地址不一致,那是如何请求到后端服务的呢?

项目实战——苍穹外卖(Day1)_第25张图片

(1)nginx反向代理

nginx 反向代理,就是将前端发送的动态请求由 nginx 转发到后端服务器

项目实战——苍穹外卖(Day1)_第26张图片

nginx 反向代理的好处:

  • 提高访问速度

    因为nginx本身可以进行缓存,如果访问的同一接口,并且做了数据缓存,nginx就直接可把数据返回,不需要真正地访问服务端,从而提高访问速度。

  • 进行负载均衡

    所谓负载均衡,就是把大量的请求按照我们指定的方式均衡的分配给集群中的每台服务器。

  • 保证后端服务安全

    因为一般后台服务地址不会暴露,所以使用浏览器不能直接访问,可以把nginx作为请求访问的入口,请求到达nginx后转发到具体的服务中,从而保证后端服务的安全。

项目实战——苍穹外卖(Day1)_第27张图片

nginx 反向代理的配置方式:

server{
    listen 80;
    server_name localhost;
    
    location /api/{
        proxy_pass http://localhost:8080/admin/; #反向代理
    }
}

proxy_pass:该指令是用来设置代理服务器的地址,可以是主机名称,IP地址加端口号等形式。

如上代码的含义是:监听80端口号, 然后当我们访问 http://localhost:80/api/../..这样的接口的时候,它会通过 location /api/ {} 这样的反向代理到 http://localhost:8080/admin/上来。

接下来,进到nginx-1.20.2\conf,打开nginx配置

# 反向代理,处理管理端发送的请求
location /api/ {
    proxy_pass   http://localhost:8080/admin/;
    #proxy_pass   http://webservers/admin/;
}

当在访问http://localhost/api/employee/login,nginx接收到请求后转到http://localhost:8080/admin/,故最终的请求地址为http://localhost:8080/admin/employee/login,和后台服务的访问地址一致。

(2)nginx 负载均衡

当如果服务以集群的方式进行部署时,那nginx在转发请求到服务器时就需要做相应的负载均衡。其实,负载均衡从本质上来说也是基于反向代理来实现的,最终都是转发请求。

nginx 负载均衡的配置方式:

upstream webservers{
    server 192.168.100.128:8080;
    server 192.168.100.129:8080;
}
server{
    listen 80;
    server_name localhost;
    
    location /api/{
        proxy_pass http://webservers/admin;#负载均衡
    }
}

upstream:如果代理服务器是一组服务器的话,我们可以使用upstream指令配置后端服务器组。

如上代码的含义是:监听80端口号, 然后当我们访问 http://localhost:80/api/../..这样的接口的时候,它会通过 location /api/ {} 这样的反向代理到 http://webservers/admin,根据webservers名称找到一组服务器,根据设置的负载均衡策略(默认是轮询)转发到具体的服务器。

注:upstream后面的名称可自定义,但要上下保持一致。

nginx 负载均衡策略:

名称 说明
轮询 默认方式
weight 权重方式,默认为1,权重越高,被分配的客户端请求就越多
ip_hash 依据ip分配方式,这样每个访客可以固定访问一个后端服务
least_conn 依据最少连接方式,把请求优先分配给连接数少的后端服务
url_hash 依据url分配方式,这样相同的url会被分配到同一个后端服务
fair 依据响应时间方式,响应时间短的服务将会被优先分配

2.3完善登陆功能

问题:员工表中的密码是明文存储,安全性太低。

解决思路:

  1. 将密码加密后存储,提高安全性 

    项目实战——苍穹外卖(Day1)_第28张图片

  2. 使用MD5加密方式对明文密码加密

实现步骤:

  1. 修改数据库中明文密码,改为MD5加密后的密文

        打开employee表,修改密码

     2.修改Java代码,前端提交的密码进行MD5加密后再跟数据库中密码比对

        打开EmployeeServiceImpl.java,修改比对密码

/**
     * 员工登录
     *
     * @param employeeLoginDTO
     * @return
     */
    public Employee login(EmployeeLoginDTO employeeLoginDTO) {

        //1、根据用户名查询数据库中的数据
       
        //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
        //.......
        //密码比对
        // TODO 后期需要进行md5加密,然后再进行比对
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!password.equals(employee.getPassword())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        //........

        //3、返回实体对象
        return employee;
    }

3.导入接口文档

前后端分离开发方式 要求我们之前需要先将接口定义好,这样前后端人员才能并行开发,

3.1前后端分离开发流程

项目实战——苍穹外卖(Day1)_第29张图片

3.2 操作步骤

将课程资料中提供的项目接口导入YApi。

(1)从资料中找到项目接口文件

(2) 导入到YApi平台

在YApi平台创建出两个项目苍穹外卖-用户端与苍穹外卖-管理端

项目实战——苍穹外卖(Day1)_第30张图片

选择苍穹外卖-管理端接口.json导入

项目实战——苍穹外卖(Day1)_第31张图片

导入成功 项目实战——苍穹外卖(Day1)_第32张图片

另一个用户端json文件也执行相同操作。

4.Swagger

4.1介绍

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务(API Documentation & Design Tools for Teams | Swagger)。 它的主要作用是:

  1. 使得前后端分离开发更加方便,有利于团队协作

  2. 接口的文档在线自动生成,降低后端开发人员编写接口文档的负担

  3. 功能测试

knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名kni4j是希望它能像一把匕首一样小巧,轻量,并且功能强悍!

目前,一般都使用knife4j框架。

4.2使用步骤

1.导入 knife4j 的maven坐标

在pom.xml中添加依赖


   com.github.xiaoymin
   knife4j-spring-boot-starter

2.在配置类中加入 knife4j 相关配置

WebMvcConfiguration.java

/**
     * 通过knife4j生成接口文档
     * @return
*/
    @Bean
    public Docket docket() {
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("苍穹外卖项目接口文档")
                .version("2.0")
                .description("苍穹外卖项目接口文档")
                .build();
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.sky.controller"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

3.设置静态资源映射,否则接口文档页面无法访问

WebMvcConfiguration.java

/**
     * 设置静态资源映射
     * @param registry
*/
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}

4.访问测试

接口文档访问路径为 http://ip:port/doc.html ---> http://localhost:8080/doc.html

项目实战——苍穹外卖(Day1)_第33张图片

接口测试:测试登录功能

项目实战——苍穹外卖(Day1)_第34张图片

思考:通过 Swagger 就可以生成接口文档,那么我们就不需要 Yapi 了?

1、Yapi 是设计阶段使用的工具,管理和维护接口

2、Swagger 在开发阶段使用的框架,帮助后端开发人员做后端的接口测试

4.3常用注解

通过注解可以控制生成的接口文档,使接口文档拥有更好的可读性,常用注解如下:

注解 说明
@Api 用在类上,例如Controller,表示对类的说明
@ApiModel 用在类上,例如entity、DTO、VO
@ApiModelProperty 用在属性上,描述属性信息
@ApiOperation 用在方法上,例如Controller的方法,说明方法的用途、作用

比如

在sky-pojo模块中

EmployeeLoginDTO.java

package com.sky.dto;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

@Data
@ApiModel(description = "员工登录时传递的数据模型")
public class EmployeeLoginDTO implements Serializable {

    @ApiModelProperty("用户名")
    private String username;

    @ApiModelProperty("密码")
    private String password;

}

你可能感兴趣的:(苍穹外卖,ui)