ToB企服应用市场:ToB评测及商务社交产业平台

标题: 苍穹外卖-第一章项目介绍 [打印本页]

作者: 鼠扑    时间: 2023-10-11 04:54
标题: 苍穹外卖-第一章项目介绍
1. 苍穹外卖项目介绍

1.1 项目介绍

1)管理端功能
员工登录/退出 , 员工信息管理 , 分类管理 , 菜品管理 , 套餐管理 , 菜品口味管理 , 订单管理 ,数据统计,来单提醒。
2)用户端功能
微信登录 , 收件人地址管理 , 用户历史订单查询 , 菜品规格查询 , 购物车功能 , 下单 , 支付、分类及菜品浏览。
1.2 产品原型

1)管理端
餐饮企业内部员工使用。 主要功能有:
模块描述登录/退出内部员工必须登录后,才可以访问系统管理后台员工管理管理员可以在系统后台对员工信息进行管理,包含查询、新增、编辑、禁用等功能分类管理主要对当前餐厅经营的 菜品分类 或 套餐分类 进行管理维护, 包含查询、新增、修改、删除等功能菜品管理主要维护各个分类下的菜品信息,包含查询、新增、修改、删除、启售、停售等功能套餐管理主要维护当前餐厅中的套餐信息,包含查询、新增、修改、删除、启售、停售等功能订单管理主要维护用户在移动端下的订单信息,包含查询、取消、派送、完成,以及订单报表下载等功能数据统计主要完成对餐厅的各类数据统计,如营业额、用户数量、订单等2)用户端
移动端应用主要提供给消费者使用。主要功能有:
模块描述登录/退出用户需要通过微信授权后登录使用小程序进行点餐点餐-菜单在点餐界面需要展示出菜品分类/套餐分类, 并根据当前选择的分类加载其中的菜品信息, 供用户查询选择点餐-购物车用户选中的菜品就会加入用户的购物车, 主要包含 查询购物车、加入购物车、删除购物车、清空购物车等功能订单支付用户选完菜品/套餐后, 可以对购物车菜品进行结算支付, 这时就需要进行订单的支付个人信息在个人中心页面中会展示当前用户的基本信息, 用户可以管理收货地址, 也可以查询历史订单数据1.3 技术选型

关于本项目的技术选型, 我们将会从 用户层、网关层、应用层、数据层 这几个方面进行介绍,主要用于展示项目中使用到的技术框架和中间件等。
1)用户层
后台的前端页面用到H5、Vue.js、ElementUI、apache echarts(展示图表)等技术。移动端应用使用到微信小程序。
2)网关层
Nginx是一个服务器,主要用来作为Http服务器,部署静态资源,访问性能高。在Nginx中还有两个比较重要的作用: 反向代理和负载均衡, 在进行项目部署时,要实现Tomcat的负载均衡,就可以通过Nginx来实现。
3)应用层
4)数据层
5)工具
2. 开发环境搭建

2.1 熟悉项目结构

对工程的每个模块作用说明:
序号名称说明1sky-take-outmaven父工程,统一管理依赖版本,聚合其他子模块2sky-common子模块,存放公共类,例如:工具类、常量类、异常类等3sky-pojo子模块,存放实体类、VO、DTO等4sky-server子模块,后端服务,存放配置文件、Controller、Service、Mapper等
2.2 数据库环境搭建

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

1.Controller层
在sky-server模块中,com.sky.controller.admin.EmployeeController
  1. /**
  2.      * 登录
  3.      *
  4.      * @param employeeLoginDTO
  5.      * @return
  6.      */
  7.     @PostMapping("/login")
  8.     public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {
  9.         log.info("员工登录:{}", employeeLoginDTO);
  10.                 //调用service方法查询数据库
  11.         Employee employee = employeeService.login(employeeLoginDTO);
  12.         //登录成功后,生成jwt令牌
  13.         Map<String, Object> claims = new HashMap<>();
  14.         claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
  15.         String token = JwtUtil.createJWT(
  16.                 jwtProperties.getAdminSecretKey(),
  17.                 jwtProperties.getAdminTtl(),
  18.                 claims);
  19.         EmployeeLoginVO employeeLoginVO = EmployeeLoginVO.builder()
  20.                 .id(employee.getId())
  21.                 .userName(employee.getUsername())
  22.                 .name(employee.getName())
  23.                 .token(token)
  24.                 .build();
  25.         return Result.success(employeeLoginVO);
  26.     }
