小型支付商城系统笔记
前言
来吧,来库库干
DDD(domain-driven design)
领域驱动设计
比如先用mvc设计一个登录校验功能
- 创建用户实体,存储用户名密码
- Controller层调用Service层
- Service层中调用Mapper层,并完成校验的业务逻辑
- 返回结果,这就写完了
而DDD设计,会把校验的逻辑直接内聚在用户实体类中,这个实体类就叫做领域对象
所以DDD是会把一些逻辑下沉在领域对象中
聚合根
- 场景:用户和地址关联
- 传统方式:在service中分别管理用户和地址
- DDD方式,将User作为聚合根,控制地址的增删改(地址的增删改内聚在用户实体中)
领域服务 和 应用服务
- 领域服务:处理跨多个实体的业务逻辑(比如转账涉及两个账户,扣款逻辑内聚在账户实体中)
- 应用服务:协调流程(比如调用领域服务+发送消息)
领域事件(Domain Events)
- 用事件显示表达业务变化
- 例:用户注册成功后触发UserRegisteredEvent
1
2
3
4
5
6public class User {
public void register() {
// .. 注册逻辑
this.events.add(new UserRegisteredEvent(this.id)); // 添加事件
}
}
| 维度 | 传统开发 | DDD |
|---|---|---|
| 业务逻辑 | 散落在Service、Util、Controller | 内聚在领域实体/领域服务中 |
| 模型作用 | 数据载体(贫血模型) | 携带行为的业务模型(充血模型) |
| 技术实现驱动 | 数据库表驱动设计 | 业务需求驱动表结构设计 |
修改功能的时候
- 传统开发:影响Service,Util等
- DDD开发:只影响领域实体类,其他类不变
拉取项目
Redisson、MySQL、MyBatis的依赖一开始没有引入数据库可以先关上
gitcode推送
克隆之后,提交并推送到自己的仓库
账号是@后面的那个,密码要用访问令牌,右上角头像的下拉菜单里创建
然后远程分支要改成自己的
克隆是直接克隆的最新的那个仓库,不是历史分支,还是下载压缩包吧
公众号配置
用natapp或者cpolar进行内网穿透
natapp的域名要自己买一个才能绑定
启动natapp可以用指令,也可以把命令放在bat里面
微信测试网址
域名后面跟后端的接口地址域名加接口
token也是自己指定的
网站用微信扫码登录的流程
【登录的调用流程】
首先,由用户发起登录操作。让WEB页面从服务端获取登录凭证。
之后,前端页面拿到登录凭证后,可以使用 Ticket 从公众号服务平台换取二维码。
最后,用户扫码登录。扫码后,服务端会接收到来自公众号的回调消息,服务端再把回调消息中的 openid【用户唯一标识】和 ticket 进行绑定。这个时候你也可以创建出 jwt token 反馈给前端,作为登录成功的存储信息,后续校验 jwt token 就可以了。
【登录要点】
通过微信公众号平台提供的 API 接口,做微信公众号扫码登录。
扫码登录主要是需要微信公众号平台,提供一个生成带参的二维码,让用户使用微信扫描二维码登录。扫码后我们在微信公众号对接的接口中会接收到扫码完成消息,里面就会含带二维码参数,这样就可以知道到是谁扫描的二维码。我们把扫描后解析的信息和用户做绑定,也就可以完成登录操作了。
- 网站打开二维码的页面,此时二维码未生成,网站先向微信的服务器发请求
- 微信服务器收到请求之后生成并返回一个ticket,和二维码url,网站展示这个二维码,然后开始轮询登录状态
- 用户扫码,用户的手机解析出二维码中的ticket后,显示确认登录按钮,点击后手机中的微信就自动将用户的openid和这个ticket发送给微信服务器
这一步后微信就知道了是哪个用户在登录哪个网站了,网站也未拿到到用户信息 - 微信收到后验证成功就将openid发给网站,网站就相当于拿ticket换了用户openid,生成自己的的登录凭证,完成登录
Retrofit
Retrofit 是一个类型安全的 HTTP 客户端框架,它让你通过定义带注解的 Java 接口,自动将方法调用转换为 HTTP 请求,并将响应 JSON 自动解析为 Java 对象。
它解决了什么问题?
- 手动拼 URL、参数、Header → ❌ 繁琐易错
- 手动解析 JSON → ❌ 容易 NPE、类型混乱
- 重复写 HttpClient 代码 → ❌ 样板代码多
- 所以调用微信api的时候都走的Retrofit
Retrofit的使用流程
定义响应数据类型
1 | |
定义契约接口
1 | |
- @GET(“cgi-bin/token”) → 拼接到 base URL 后
- @Query(“appid”) → 自动变成 URL 查询参数 ?appid=xxx,很方便
创建实例并调用
实际使用可以配置config把retrofit注册到spring容器中
就可以省下这个第一步的代码,其他类直接注入retrofit实例就行
1 | |
支付宝支付
首先,用户在系统中创建订单(流水单),创建过程中需要判断是否存在未支付订单,存在则可以直接返回。另外还有一种可能,创建的订单存在,但没有支付单,也就是【掉单】。这是因为本身的业务系统和外部的支付创建(支付宝)不是一个事务,不能一起成功或失败,所以要做一些流程的校验。比如我们创建订单成功,但创建支付单失败。这个之后用户继续创建订单,就会优先使用这笔订单创建支付单。如果流程中没有存在的掉单,则直接创建支付单即可。
之后,创建完支付宝订单,会由页面跳转到网络收银台,引导用户完成支付操作。
最后,就是接收支付回调消息,更新本地的订单状态,以及推动后续流程。比如;发放商品、驱动物流、虚拟支付等。当然在实际的商城中,还会有逆向流程,比如商品有问题,或者用户主动发起退单。这个时候就要走逆向流程,退单、审核、退款流程。你可以尝试完成。
支付宝沙箱
支付宝|开放平台
用第一页配置环境,需要内网穿透
用第二页的沙箱账号来测试
DDD改造
| MVC | DDD |
|---|---|
| web模块中的Controller接口 | trigger模块中的Controller |
| common模块中的通用工具类 | types模块中的skd.weixin |
| Resource下的mybatis文件夹和yml配置文件 | app模块 |
| domain模块中存放的实体类 | infrastructure(基础建设)模块中的gateway的dto |
| service模块中的实现类 | domain模块中的service |
| service模块中的接口 | infrastructure模块中的gateway |