# 微服务架构的国内航班查询与预订系统
**Repository Path**: Xtreeroot/CSC_FlightPort
## Basic Information
- **Project Name**: 微服务架构的国内航班查询与预订系统
- **Description**: 请使用bisher分支
常州信息移动互联应用学生毕业设计
微服务架构的国内航班查询与预订系统---接口
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2022-04-18
- **Last Updated**: 2023-12-30
## Categories & Tags
**Categories**: Uncategorized
**Tags**: 毕业设计
## README
# 微服务架构的国内航班查询与预订系统
## 工程目录
## common.common_utils
该目录中存放的是公共处理中心。将经常使用到的或者不作为影响主体业务的工具类做统一管理,再通过引入依赖方式,提供给消费者
**result包:**同一结果返回处理中心
- ResultCode :统一状态码标志
- 成功:Integer SUCCESS = 20001
- 失败:Integer ERROR = 20000
- R:结果返回类
- R类的属性:Boolean success是否成功 Integer code返回的状态码 message返回的信息 Map data = new HashMap() 返回数据
- R类静态方法:public static R ok(){}成功静态方法 public static R error() {}失败静态方法 这里使用静态的目的是方便全局使用
**exceptionhandler包**:异常处理中心
- MyException extends RuntimeException继承异常类使之成为异常类
- Integer code 状态码
- String msg 异常信息
- GlobalExceptionHandler (自定义的异常处理)全局异常处理程序
**ordervo**:订单调用封装类
1. PlanelnfoOrder返回一个PlanelnfoOrder类信息
2. Userinfo Order 返回一个Userinfo Order类信息
**handler**:*@class mybatisPlus属性自动填充*处理中心
- MyMetaObjectHandler
> 在我们向数据库插入一条数据的时候,少不了一些向createTime、updateTime此类字段,每次插入的数据都要设置这些个值,很烦,通过实现MetaObjectHandler接口重写insertFill、updateFill方法解决
>
> MetaObjectHandler接口是mybatisPlus为我们提供的的一个扩展接口,我们可以利用这个接口在我们插入或者更新数据的时候,为一些字段指定默认值
>
> *对应的实体类字段上需要加@TableField(fill = FieldFill.INSERT_UPDATE)*
**utils**:工具包使用中心
- Http Client :http请求客户端
- JwtUtils:token的生成与解析器
- MD5: MD5 32位加密方式
- OrderNoUtil: 生成订单号
- RandomUtil:生成4位/6位随机数
- ResponseUtil:自定义json工具类*ResponseUtil*,然后把数据转为json数据【项目中未使用】
- 灰度发布
- Apiversion
- ApiVersionHandleMapping
- ApiVersionMappingRegister
- ApiVersionRequestCondition
- BaseConfiguration
- 添加一个自定义注解用于标注接口类以及接口方法
- 自定义HandleMapping
- 自定义封裝Requestc
- 注册自定义的 ApiVersionHandleMappingondition,
> 效果图
>
>
>
>
- AOP令牌桶
- ```
不同的接口,不同的流量控制
* map的key为 Limiter.key
* RateLimiter 创建具有指定稳定吞吐量的速率限制器,以“每秒许可数”(通常称为QPs,每秒查询数)表示。
* 返回的RateLimitor确保在任何给定的一秒钟内平均每秒发出的许可数不超过permitsPer,持续的请求在每秒钟内平滑分布。
* 当传入请求速率超过permitsPerSecond时,速率限制器将每(1.0/permitsPerSecond)秒释放一个许可。
* 当速率限制器未使用时,将允许爆发高达permitsPerSecond的许可,随后的请求将以稳定的permitsPerSecond速率顺利限制。
* Params:permitsPerSecond—返回的速率限制器的速率,以每秒可用的许可数量来衡量
* 抛出:ILLegalArgumentException-如果permitsPerSecond为负或零
```
- hystrixRegistrationBean
- 统一开启数据通道
- 
## common.service_base
**config**:工具配置包
- MybatisPlusConfig : 逻辑删除插件 分页插件 乐观锁插件
- RedisConfig: redis
- SwaggerConfig API测试中心
## infrastructure.apigateway
**config**:配置信息
- CorsConfig:处理跨域
- 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。浏览器从一个域名的网页去请求另一个域名的资源时,出现域名、端口、协议任一不同,都属于跨域。
- filter:过滤器
- AuthGlobalFilter:身份全局认证
- 对特定的api进行处理,禁止普通用户去访问特定资源 起到保护作用
- handler:解决方案
- ErrorHandlerConfig 网关错误流程 覆盖默认的异常处理
- JsonExceptionHandler 异常信息json反馈 异常时用JSON代替HTML异常信息
- 主要依赖
```xml
org.springframework.cloud
spring-cloud-starter-gateway
```
- application.yml
- 对其他的服务开启转发网关
```yaml
spring:
boot:
cloud:
routes:
- id: 需要配置网关的服务名称
uri: lb://需要配置网关的服务名称
predicates:
//指定 该服务的某个api接使用gateway服务的资源
- Path=/*/acl/**
```
## infrastructure.service-admin
### 功能需求
> 统应当具备对自身运行状况的监控及报警能力,并提供相应的可视化界面;需要为非功能需求中的熔断/限流/灰度等能力提供相应的可视化配置界面。
监控能力主要由 Spring Boot Admin来实现:
使用Actuator可以收集应用系统的健康状态、内存、线程、堆栈、配置等信息,比较全面地监控了Spring Boot应用的整个生命周期
使用Spring Boot Admin呈现这些采集到的应用监控数据、性能数据
Spring Boot Admin是一个管理和监控Spring Boot应用程序的开源项目,在对单一应用服务监控的同时也提供了集群监控方案,支持通过eureka、consul、zookeeper等注册中心的方式实现多服务监控与管理。Spring Boot Admin UI部分使用Vue JS将数据展示在前端。
Spring Boot Admin分为服务端(spring-boot-admin-server)和客户端(spring-boot-admin-client)两个组件:
spring-boot-admin-server通过采集actuator端点数据显示在spring-boot-admin-ui上,已知的端点几乎都有进行采集。
spring-boot-admin-client是对Actuator的封装,提供应用系统的性能监控数据。此外,还可以通过spring-boot-admin动态切换日志级别、导出日志、导出heapdump、监控各项性能指标等。
Spring Boot Admin服务器端负责收集各个客户的数据。各台客户端配置服务器地址,启动后注册到服务器。服务器不停地请求客户端的信息(通过Actuator接口)
在每个Spring Boot应用程序上增加Spring Boot Admin Client组件。这样每个Spring Boot应用即Admin客户端,Admin服务端通过请求Admin客户端的接口收集所有的Spring Boot应用信息并进行数据呈现,从而实现Spring Boot应用监控。
设置Spring Boot Admin的邮件提醒,需要用到Spring Boot的邮件组件:spring-boot-starter-mail。这里展示邮件报警功能的使用
- 主要依赖
```xml
控。-->
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
2.2.10.RELEASE
nl.devillers
spring-boot-admin-hystrix-dashboard
1.0.2
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-mail
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-discovery
de.codecentric
spring-boot-admin-starter-client
2.2.2
de.codecentric
spring-boot-admin-starter-server
2.2.1
```
- application.yml
```yaml
spring:
boot:
admin:
# server端的访问路径
context-path: /admin
# client端状态的生命周期,该生命周期内不会更新client状态
monitor:
status-lifetime: 100000
# 报警邮箱服务
notify:
mail:
enabled: true
# 接收者
to: 553503639@qq.com
# 发送者
from: xu_genyin@163.com
ui:
title: "国内航班微服务监控及报警"
client:
# 要注册的server端的url地址。如果要同时在多个server端口注册,则用逗号分隔各个server端的url地址
url: http://localhost:8007/admin
instance:
# server端获取client信息的路径,默认情况下server通过访问/instances请求来获取到client端的信息。
prefer-ip: true #默认值instances
# 获取到元数据的账号密码 使管理端有权限获取客户端端点数据
metadata:
user.name: ${spring.boot.admin.client.username}
user.password: ${spring..boot.admin.client.password}
# 如果server端需要进行认证时,该属性用于配置用户名
username: admin
password: 123456
# 是否启用springbootAdmin客户端
enabled: true
# 注册连接超时时间
connect-timeout: 50000
# 监控暴露所有端点
management:
endpoints:
web:
exposure:
include: '*'
exclude: env,beans
endpoint:
# health端点公开的信息
health:
# 详细信息显示给所有用户。health健康检查显示详细信息
show-details: always
# 开启shutdown端口
shutdown:
enabled: true
logfile:
# 日志文件存储位置
external-file: ./logs/log_file.log
```
### 报警能力:
### 系统监控能力:
### 熔断可视化配置界面:
## service.service order
### 功能需求
> 机票预订功能:【必选】至少应当支持对给定日期、航班机票的预订及预订后的机票改期退票功能;应当具备基本的座位库存控制能力,能正确处理多人并发预订机票时的库存扣减事务。【可选】座位价格可动态变化
#### 生成订单
接口:/order/pcorderinfo/createBaseOrder/{planeId}
生成订单的实现:
配置nacos服务发现与服务注册中心
通过feign远程调用需要的服务
通过用户登录存在浏览器head的token获取会员id 再通过会员id获取到会员的全部信息
与远程调用通过航班列表的航班id获取到航班信息
两者生成新的实体类 订单信息
#### 订单支付
接口:/order/paylog/toPay/{type}
具体实现,feign远程调用修改航班信息的方法
具体实现:
service.service_plane.mapper
```java
@Update(
{
"UPDATE pc_plane set seating = seating -1 WHERE seating !=0 AND id = #{planeId}"}
)
void updateSeatingByIdOrderReduce(@Param("planeId") String planeId );
@Update(
"UPDATE pc_plane set seating = seating +1 WHERE id = #{planeId};"
)
void updateFlagByIdOrderAdd(@Param("planeId") String planeId);
```
#### 【前端展示】
## service.service_plane
### 功能需求
> 【必选】至少应当支持在给定日期、航班号或给定日期、出发地、目的地两种组合模式下的航班查询,查询结果中至少应当包含航班的起降时间、剩余座位数、票价。【可选】如能提供按其他有现实需求的条件组合来进行航班查询
#### 航班查询
接口:**/pc/plane/getPlaneTypeCondition/{current}/{limit}**
#### 提供中转航班查询、提供往返或联程航班查询
查询条件封装于queryPlaneVo类中
```java
@Data
@ApiModel(value = "航班对象", description = "航班对象")
public class queryPlaneVo {
@ApiModelProperty(value = "出发日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private String startDateTime;
@ApiModelProperty(value = "航班号 ")
private String flightNumber;
@ApiModelProperty(value = "出发城市 ")
private String startCity;
@ApiModelProperty(value = "到达城市")
private String endCity;
@TableField(exist = false)
@ApiModelProperty(value = "开始价格 ")
private String priceStart;
@TableField(exist = false)
@ApiModelProperty(value = "结束价格")
private String priceEnd;
@TableField(exist = false)
@ApiModelProperty(value = "航班类型")
private String type;
}
```
#### 给定日期、航班号或给定日期、出发地、目的地两种组合模式下的航班查询
#### 以价格区间来查询航班
```java
// 以价格区间来查询航班
.between(PcPlaneTransfer::getPrice, query.getPriceStart(), query.getPriceEnd())
```
#### 【前端展示】
## service.service_ user
### 用户登录
接口:/user/pcuserinfo/login
具体实现:用户传入参数phone 与password 交给后台进行参数效验
将密码加密为MD32位密文 再用数据库进行对比
这里主要使用到了JWT生成Token随机字符串与 MD5加密工具
登录完成后的用户会将自己的信息信息转化为token,前端工程师可通过“通过token获取用户信息”对用户对的信息进行效验
#### JWT实现
使用Jwts.builder()方法
返回一个新的JwtBuilder实例,该实例可以配置,然后用于创建JWT压缩序列化字符串。
主要设置为:头部标题:type:JWT&alg:HS256
alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT
**playload**:subject:scsFp-user
expiration:1000 * 60 * 60 * 24;
jwt id:id
signwith:SignatureAlgorithm.HS256, APP_SECRET
标准中注册的声明(常用)
iss(issuer):表示JWT的签发者
sub(subject):表示JWT的所有者
aud(audience):表示JWT的接受者
exp(expiration):一个时间戳,表示JWT的过期时间
nbf(not before):一个时间戳,表示该JWT的生效时间,在这个时间之前验证JWT是会失败的
iat(issued at):一个时间戳,表示这个JWT的签发时间
jti(jwt id):JWT的唯一标识(也常用于redis的键)
公共的声明(可以存放任何信息,通常用Map保存键值对,然后再加入其中)
私有的声明(可以存放签发者和接收者共同定义的信息,不常用)
MD5具体实现:
```java
public static String encrypt(String strSrc) {
try {
char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f' };
byte[] bytes = strSrc.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
bytes = md.digest();
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
return new String(chars);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("MD5加密出错!!+" + e);
}
}
```
### 用户注册
接口:/user/pcuserinfo/regist
用户传入关键参数 code(具体获得code请看service.service_sms) phone password 交给后台进行参数效验
将密码加密为MD32位密文 再存入数据库
这里主要使用到 MD5加密工具(与上同)
### 通过token获取用户信息
接口:/user/pcuserinfo/getUserInfoByToken
具体实现:通过获取浏览器头部不的关键字“token”获取到用户token码 返回用户id
这里是一个反向token的过程
## service.service_sms
### 短信服务
在我的配置文件中写入自己的配置信息:
```yaml
tencent:
sms:
account:
secret_id: xxxxx
secret_key: xxxxx
sms_sdk_app_id: xxxxx
template_id: xxxxx
sign_name: xxxxx
```
设置腾讯短信发送基本配置
腾讯短信网关、区域:
```java
private static String URL ="sms.tencentcloudapi.com";
private static final String REGION = "ap-guangzhou";
```
从配置文件中注入到基本配置
认证实例化
```java
public SmsClient smsClient(){
// 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,
Credential cred = new Credential(SECRET_ID, SECRET_KEY);
// 实例化一个http选项,可选的,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint(URL);
// 实例化一个client选项,可选的,没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
//实例化 SMS 的 client 对象
return new SmsClient(cred, REGION, clientProfile);
}
```
接口:/tencentSms/send/{phone}
具体实现:
先从redis里去获取验证码
如果redis获取不到验证码就到腾讯发送
发送成功后将验证码发到redis里面
设置有效时间3分钟
## service.service_upload
### 上传服务
接口:/upload/
在我的配置文件中写入自己的保存路径信息:
```yaml
yuan:
file:
root:
## 定义文件保存的路径
path: /Users/xugenyin/CSC/CSC_FlightPort/service/service_upload/src/main/java/com/treeroot/uploadservice/static/
```
将保存在本地的资源映射到文件根路径
WebMvcConfigurer配置类其实Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制,可以自定义一些Handler,Interceptor,ViewResolver,MessageConverter。基于java-based方式的spring mvc配置,需要创建一个配置类并实现WebMvcConfigurer 接口
通过ResourceHandlers实现静态资源的地址映射
**配置ResourceHandlers**
此方法用来专门注册一个`Handler`,来处理静态资源的,例如:图片,js,css等
具体实现:
判断上传的文件是否为空
不为空则返回文件原始名称,截取到原始名称`.`后至\
作为分类文件夹
如果上传的文件没有该分类目录则创建并将文件保存至此目录
再通过 requst请求获取到端口号文件名变成一个可在网络访问的文件
## service.service_ address
### 地区管理
接口:/address/list/tree/{provinceCode}/{cityCode}
代码
```java
// 通过省code与城市中省code匹配 查出该省下的市 @Select( "select city.* " + "from pc_ad_province province, pc_ad_city city " + "where (province.code = city.provinceCode) AND province.code =#{provinceCode}" ) List getCity(@Param("provinceCode") String provinceCode); // 通过城市code与镇中省code匹配 查出该市下的镇 @Select( "select town.* " + "from pc_ad_city city ,pc_ad_town town " + "where (city.code = town.cityCode) AND city .code = #{cityCode}" ) List getTown(@Param("cityCode") String cityCode);}
```
具体实现:
首次加载时返回所有的省份与省份code用于获取用户选择的省份下的市区
# END
------二零二二年六月二十日
#### 起步
Create in 22:52 / 2022/4/18
Author:TreeRoot
#### 使用说明
#### 参与贡献
TreeRoot
**2022-04-18 21:02**
**author:TreeRoot**
**2022-12-29 15:24**
**author:TreeRoot**