复制代码
2.Service层
在sky-server模块中,com.sky.service.impl.EmployeeServiceImpl
  1. /**
  2.      * 员工登录
  3.      *
  4.      * @param employeeLoginDTO
  5.      * @return
  6.      */
  7.     public Employee login(EmployeeLoginDTO employeeLoginDTO) {
  8.         String username = employeeLoginDTO.getUsername();
  9.         String password = employeeLoginDTO.getPassword();
  10.         //1、根据用户名查询数据库中的数据
  11.         Employee employee = employeeMapper.getByUsername(username);
  12.         //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
  13.         if (employee == null) {
  14.             //账号不存在
  15.             throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
  16.         }
  17.         //密码比对
  18.         if (!password.equals(employee.getPassword())) {
  19.             //密码错误
  20.             throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
  21.         }
  22.         if (employee.getStatus() == StatusConstant.DISABLE) {
  23.             //账号被锁定
  24.             throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
  25.         }
  26.         //3、返回实体对象
  27.         return employee;
  28.     }
复制代码
3.Mapper层
在sky-server模块中,com.sky.mapper.EmployeeMapper
  1. package com.sky.mapper;
  2. import com.sky.entity.Employee;
  3. import org.apache.ibatis.annotations.Mapper;
  4. import org.apache.ibatis.annotations.Select;
  5. @Mapper
  6. public interface EmployeeMapper {
  7.     /**
  8.      * 根据用户名查询员工
  9.      * @param username
  10.      * @return
  11.      */
  12.     @Select("select * from employee where username = #{username}")
  13.     Employee getByUsername(String username);
  14. }
复制代码
注:可以通过断点调试跟踪后端程序的执行过程
2.4 nginx反向代理和负载均衡

对登录功能测试完毕后,接下来一个问题:前端发送的请求,是如何请求到后端服务的?
前端请求地址:http://localhost/api/employee/login
后端接口地址:http://localhost:8080/admin/employee/login
很明显,两个地址不一致,那是如何请求到后端服务的呢?
1)nginx反向代理
nginx 反向代理,就是将前端发送的动态请求由 nginx 转发到后端服务器
那为什么不直接通过浏览器直接请求后台服务端,需要通过nginx反向代理呢?
nginx 反向代理的好处:
nginx 反向代理的配置方式:
  1. server{
  2.     listen 80;
  3.     server_name localhost;
  4.     location /api/{
  5.         proxy_pass http://localhost:8080/admin/; #反向代理
  6.     }
  7. }
复制代码
proxy_pass:该指令是用来设置代理服务器的地址,可以是主机名称,IP地址加端口号等形式。
如上代码的含义是:监听80端口号, 然后当我们访问 http://localhost:80/api/../..这样的接口的时候,它会通过 location /api/ {} 这样的反向代理到 http://localhost:8080/admin/上来。
接下来,进到nginx-1.20.2\conf,打开nginx配置
  1. # 反向代理,处理管理端发送的请求
  2. location /api/ {
  3.         proxy_pass   http://localhost:8080/admin/;
  4.     #proxy_pass   http://webservers/admin/;
  5. }
