文章目录
概要
需求分析以及接口设计
这里要查询的是发放中的,并且领取方式是手动领取的优惠券。这就是一个简单的带条件的批量查询接口。因此按照Restful风格来设计即可,我们要分析的核心就是请求参数和返回值类型。
之前也说过,这里的查询条件包含两个:
-
发放中的优惠券
-
领取方式是手动领取的
不过这都是一些状态信息,不需要前端传递,我们自己在业务中判断即可。也就是说这个查询是无参的。
返回值首先肯定是优惠券集合,而优惠券数据就相对复杂一些,结合页面原型可以发现首先是一些基本字段:
-
优惠券id:领取的时候使用
-
优惠券名称
-
优惠的详细信息,包含四个字段:
-
优惠的折扣类型
-
优惠门槛
-
优惠值
-
最大优惠值
-
-
是否限定了范围
-
有效期的结束时间:页面写的是有效期至xxx,也就是说不关心有效期的开始时间,只关心结束时间
-
有效天数:券的使用有效期有两种方式,一种是到期时间;一种是固定天数,也就是自领取之日起算起。
OK,优惠券的基本信息就这么多。但是这里有一些隐含的内容在原型中没有显示出来:大家思考一下,如果这个优惠券我点击过立即领取,并且领取成功以后,页面该如何显示?
难道还是显示立即领取吗?这显然不行,一般优惠券领取完后应该显示为立即使用,提醒用户赶紧去买东西。
另外,如果这个券全部领完了呢?还展示立即领取吗?显然不行,这种应该显示为已领完。
因此,我们应该在返回值中标示优惠券的这些状态:
-
是否可以领取:也就是优惠券还有剩余并且用户已领取数量未超过限领数量。如果为false,展示为已抢完
-
是否已经领取:也就是用户是否有已经领取,尚未使用的券。如果有,则显示为去使用
如果以上都不成立,则展示为立即领取
综上,结合Restful的风格,查询发放中的优惠券的接口规范如下:
技术细节
1.Controller层
@ApiOperation("查询发放中的优惠券列表")
@GetMapping("/list")
public List<CouponVO> queryIssuingCoupons(){
return couponService.queryIssuingCoupons();
}
2.Service层:
@Override
public List<CouponVO> queryIssuingCoupons() {
// 1.查询发放中的优惠券列表
List<Coupon> coupons = lambdaQuery()
.eq(Coupon::getStatus, ISSUING)
.eq(Coupon::getObtainWay, ObtainType.PUBLIC)
.list();
if (CollUtils.isEmpty(coupons)) {
return CollUtils.emptyList();
}
// 2.统计当前用户已经领取的优惠券的信息
List<Long> couponIds = coupons.stream().map(Coupon::getId).collect(Collectors.toList());
// 2.1.查询当前用户已经领取的优惠券的数据
List<UserCoupon> userCoupons = userCouponService.lambdaQuery()
.eq(UserCoupon::getUserId, UserContext.getUser())
.in(UserCoupon::getCouponId, couponIds)
.list();
// 2.2.统计当前用户对优惠券的已经领取数量
Map<Long, Long> issuedMap = userCoupons.stream()
.collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));
// 2.3.统计当前用户对优惠券的已经领取并且未使用的数量
Map<Long, Long> unusedMap = userCoupons.stream()
.filter(uc -> uc.getStatus() == UserCouponStatus.UNUSED)
.collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));
// 3.封装VO结果
List<CouponVO> list = new ArrayList<>(coupons.size());
for (Coupon c : coupons) {
// 3.1.拷贝PO属性到VO
CouponVO vo = BeanUtils.copyBean(c, CouponVO.class);
list.add(vo);
// 3.2.是否可以领取:已经被领取的数量 < 优惠券总数量 && 当前用户已经领取的数量 < 每人限领数量
vo.setAvailable(
c.getIssueNum() < c.getTotalNum()
&& issuedMap.getOrDefault(c.getId(), 0L) < c.getUserLimit()
);
// 3.3.是否可以使用:当前用户已经领取并且未使用的优惠券数量 > 0
vo.setReceived(unusedMap.getOrDefault(c.getId(), 0L) > 0);
}
return list;
}