在上篇文章 中我们介绍了项目的整体内容以及架构,本文就开始实现一个单体的版本,在之后的文章中,在使用springcloud相关组件将这个单体的版本一步步的拆分为微服务的版本,在开始之前再贴下组件图:
本文我们分别来实现这四个组件。
源码 。
定义服务请求和相应需要用到的公共的beans,单独定义的好处是,如果需要用到的话,单独引用即可,不需要引入其他不需要的类。
首先来定义优惠券类型的枚举:
@Getter
@AllArgsConstructor
public enum CouponType {
UNKNOWN("unknown", "0"),
MONEY_OFF("满减券", "1"),
DISCOUNT("打折", "2"),
RANDOM_DISCOUNT("随机减", "3"),
LONELY_NIGHT_MONEY_OFF("晚间双倍优惠券", "4");
private String description;
// 存在数据库里的最终code
private String code;
public static CouponType convert(String code) {
// .orElse(UNKNOWN) 避免有人使坏
return Stream.of(values())
.filter(bean -> bean.code.equalsIgnoreCase(code))
.findFirst()
.orElse(UNKNOWN);
}
}
然后定义优惠券模板类:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CouponTemplateInfo {
private Long id;
@NotNull
private String name;
// 优惠券描述
@NotNull
private String desc;
// 优惠券类型
@NotNull
private String type;
// 适用门店 - 若无则为全店通用券
private Long shopId;
/** 优惠券规则 */
@NotNull
private TemplateRule rule;
private Boolean available;
}
优惠券类:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CouponInfo {
private Long id;
private Long templateId;
private Long userId;
private Long shopId;
private Integer status;
private CouponTemplateInfo template;
}
具体的参考源码。
采用spring data jpa 约定由于配置,提高生产力!
。dao继承JpaRepositry,拥有基础的增删改查功能:
/**
* coupon_template 表的spring data jpa(构建在hibernate之上的db操作框架)接口
* https://blog.csdn.net/wang0907/article/details/131550318
*/
public interface CouponTemplateDao
extends JpaRepository<CouponTemplate, Long> {
// 根据Shop ID查询出所有券模板
List<CouponTemplate> findAllByShopId(Long shopId);
// IN查询 + 分页支持的语法
Page<CouponTemplate> findAllByIdIn(List<Long> Id, Pageable page);
// 根据shop ID + 可用状态查询店铺有多少券模板
Integer countByShopIdAndAvailable(Long shopId, Boolean available);
// 将优惠券设置为不可用
@Modifying
@Query("update CouponTemplate c set c.available = 0 where c.id = :id")
int makeCouponUnavailable(@Param("id") Long id);
}
定义模板模块对外的接口:
@Slf4j
@RestController
@RequestMapping("/template")
public class CouponTemplateController {
@Autowired
private CouponTemplateService couponTemplateService;
// 创建优惠券
@PostMapping("/addTemplate")
public CouponTemplateInfo addTemplate(@Valid @RequestBody CouponTemplateInfo request) {
log.info("Create coupon template: data={}", request);
return couponTemplateService.createTemplate(request);
}
...
}
定义其他模块可能用到的pojo,具体参考源码。
具体计算模块,定义各种优惠券的计算服务,主要的技术点是采用了模板方法设计模式 ,类图如下:
具体参考源码。
json:
{"products":[{"price":3000,"count":2,"shopId":3},{"price":1000,"count":4,"shopId":1}],"couponId":10,"couponInfos":[{"id":10,"templateId":2,"userId":null,"shopId":null,"template":{"name":"单店满减","desc":"满40减5","type":"1","available":true,"shopId":1,"rule":{"limitation":10,"discount":{"quota":500,"threshold":4000}}}}],"userId":1}
在pom中需要引入template和calculator,这样我们就有了一个三合一的单体应用
了(后面我们来一起改造它!!!)
。
定义用到的pojo,具体看源码。
具体看源码。
定义接口,服务层代码,定义用户领券,删除券等操作,如下用户领券代码:
@PostMapping("requestCoupon")
public Coupon requestCoupon(@Valid @RequestBody RequestCoupon request) {
return customerService.requestCoupon(request);
}
启动后测试领券
:
{
"userId": 1,
"couponTemplateId": 2
}
{
"products": [
{
"price": 3000,
"count": 2,
"shopId": 3
},
{
"price": 1000,
"count": 10,
"shopId": 1
}
],
"couponIDs": [
1
],
"userId": 1
}
这样我们的一个单体应用
就完成了,掌声!!!