复制代码
当在访问http://localhost/api/employee/login,nginx接收到请求后转到http://localhost:8080/admin/,故最终的请求地址为http://localhost:8080/admin/employee/login,和后台服务的访问地址一致
2)nginx 负载均衡
当如果服务以集群的方式进行部署时,那nginx在转发请求到服务器时就需要做相应的负载均衡。其实,负载均衡从本质上来说也是基于反向代理来实现的,最终都是转发请求。
nginx 负载均衡的配置方式:
  1. upstream webservers{
  2.     server 192.168.100.128:8080;
  3.     server 192.168.100.129:8080;
  4. }
  5. server{
  6.     listen 80;
  7.     server_name localhost;
  8.     location /api/{
  9.         proxy_pass http://webservers/admin;#负载均衡
  10.     }
  11. }
复制代码
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依据响应时间方式,响应时间短的服务将会被优先分配具体配置方式:
轮询:
  1. upstream webservers{
  2.     server 192.168.100.128:8080;
  3.     server 192.168.100.129:8080;
  4. }
复制代码
weight:
  1. upstream webservers{
  2.     server 192.168.100.128:8080 weight=90;
  3.     server 192.168.100.129:8080 weight=10;
  4. }
复制代码
ip_hash:
  1. upstream webservers{
  2.     ip_hash;
  3.     server 192.168.100.128:8080;
  4.     server 192.168.100.129:8080;
  5. }
复制代码
least_conn:
  1. upstream webservers{
  2.     least_conn;
  3.     server 192.168.100.128:8080;
  4.     server 192.168.100.129:8080;
  5. }
复制代码
url_hash:
  1. upstream webservers{
  2.     hash &request_uri;
  3.     server 192.168.100.128:8080;
  4.     server 192.168.100.129:8080;
  5. }
复制代码
fair:
  1. upstream webservers{
  2.     server 192.168.100.128:8080;
  3.     server 192.168.100.129:8080;
  4.     fair;
  5. }
复制代码
3. 完善登录功能

问题:员工表中的密码是明文存储,安全性太低。
解决思路:
实现步骤:
  1.    /**
  2.         * 员工登录
  3.         *
  4.         * @param employeeLoginDTO
  5.         * @return
  6.         */
  7.        public Employee login(EmployeeLoginDTO employeeLoginDTO) {
  8.            //1、根据用户名查询数据库中的数据
  9.            //2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
  10.            //.......
  11.            //密码比对
  12.            // TODO 后期需要进行md5加密,然后再进行比对
  13.            password = DigestUtils.md5DigestAsHex(password.getBytes());
  14.            if (!password.equals(employee.getPassword())) {
  15.                //密码错误
  16.                throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
  17.            }
  18.            //3、返回实体对象
  19.            return employee;
  20.        }
复制代码
4. Swagger

4.1 介绍

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务(https://swagger.io/)。 它的主要作用是:
Spring已经将Swagger纳入自身的标准,建立了Spring-swagger项目,现在叫Springfox。通过在项目中引入Springfox ,即可非常简单快捷的使用Swagger。
knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui,取名kni4j是希望它能像一把匕首一样小巧,轻量,并且功能强悍!
目前,一般都使用knife4j框架。
4.2 使用步骤

在pom.xml中添加依赖
  1.    <dependency>
  2.       <groupId>com.github.xiaoymin</groupId>
  3.       <artifactId>knife4j-spring-boot-starter</artifactId>
  4.    </dependency>
复制代码
WebMvcConfiguration.java
  1.    /**
  2.         * 通过knife4j生成接口文档
  3.         * @return
  4.    */
  5.        @Bean
  6.        public Docket docket() {
  7.            ApiInfo apiInfo = new ApiInfoBuilder()
  8.                    .title("苍穹外卖项目接口文档")
  9.                    .version("2.0")
  10.                    .description("苍穹外卖项目接口文档")
  11.                    .build();
  12.            Docket docket = new Docket(DocumentationType.SWAGGER_2)
  13.                    .apiInfo(apiInfo)
  14.                    .select()
  15.                    .apis(RequestHandlerSelectors.basePackage("com.sky.controller"))
  16.                    .paths(PathSelectors.any())
  17.                    .build();
  18.            return docket;
  19.        }
复制代码
WebMvcConfiguration.java
  1.    /**
  2.         * 设置静态资源映射
  3.         * @param registry
  4.    */
  5.    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
  6.            registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
  7.            registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
  8.    }
