/aws-hackathon-2021

aws-hackathon-2021

Primary LanguageJava

aws-hackathon-2021

Demo

项目背景

为了让更多人了解并培养使用亚马逊电子书的习惯,我们设计并实现了一个模拟亚马逊的电子书促销系统。

  • 前提假设:
    1. 假定所依赖的其他系统完好,使用模拟数据,比如库存系统。所模拟的数据库包括user_info, user password, items_info, items_stock, order_info, promo_info, sequence_info。
    2. 用户信息和密码表分开用以保护用户信息安全,性别输入为0/1的形式,商品信息和库存分开用来保护商品信息安全,sequence_info流水号用于解决事务createorder下单回滚的情况。
    3. 用户既可以是买家下单买书,也可以是卖家上架书籍售卖,买书或者卖书均需要登陆(基于token实现分布式会话)。
    4. 优惠书籍和原价书籍分区展示。优惠券类型设置为“折扣”,反映在“抢购折扣”页面,此页面展示电子书打折后的价格,详见下图1.

      (图1)

    5. 全部书籍(All Books)区域包含即将开始秒杀,秒杀已经结束和正在秒杀阶段的全部书籍,点击buy按钮可查看活动进展。若秒杀活动还未开始,页面显示活动开始时间和倒计时,折扣价格和原价,下单按钮被disable直到秒杀活动开始。

      (图2)

    6. 考虑到是电子书,每次下单,订购数目默认是1。
    7. 秒杀系统的主页无需登录即可浏览折扣书籍和全部在售书籍,当点击下单时若用户未登陆则需要注册/登陆后下单。

项目架构

数据模型

DAO/Service/Controller模型

项目细节

  • 使用配置mybatis自动生成器来生成文件,在mybatis-generator.xml配置文件中在对应生成表类名配置中加入 enableCountByExample="false"enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"selectByExampleQueryId="false" 避免生成不常用方法。
  • 前端ajax调用接口获取验证码 html/getotp.html,出现跨域请求问题 解决方法:@CrossOrigin(origins = {"*"}, allowCredentials = "true") allowedHeaders允许前端将 token 放入 header 做 session 共享的跨域请求。allowCredentials 授信后,需前端也设置 xhfFields 授信才能实现跨域 session 共享。 xhrFields: {withCredentials: true}
  • 统一前端返回格式CommonReturnType {status: xx ,object:xx}dataobject -> 与数据库对应的映射对象; model -> 用于业务逻辑service的领域模型对象; viewobject -> 用于前端交互的模型对象。
  • 使用 hibernate-validator 通过注解来完成模型参数校验。
  • insertSelective 中设置 keyProperty="id" useGeneratedKeys="true" 使得插入完后的DO生成自增id。insertSelective与insert区别:insertSelective对应的sql语句加入了NULL校验,即只会插入数据不为null的字段值(null的字段依赖于数据库字段默认值)insert则会插入所有字段,会插入null。
  • 数据库设计规范,设计时字段要设置为not null,并设置默认值,避免唯一索引在null情况下失效等类似场景。
  • 使用聚合模型在itemModel加入PromoModel. PromoModel,若不为空表示其有未结束的秒杀活动;在orderModel中加入promoId,若不为空,则以秒杀方式下单。

部署流程

数据库部署

  • 使用AWS RDS工具直接方便部署MySQL数据库。图片存放在AWS S3中,图片链接存放在RDS的商品信息表中。

水平扩展

  • Nginx部署前端静态资源。用户通过nginx/html/resources访问前端静态页面。而Ajax请求则会通过Nginx反向代理到三台不同的应用服务器。
  • 三台EC2部署后端项目打成的jar包。使用./deploy.sh &即可在后台启动,使用tail -f nohup.out即可查看项目启动、运行的信息。
  • 基于Token实现分布式会话。用UUID生成登录凭证token,然后将生成的token作为KEY,UserModel作为VALUE存入到Redis服务器。

三级缓存

一级缓存:

