Service接口的设计
之前我们写好了DAO层的接口,这里我们要开始着手编写业务层接口,然后编写业务层接口的实现类并编写业务层的核心逻辑。
设计业务层接口,应该站在 使用者 角度上设计,如我们应该做到:
- 1.定义业务方法的颗粒度要细。
- 2.方法的参数要明确简练,不建议使用类似Map这种类型,让使用者可以封装进Map中一堆参数而传递进来,尽量精确到哪些参数。
- 3.方法的return返回值,除了应该明确返回值类型,还应该指明方法执行可能产生的异常(RuntimeException),并应该手动封装一些通用的异常处理机制。
类比DAO层接口的定义,我这里先给出完整的 SeckillService.java 的定义(注意:在DAO层(Mapper)中我们定义了两个接口 SeckillMapper 和 SeckillOrderMapper ,但是Service层接口为1个):
public interface SeckillService { /** * 获取所有的秒杀商品列表 * * @return */ List<Seckill> findAll(); /** * 获取某一条商品秒杀信息 * * @param seckillId * @return */ Seckill findById(long seckillId); /** * 秒杀开始时输出暴露秒杀的地址 * 否者输出系统时间和秒杀时间 * * @param seckillId */ Exposer exportSeckillUrl(long seckillId); /** * 执行秒杀的操作 * * @param seckillId * @param userPhone * @param money * @param md5 */ SeckillExecution executeSeckill(long seckillId, BigDecimal money, long userPhone, String md5) throws SeckillException, RepeatKillException, SeckillCloseException; }
这里我将依次讲解一下为什么接口会这样设计?接口方法的返回值是怎样定义的?
findById和findAll方法
这两个方法就简单很多:
- findById(): 顾名思义根据ID主键查询。按照接口的设计我们需要指定参数是 seckillId (秒杀商品的ID值。注意:这里定义为 long 类型,不要定义为包装类类型,因为包装类类型不能直接进行大小比较,必须转换为基本类型才能进行值大小比较);返回值自然是查询到的商品表数据级 Seckill 实体类了。
- findAll(): 顾名思义是查询数据库中所有的秒杀商品表的数据,因为记录数不止一条,所以一般就用List集合接收,并制定泛型是 List<Seckill> ,表示从数据库中查询到的列表数据都是Seckill实体类对应的数据,并以Seckill实体类的结构将列表数据封装到List集合中。
exportSeckillUrl方法
exportSeckillUrl() 方法可有的讲了,他是 暴露接口 用到的方法,目的就是 获取秒杀商品抢购的地址 。
1.为什么要单独创建一个方法来获取秒杀地址?
在之前我们做的后端项目中,跳转到某个详情页一般都是:根据ID查询该详情数据,然后将页面跳转到详情页并将数据直接渲染到页面上。但是秒杀系统不同,它也不能就这样简单的定义,要知道秒杀技术的难点就是如何应对高并发?同一件商品,比如瞬间有十万的用户访问,而还存在各种黄牛,有各种工具去抢购这个商品,那么此时肯定不止10万的访问量的,并且开发者要尽量的保证每个用户抢购的公平性,也就是不能让一个用户抢购一堆数量的此商品。
这就是我们常说的 接口防刷 问题。因此单独定义一个获取秒杀接口的方法是有必要的。
2.如何做到接口防刷?
接口方法: Exposer exportSeckillUrl(long seckillId); 从参数列表中很易明白:就是根据该商品的ID获取到这个商品的秒杀url地址;但是返回值类型 Exposer 是什么呢?
思考一下如何做到 接口防刷?
- 首先要保证该商品处于秒杀状态。也就是1.秒杀开始时间要<当前时间;2.秒杀截止时间要>当前时间。
- 要保证一个用户只能抢购到一件该商品,应做到商品秒杀接口对应同一用户只能有唯一的一个URL秒杀地址,不同用户间秒杀地址应是不同的,且配合订单表 seckill_order 中 联合主键的配置实现。
针对上面的两条分析,我们给出 Exposer 的设计(要注意此类定义在 /dto/ 路径下表明此类是我们手动封装的结果属性,它类似JavaBean但又不属于,仅用来封装秒杀状态的结果,目的是提高代码的重用率):
此例源码请看ÿ