当前位置: 首页 > news >正文

苍穹外卖上半部分总结

苍穹外卖一个很经典的项目 虽然已经烂大街,但项目依旧是很优秀,并且代码十分规范,很值得学习。

前置介绍

niginx反向代理

前端和后端的url请求不一致的原因:前端是请求到nginx服务器,再由nginx服务器转发到后端

nginx的好处

1.提高访问速度,当这条数据相同,不必要到后端去处理了,之间有nginx服务器返回数据,nginx就相当于一个缓存,redis

2.进行负载均衡 ,后端可能有多个服务器,访问一个服务器,会导致服务器压力大,就由nginx把请求均匀分配给多个服务器

3.保证后端服务安全,直接把后端url暴露,是不安全的行为。让前端访问nginx服务器,不暴露后端

niginx配置

负债均衡配置

负债均衡策略

配置文件

接口文档

apifox

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

创建项目-项目设置-导入数据-Yapi-导入数据

接口测试文档

Swagger是在开发阶段使用的框架,用在后端测试接口测试

Swagger常用注解

@Api用在类上,描述这个类中接口的作用

@ApiOperation用在方法上,描述此接口的功能

@ApiModel描述自定义返回类型

@ApiModelProperty描述参数的作用

用Swagger测试功能记得添加jwt令牌全局参数

添加全局参数 校验过令牌

1.正常获取令牌

2.添加全局参数

项目目录

项目分为三个包

sky-common、sky-pojo、sky-server

sky-common包主要存放的都是静态常量

sky-common包目录

如信息异常常量类:

sky-pojo包主要存放的是各种O 统称POJO和数据库对应的类

包目录

DTO是专门接收前端传来的数据,整合成一个类 统称DTO

VO是后端整合的数据传给前端,统称VO

sky-server包存放控制类、接口类、数据库Mapper和.XML以及配置类

接口实现

员工登录相关接口

前端穿的是JSON数据时,应加上@RequestBody注解 接收JSON文件

调用服务类接口

接口调用实现类

实现类

成功后生成jwt令牌

将数据整合为VO 返回

添加员工接口

这里就不再接收控制类 都是一样的 调用服务类 直接讲解服务类实现即可

数据初始化后,添加到数据库

分页查询

返回的类型是pageResut

使用的是PageHelper插件 简化分页查询

pageHelper是一个帮我们自动计算页数的插件

pom.xml

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>

使用方法:

传入当前页数,和每页多少条数据

//使用pageHelper 简化分页查询         参数1 当前查询的页数 参数2 每页多少条数据
PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());

然后以Page<你数据库返回的对应的类>

Page<Employee> page=employeeMapper.getPage(employeePageQueryDTO);

SQL内 他会自动添加limit 不需要手动计算

//共有多少条数据
long total = page.getTotal();
//查询出来每页的数据
List<Employee> result = page.getResult();

之后从数据内取出对应的数据即可

使用PageHelper的startPage方法 传入当前页码,和每页多少条数据。

传入DTO 返回类型为Page<数据库返回的封装数据(Employee)>

取出共有多少条数据 每页的总数据

返回PageResult 数据为刚出的多少条数据 每页的总数据

page插件会自动把计算,并把limit加上

启用禁用用户状态接口

前端一个传的是url参数

需要加@PathVariable注解

将数据拷贝到完整数据类内

动态SQL 避免代码冗余

当某个字段不为空时,就加上对应的SQL语句

根据ID查询员工信息

查询后,密码即使加密过,也不暴露显示,统一改为

修改员工信息接口

因为前端传的是JSON数据 所以要加@RequestBody注解 接收JSON数据

将DTO数据拷贝到完整类内

SQL直接复用动态sql即可。

分类接口

分类接口大部分与员工接口逻辑相似

新增分类

将DTO数据拷贝到完整类内

分类分页查询

使用PageHelper插件帮忙计算limit

使用PageHelper的startPage方法传入当前页码和查询数量

返回总数和数据列表

SQL语句

删除分类

若分类中有关联菜品 无法直接删除

修改分类

将DTO数据拷贝到完整类内

动态SQL 提高复用性

启用、禁用分类

数据舒适化后,复用动态SQL

根据类型查询分类

公共接口

上传文件接口

这里使用的是OSS 客户端把图片,音频等上传到服务器,服务器不本地保存,上传到阿里云OSS内

配置OSS

阿里创建OSS

网页端上传服务端 服务端不在本地存放图片、视频、音频 而是在云端存放,这样不会在服务器消耗内存,减少服务器消耗。

登录阿里云 购买OSS

之后创建AccessKey 会让你下载一个excel 里面存放的是AccessKeyID和AccessKey Secret 这个只能查看一次,所以excel务必保存好。

endpoint 是域名的外围的endpoint 具体参考:

access-key-id和access-key-secret就是下载的excel文件内存放的

bucket-name就是你创建Bucket的名字

帮助中心

pom.xml

<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId>
</dependency>
​
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId>
</dependency>

这是上传文件的配置文件