OpenResty对Nginx进行了扩展,集成了lua开发环境。使用OpenResty的Shared dict,把压力转移到了Nginx服务器,后面两个Tomcat服务器压力减小。同时减少了与后面两个Tomcat服务器、Redis服务器和数据库服务器的网络I/O,当网络I/O成为瓶颈时,Shared dict提供了优化的方法。

二级缓存:

在Redis的前面再添加一层“本地热点”缓存,使用了Google的Guava Cache方案利用本地JVM的内存存放多次查询的数据。Guava Cache除了线程安全外,还可以控制超时时间,提供淘汰机制。

三级缓存:

修改ItemController.getItem接口,先从Redis服务器获取,若没有,则从数据库查询并存到Redis服务。有的话直接用。

接口规范

登陆

POST /login

请求体

参数名 类型 描述
telephone string 用户名
password string 密码

请求示例

{  
    "telephone": "robot",  
    "password": "robot"
}

响应示例

200 OK {   
    "access_token": "xxx"
    }

异常示例

用户名不存在或者密码错误: 403 Forbidden

{  
    "code": "USER_AUTH_FAIL",  
    "message": "用户名或密码错误"
}

注册

POST /register

请求体

参数名 类型 描述
telephone string 用户名
password string 密码
code string 验证码
gender int 性别
name string 姓名

请求示例

POST /register
{  
    "telephone": "robot",	
    “otpCode”:”12345”,	
    “name”:”robot”,	
    “gender”:1,  
    "password": "robot"
}

响应示例

200 OK{ null}

异常示例

短信验证码不匹配:

403 Forbidden
{  
    "code": "USER_AUTH_FAIL",  
    "message": "Registration Failed! 用户名或密码错误"
 }

商品列表

get /listitem

请求示例

get/listitem

响应示例

200 OK
[  
    {    
        description: "by Erin French",
        id: 8,
        imgUrl: "https://miaoshas3.s3.amazonaws.com/item_img/id_8.jpg",
        price: 69.99,
        promoId: 9,
        promoPrice: 12.99,
        promoStatus: 1,
        sales: 897,
        startDate: "2021-04-23 10:03:00",
        stock: 454,
        title: "FINDING FREEDOM"
      }
      {
        description: "by Judy Batalion",
        id: 11,
        imgUrl: "https://miaoshas3.s3.amazonaws.com/item_img/id_11.jpg",
        price: 99.87,
        promoId: null,
        promoPrice: null,
        promoStatus: 0,
        sales: 6580,
        startDate: null,
        stock: 52,
        title: "THE LIGHT OF DAYS"
      }
 ]

商品详情

GET /getitem

请求示例:

GET /item/get?id=1

响应示例

{
    description: "by Cynthia D'Aprix Sweeney",
    id: 6,
    imgUrl: "https://miaoshas3.s3.amazonaws.com/item_img/id_6.jpg",
    price: 19.88,
    promoId: 7,
    promoPrice: 10.99,
    promoStatus: 2,
    sales: 600,
    startDate: "2021-04-21 10:53:00",
    stock: 7324,
    title: "GOOD COMPANY"
}

下单

POST /createorder

请求体

参数名 类型 描述
item_id string 商品id
amount int 下单数量(1)
promoId string 促销活动id

请求示例

POST "/order/createorder?token="+token,
{ 
    "itemId":”1”, 
    "amount":1, 
    "promoId":”2”
}

响应示例

200 OK
{  
    null
}

需求文档

优惠券/秒杀

页面 - siqi
注册/登陆 修改
主页面:领取商品 - 只有一种商品 - 脚本 - 点击跳转 - 登陆 - 领取优惠券 - 跳转商品购买 修改
领取优惠券 - 只有一种优惠券 - 脚本 新写

数据库 -

rds:

coupon - 一种,用户 (一一对应)
user - coupon column
product - 图片地址,描述 - 存储在另外服务器,属性里保存链接
orders- 结算历史记录

后端

springboot 框架管理 Mybatis|JPA

中间件

redis - 管理队列|数据缓存