复制代码
接口文档访问路径为 http://ip:port/doc.html ---> http://localhost:8080/doc.html
4.3 常用注解

通过注解可以控制生成的接口文档,使接口文档拥有更好的可读性,常用注解如下:
注解说明@Api用在类上,例如Controller,表示对类的说明@ApiModel用在类上,例如entity、DTO、VO@ApiModelProperty用在属性上,描述属性信息@ApiOperation用在方法上,例如Controller的方法,说明方法的用途、作用接下来,使用上述注解,生成可读性更好的接口文档
在sky-pojo模块中
EmployeeLoginDTO.java
  1. package com.sky.dto;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. import lombok.Data;
  5. import java.io.Serializable;
  6. @Data
  7. @ApiModel(description = "员工登录时传递的数据模型")
  8. public class EmployeeLoginDTO implements Serializable {
  9.     @ApiModelProperty("用户名")
  10.     private String username;
  11.     @ApiModelProperty("密码")
  12.     private String password;
  13. }
复制代码
EmployeeLoginVo.java
  1. package com.sky.vo;
  2. import io.swagger.annotations.ApiModel;
  3. import io.swagger.annotations.ApiModelProperty;
  4. import lombok.AllArgsConstructor;
  5. import lombok.Builder;
  6. import lombok.Data;
  7. import lombok.NoArgsConstructor;
  8. import java.io.Serializable;
  9. @Data
  10. @Builder
  11. @NoArgsConstructor
  12. @AllArgsConstructor
  13. @ApiModel(description = "员工登录返回的数据格式")
  14. public class EmployeeLoginVO implements Serializable {
  15.     @ApiModelProperty("主键值")
  16.     private Long id;
  17.     @ApiModelProperty("用户名")
  18.     private String userName;
  19.     @ApiModelProperty("姓名")
  20.     private String name;
  21.     @ApiModelProperty("jwt令牌")
  22.     private String token;
  23. }
复制代码
在sky-server模块中
EmployeeController.java
  1. package com.sky.controller.admin;
  2. import com.sky.constant.JwtClaimsConstant;
  3. import com.sky.dto.EmployeeLoginDTO;
  4. import com.sky.entity.Employee;
  5. import com.sky.properties.JwtProperties;
  6. import com.sky.result.Result;
  7. import com.sky.service.EmployeeService;
  8. import com.sky.utils.JwtUtil;
  9. import com.sky.vo.EmployeeLoginVO;
  10. import io.swagger.annotations.Api;
  11. import io.swagger.annotations.ApiOperation;
  12. import lombok.extern.slf4j.Slf4j;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.web.bind.annotation.PostMapping;
  15. import org.springframework.web.bind.annotation.RequestBody;
  16. import org.springframework.web.bind.annotation.RequestMapping;
  17. import org.springframework.web.bind.annotation.RestController;
  18. import java.util.HashMap;
  19. import java.util.Map;
  20. /**
  21. * 员工管理
  22. */
  23. @RestController
  24. @RequestMapping("/admin/employee")
  25. @Slf4j
  26. @Api(tags = "员工相关接口")
  27. public class EmployeeController {
  28.     @Autowired
  29.     private EmployeeService employeeService;
  30.     @Autowired
  31.     private JwtProperties jwtProperties;
  32.     /**
  33.      * 登录
  34.      *
  35.      * @param employeeLoginDTO
  36.      * @return
  37.      */
  38.     @PostMapping("/login")
  39.     @ApiOperation(value = "员工登录")
  40.     public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO)         {
  41.         //
  42.     }
  43.     /**
  44.      * 退出
  45.      *
  46.      * @return
  47.      */
  48.     @PostMapping("/logout")
  49.     @ApiOperation("员工退出")
  50.     public Result<String> logout() {
  51.         return Result.success();
  52.     }
  53. }
复制代码
启动服务:访问http://localhost:8080/doc.html

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4