package com.sky.utils;
​
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;
​
@Data
@AllArgsConstructor
@Slf4j
public class AliOssUtil {
​private String endpoint;private String accessKeyId;private String accessKeySecret;private String bucketName;
​/*** 文件上传** @param bytes* @param objectName* @return*/public String upload(byte[] bytes, String objectName) {
​// 创建OSSClient实例。OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
​try {// 创建PutObject请求。ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));} catch (OSSException oe) {System.out.println("Caught an OSSException, which means your request made it to OSS, "+ "but was rejected with an error response for some reason.");System.out.println("Error Message:" + oe.getErrorMessage());System.out.println("Error Code:" + oe.getErrorCode());System.out.println("Request ID:" + oe.getRequestId());System.out.println("Host ID:" + oe.getHostId());} catch (ClientException ce) {System.out.println("Caught an ClientException, which means the client encountered "+ "a serious internal problem while trying to communicate with OSS, "+ "such as not being able to access the network.");System.out.println("Error Message:" + ce.getMessage());} finally {if (ossClient != null) {ossClient.shutdown();}}
​//文件访问路径规则 https://BucketName.Endpoint/ObjectNameStringBuilder stringBuilder = new StringBuilder("https://");stringBuilder.append(bucketName).append(".").append(endpoint).append("/").append(objectName);
​log.info("文件上传到:{}", stringBuilder.toString());
​return stringBuilder.toString();}
}
创建一个配置类 创建Util对象

public class OssConfiguration {
​@Bean@ConditionalOnMissingBeanpublic AliOssUtil aliOssUtil(AliOssProperties aliOssProperties){log.info("开始创建阿里上传文件对象{}",aliOssProperties);return new AliOssUtil(aliOssProperties.getEndpoint(),aliOssProperties.getAccessKeyId(),aliOssProperties.getAccessKeySecret(),aliOssProperties.getBucketName());}
​
}

创建一个公共接口

自定义注解

当插入数据或修改数据时,都需要手动更改创建人id 修改人id 创建时间,修改时间等,代码造成冗余,所以自定义一个注解,当执行此类操作时,统一完成操作即可,避免代码冗余

创建一个自定义注解接口

public class AutoFillAspect {
​/*** 指定切入点* 参数1 指定拦截的路径    参数2 注解存在的路径*/@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void autoFillPointCut(){}
​/*** 前置通知,在通知中进行公共字段的赋值* 在方法执行前进行拦截 并且把对应属性赋值*/@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint){log.info("开始进行公共字段自动填充...");
​//获取当前拦截方法中数据库上的操作类型MethodSignature signature=(MethodSignature) joinPoint.getSignature();AutoFill autoFill=signature.getMethod().getAnnotation(AutoFill.class);OperationType operationType=autoFill.value();
​//获取当前拦截方法的参数Object[] args=joinPoint.getArgs();if(args==null || args.length==0){return;}
​Object entity=args[0];
​//准备当前时间和用户idLocalDateTime now=LocalDateTime.now();Long currenId= BaseContext.getCurrentId();
​//根据数据库操作类型的不同,为对应的属性通过反射赋值if(operationType==OperationType.INSERT){//如果市插入数据 为四个属性赋值try {Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
​//通过反射为对象属性赋值setCreateTime.invoke(entity,now);setCreateUser.invoke(entity,currenId);setUpdateTime.invoke(entity,now);setUpdateUser.invoke(entity,currenId);} catch (Exception e) {throw new RuntimeException(e);}}if(operationType==OperationType.UPDATE){//如果是修改 就为两个属性赋值try {Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
​//通过反射为对象属性赋值setUpdateTime.invoke(entity,now);setUpdateUser.invoke(entity,currenId);} catch (Exception e) {throw new RuntimeException(e);}}}

菜品管理接口

新增菜品接口

不仅仅要添加菜品 还要添加菜品的口味 菜品口味再另一个表

添加菜品口味 需要菜品的id 菜品id为自增 所以要返回菜品的id

插入菜品口味时,都需要设置菜品id

动态SQL 循环插入 第一个为形参参数 每个遍历出来的名字 用,分割

菜品分页接口

菜品停、启接口

复用SQL接口

根据ID查询菜品新接口

这个接口是当要修改菜品信息时 把菜品信息返回给前端

查询出菜品信息,还得查询菜品对应的口味数据

然后封装成VO返回给前端

批量删除菜品接口

前端穿的是String 1,2,3 这样的 使用@RequestParam转换成List<Long>类型

修改菜品接口


http://www.mrgr.cn/news/34537.html

相关文章:

  • 【灭鼠先锋 / B】
  • 《CUDA编程》1.GPU硬件与CUDA环境搭建
  • 某恩加密数据爬虫逆向分析
  • P4630 [APIO2018] 铁人两项(圆方树模版)
  • 基于SpringBoot+Vue+MySQL的旅游推荐管理系统
  • 24. Revit API: 几何对象(五)- (Sur)Face
  • QT中添加资源文件
  • 隐匿发案:David律所代理艺术家Ina Tomecek的两张青蛙版权画维权
  • 在 macOS 上安装 FFmpeg 的详细指南
  • 有关在.Net Core中以TEXT类型将Json格式字段存到数据库的学习
  • 通义千问模型升级:2.5正式上线的使用体验
  • 设计模式介绍
  • 动态时间【JavaScript】
  • 通过spring-boot创建web项目
  • PostgreSQL的学习心得和知识总结(一百五十一)|[performance] PostgreSQL列对齐
  • 杰发科技——Eclipse环境安装
  • 很有意思的css动态渐变
  • 基于SpringBoot+Vue+MySQL的电影院购票管理系统
  • JavaEE: 深入探索TCP网络编程的奇妙世界(六)
  • 怎么开通GitHub Copilot?不会开通GitHub Copilot?一文看懂