benchmark中增加liteflow-benchmark-common-example

This commit is contained in:
everywhere.z
2025-09-04 17:09:59 +08:00
parent 5d265abd63
commit 09e3dcf6a6
31 changed files with 1712 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>liteflow-benchmark</artifactId>
<groupId>com.yomahub</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>liteflow-benchmark-common-example</artifactId>
<dependencies>
<dependency>
<groupId>com.yomahub</groupId>
<artifactId>liteflow-script-javax-pro</artifactId>
<version>${revision}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,64 @@
package com.yomahub.liteflow.benchmark;
import cn.hutool.core.io.resource.ResourceUtil;
import com.yomahub.liteflow.benchmark.bean.PriceCalcReqVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.util.JsonUtil;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import java.util.concurrent.TimeUnit;
@State(Scope.Benchmark)
@EnableAutoConfiguration
@PropertySource(value = "classpath:application.properties")
@ComponentScan("com.yomahub.liteflow.benchmark.cmp")
public class CommonExampleBenchmark {
private ConfigurableApplicationContext applicationContext;
private FlowExecutor flowExecutor;
private PriceCalcReqVO req;
@Setup
public void setup() {
applicationContext = SpringApplication.run(CommonExampleBenchmark.class);
flowExecutor = applicationContext.getBean(FlowExecutor.class);
req = JsonUtil.parseObject(ResourceUtil.readUtf8Str("reqData.json"), PriceCalcReqVO.class);
}
@TearDown
public void tearDown() {
applicationContext.close();
}
@Benchmark
public void test1(){
flowExecutor.execute2Resp("mainChain", req, PriceContext.class);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(CommonExampleBenchmark.class.getSimpleName())
.mode(Mode.Throughput)
.warmupIterations(1)//预热次数
.measurementIterations(3)//执行次数
.measurementTime(new TimeValue(10, TimeUnit.SECONDS))//每次执行多少时间
.threads(100)//多少个线程
.forks(1)//多少个进程
.timeUnit(TimeUnit.SECONDS)
.build();
new Runner(opt).run();
}
}

View File

@@ -0,0 +1,37 @@
package com.yomahub.liteflow.benchmark;
import cn.hutool.core.io.resource.ResourceUtil;
import com.yomahub.liteflow.benchmark.bean.PriceCalcReqVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import com.yomahub.liteflow.util.JsonUtil;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import javax.annotation.Resource;
@ExtendWith(SpringExtension.class)
@TestPropertySource(value = "classpath:application.properties")
@SpringBootTest(classes = CommonExampleTest.class)
@EnableAutoConfiguration
@ComponentScan({ "com.yomahub.liteflow.benchmark.cmp" })
public class CommonExampleTest {
@Resource
private FlowExecutor flowExecutor;
@Test
public void test1() throws Exception {
PriceCalcReqVO req = JsonUtil.parseObject(ResourceUtil.readUtf8Str("reqData.json"), PriceCalcReqVO.class);
LiteflowResponse response = flowExecutor.execute2Resp("mainChain", req, PriceContext.class);
if (!response.isSuccess()){
throw response.getCause();
}
}
}

View File

@@ -0,0 +1,96 @@
package com.yomahub.liteflow.benchmark.bean;
import com.yomahub.liteflow.benchmark.enums.OrderChannelEnum;
import java.util.List;
public class PriceCalcReqVO {
private Long id;
/**
* 订单号
*/
private String orderNo;
/**
* 是否境外购
*/
private boolean oversea;
/**
* 商品包
*/
private List<ProductPackVO> productPackList;
/**
* 订单渠道
*/
private OrderChannelEnum orderChannel;
/**
* 会员CODE
*/
private String memberCode;
/**
* 优惠券ID
*/
private Long couponId;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public List<ProductPackVO> getProductPackList() {
return productPackList;
}
public void setProductPackList(List<ProductPackVO> productPackList) {
this.productPackList = productPackList;
}
public OrderChannelEnum getOrderChannel() {
return orderChannel;
}
public void setOrderChannel(OrderChannelEnum orderChannel) {
this.orderChannel = orderChannel;
}
public String getMemberCode() {
return memberCode;
}
public void setMemberCode(String memberCode) {
this.memberCode = memberCode;
}
public Long getCouponId() {
return couponId;
}
public void setCouponId(Long couponId) {
this.couponId = couponId;
}
public boolean isOversea() {
return oversea;
}
public void setOversea(boolean oversea) {
this.oversea = oversea;
}
}

View File

@@ -0,0 +1,95 @@
package com.yomahub.liteflow.benchmark.bean;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import java.math.BigDecimal;
public class PriceStepVO {
/**
* 价格类型
*/
private PriceTypeEnum priceType;
/**
* 价格类型关联id
*/
private String extId;
/**
* 上一步的订单总价格
*/
private BigDecimal prePrice;
/**
* 价格的变动值
*/
private BigDecimal priceChange;
/**
* 这步价格计算后的订单总价格
*/
private BigDecimal currPrice;
/**
* 价格步骤描述
*/
private String stepDesc;
public PriceStepVO(PriceTypeEnum priceType, String extId, BigDecimal prePrice, BigDecimal priceChange, BigDecimal currPrice, String stepDesc) {
this.priceType = priceType;
this.extId = extId;
this.prePrice = prePrice;
this.priceChange = priceChange;
this.currPrice = currPrice;
this.stepDesc = stepDesc;
}
public PriceTypeEnum getPriceType() {
return priceType;
}
public void setPriceType(PriceTypeEnum priceType) {
this.priceType = priceType;
}
public String getExtId() {
return extId;
}
public void setExtId(String extId) {
this.extId = extId;
}
public BigDecimal getPrePrice() {
return prePrice;
}
public void setPrePrice(BigDecimal prePrice) {
this.prePrice = prePrice;
}
public BigDecimal getPriceChange() {
return priceChange;
}
public void setPriceChange(BigDecimal priceChange) {
this.priceChange = priceChange;
}
public BigDecimal getCurrPrice() {
return currPrice;
}
public void setCurrPrice(BigDecimal currPrice) {
this.currPrice = currPrice;
}
public String getStepDesc() {
return stepDesc;
}
public void setStepDesc(String stepDesc) {
this.stepDesc = stepDesc;
}
}

View File

@@ -0,0 +1,163 @@
package com.yomahub.liteflow.benchmark.bean;
import com.yomahub.liteflow.benchmark.enums.CategoryEnum;
import com.yomahub.liteflow.benchmark.enums.SkuSourceEnum;
import java.math.BigDecimal;
import java.util.List;
public class ProductPackVO {
/**
* 这里注意下product和sku的关系一个商品可能有很多规格比如Product是"NIKE运动鞋"SKU就是"NIKE运动鞋黑色40码"
*/
/**
* 商品ID
*/
private Long productId;
/**
* 商品CODE
*/
private String productCode;
/**
* SKU ID
*/
private Long skuId;
/**
* SKU CODE
*/
private String skuCode;
/**
* SKU名称
*/
private String skuName;
/**
* 商品来源
*/
private SkuSourceEnum skuSource;
/**
* 类目
*/
private CategoryEnum category;
/**
* 售价
*/
private BigDecimal salePrice;
/**
* 数量
*/
private Integer count;
/**
* 优惠信息,一个商品可能有多个优惠信息
*/
private List<PromotionInfoVO> promotionList;
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public String getProductCode() {
return productCode;
}
public void setProductCode(String productCode) {
this.productCode = productCode;
}
public Long getSkuId() {
return skuId;
}
public void setSkuId(Long skuId) {
this.skuId = skuId;
}
public String getSkuCode() {
return skuCode;
}
public void setSkuCode(String skuCode) {
this.skuCode = skuCode;
}
public String getSkuName() {
return skuName;
}
public void setSkuName(String skuName) {
this.skuName = skuName;
}
public SkuSourceEnum getSkuSource() {
return skuSource;
}
public void setSkuSource(SkuSourceEnum skuSource) {
this.skuSource = skuSource;
}
public BigDecimal getSalePrice() {
return salePrice;
}
public void setSalePrice(BigDecimal salePrice) {
this.salePrice = salePrice;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public CategoryEnum getCategory() {
return category;
}
public void setCategory(CategoryEnum category) {
this.category = category;
}
public List<PromotionInfoVO> getPromotionList() {
return promotionList;
}
public void setPromotionList(List<PromotionInfoVO> promotionList) {
this.promotionList = promotionList;
}
@Override
public boolean equals(Object obj) {
if (obj == null){
return false;
}else{
if(getClass() != obj.getClass()){
return false;
}else{
if(((ProductPackVO)obj).getSkuId().equals(this.getSkuId())){
return true;
}else{
return false;
}
}
}
}
}

View File

@@ -0,0 +1,68 @@
package com.yomahub.liteflow.benchmark.bean;
import com.yomahub.liteflow.benchmark.enums.PromotionTypeEnum;
public class PromotionInfoVO {
/**
* id
*/
private Long id;
/**
* 优惠CODE
*/
private String promotionCode;
/**
* 优惠名称
*/
private String promotionName;
/**
* 优惠类型
*/
private PromotionTypeEnum promotionType;
public PromotionInfoVO() {
}
public PromotionInfoVO(Long id, String promotionCode, String promotionName, PromotionTypeEnum promotionType) {
this.id = id;
this.promotionCode = promotionCode;
this.promotionName = promotionName;
this.promotionType = promotionType;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPromotionCode() {
return promotionCode;
}
public void setPromotionCode(String promotionCode) {
this.promotionCode = promotionCode;
}
public String getPromotionName() {
return promotionName;
}
public void setPromotionName(String promotionName) {
this.promotionName = promotionName;
}
public PromotionTypeEnum getPromotionType() {
return promotionType;
}
public void setPromotionType(PromotionTypeEnum promotionType) {
this.promotionType = promotionType;
}
}

View File

@@ -0,0 +1,37 @@
package com.yomahub.liteflow.benchmark.bean;
import java.util.List;
public class PromotionPackVO extends PromotionInfoVO{
/**
* 这个优惠活动关联的商品包
*/
private List<ProductPackVO> relatedProductPackList;
public List<ProductPackVO> getRelatedProductPackList() {
return relatedProductPackList;
}
public void setRelatedProductPackList(List<ProductPackVO> relatedProductPackList) {
this.relatedProductPackList = relatedProductPackList;
}
@Override
public boolean equals(Object obj) {
if (obj == null){
return false;
}else{
if(getClass() != obj.getClass()){
return false;
}else{
if(((PromotionPackVO)obj).getId().equals(this.getId())){
return true;
}else{
return false;
}
}
}
}
}

View File

@@ -0,0 +1,44 @@
package com.yomahub.liteflow.benchmark.cmp;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* 优惠券抵扣计算组件
*/
@Component("couponCmp")
public class CouponCmp extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
/**这里Mock下根据couponId取到的优惠卷面值为15元**/
Long couponId = context.getCouponId();
BigDecimal couponPrice = new BigDecimal(15);
BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice();
BigDecimal currPrice = prePrice.subtract(couponPrice);
context.addPriceStep(new PriceStepVO(PriceTypeEnum.COUPON_DISCOUNT,
couponId.toString(),
prePrice,
currPrice.subtract(prePrice),
currPrice,
PriceTypeEnum.COUPON_DISCOUNT.getName()));
}
@Override
public boolean isAccess() {
PriceContext context = this.getContextBean(PriceContext.class);
if(context.getCouponId() != null){
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,78 @@
package com.yomahub.liteflow.benchmark.cmp;
import cn.hutool.core.collection.CollectionUtil;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.bean.ProductPackVO;
import com.yomahub.liteflow.benchmark.bean.PromotionPackVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import com.yomahub.liteflow.benchmark.enums.PromotionTypeEnum;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;
/**
* 满减计算组件
*/
@Component("fullCutCmp")
public class FullCutCmp extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext slot = this.getContextBean(PriceContext.class);
PromotionPackVO promotionPack = getMatchPromotion();
/***这里Mock下根据优惠信息查到的满减信息为满100减5块***/
BigDecimal triggerPrice = new BigDecimal(100);
BigDecimal cutPrice = new BigDecimal(5);
//从PromotionPack对象中取到这个优惠关联的商品信息判断是否超过了触发满减的金额
BigDecimal reletedProductTotalPrice = new BigDecimal(0);
for(ProductPackVO productPack : promotionPack.getRelatedProductPackList()){
reletedProductTotalPrice = reletedProductTotalPrice.add(productPack.getSalePrice().multiply(new BigDecimal(productPack.getCount())));
}
if (reletedProductTotalPrice.compareTo(triggerPrice) >= 0){
BigDecimal prePrice = slot.getLastestPriceStep().getCurrPrice();
BigDecimal currPrice = prePrice.subtract(cutPrice);
slot.addPriceStep(new PriceStepVO(PriceTypeEnum.PROMOTION_DISCOUNT,
promotionPack.getId().toString(),
prePrice,
currPrice.subtract(prePrice),
currPrice,
PriceTypeEnum.PROMOTION_DISCOUNT.getName() + "[满减]"));
}
}
@Override
public boolean isAccess() {
//过滤出优惠信息列表中有没有满减这个活动,如果有,则进入这个组件,反义就不进入
PromotionPackVO promotionPack = getMatchPromotion();
if(promotionPack != null){
return true;
}else{
return false;
}
}
private PromotionPackVO getMatchPromotion(){
PriceContext context = this.getContextBean(PriceContext.class);
List<PromotionPackVO> matchList = context.getPromotionPackList().stream().filter(promotionPackVO -> {
if(promotionPackVO.getPromotionType().equals(PromotionTypeEnum.FULL_CUT)){
return true;
}else{
return false;
}
}).collect(Collectors.toList());
if(CollectionUtil.isNotEmpty(matchList)){
return matchList.get(0);
}else{
return null;
}
}
}

View File

@@ -0,0 +1,79 @@
package com.yomahub.liteflow.benchmark.cmp;
import cn.hutool.core.collection.CollectionUtil;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.bean.ProductPackVO;
import com.yomahub.liteflow.benchmark.bean.PromotionPackVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import com.yomahub.liteflow.benchmark.enums.PromotionTypeEnum;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.stream.Collectors;
/**
* 满折计算组件
*/
@Component("fullDiscountCmp")
public class FullDiscountCmp extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
PromotionPackVO promotionPack = getMatchPromotion();
/***这里Mock下根据优惠信息查到的满折信息为满200打9折***/
BigDecimal triggerPrice = new BigDecimal(200);
BigDecimal discountRate = new BigDecimal("0.9");
//从PromotionPack对象中取到这个优惠关联的商品信息判断是否超过了触发满折的金额
BigDecimal reletedProductTotalPrice = new BigDecimal(0);
for(ProductPackVO productPack : promotionPack.getRelatedProductPackList()){
reletedProductTotalPrice = reletedProductTotalPrice.add(productPack.getSalePrice().multiply(new BigDecimal(productPack.getCount())));
}
if (reletedProductTotalPrice.compareTo(triggerPrice) >= 0){
BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice();
BigDecimal currPrice = prePrice.multiply(discountRate).setScale(2, RoundingMode.HALF_UP);
context.addPriceStep(new PriceStepVO(PriceTypeEnum.PROMOTION_DISCOUNT,
promotionPack.getId().toString(),
prePrice,
currPrice.subtract(prePrice),
currPrice,
PriceTypeEnum.PROMOTION_DISCOUNT.getName() + "[满折]"));
}
}
@Override
public boolean isAccess() {
//过滤出优惠信息列表中有没有满折这个活动,如果有,则进入这个组件,反义就不进入
PromotionPackVO promotionPack = getMatchPromotion();
if(promotionPack != null){
return true;
}else{
return false;
}
}
private PromotionPackVO getMatchPromotion(){
PriceContext context = this.getContextBean(PriceContext.class);
List<PromotionPackVO> matchList = context.getPromotionPackList().stream().filter(promotionPackVO -> {
if(promotionPackVO.getPromotionType().equals(PromotionTypeEnum.FULL_DISCOUNT)){
return true;
}else{
return false;
}
}).collect(Collectors.toList());
if(CollectionUtil.isNotEmpty(matchList)){
return matchList.get(0);
}else{
return null;
}
}
}

View File

@@ -0,0 +1,78 @@
package com.yomahub.liteflow.benchmark.cmp;
import cn.hutool.core.collection.CollectionUtil;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.annotation.LiteflowMethod;
import com.yomahub.liteflow.benchmark.bean.PriceCalcReqVO;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.bean.ProductPackVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
import java.math.BigDecimal;
import java.util.List;
@LiteflowComponent
public class InitCmps {
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "checkCmp")
public void processCheckCmp(NodeComponent bindCmp){
//拿到请求参数
PriceCalcReqVO req = bindCmp.getRequestData();
//参数验证完成
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "slotInitCmp")
public void processSlotInitCmp(NodeComponent bindCmp){
//把主要参数冗余到slot里
PriceCalcReqVO req = bindCmp.getRequestData();
PriceContext context = bindCmp.getContextBean(PriceContext.class);
context.setOrderNo(req.getOrderNo());
context.setOversea(req.isOversea());
context.setMemberCode(req.getMemberCode());
context.setOrderChannel(req.getOrderChannel());
context.setProductPackList(req.getProductPackList());
context.setCouponId(req.getCouponId());
}
@LiteflowMethod(value = LiteFlowMethodEnum.IS_ACCESS, nodeId = "slotInitCmp")
public boolean accessSlotInitCmp(NodeComponent bindCmp){
PriceCalcReqVO req = bindCmp.getRequestData();
if(req != null){
return true;
}else{
return false;
}
}
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "priceStepInitCmp")
public void processPriceStepInitCmp(NodeComponent bindCmp){
PriceContext context = bindCmp.getContextBean(PriceContext.class);
//初始化价格步骤
List<ProductPackVO> packList = context.getProductPackList();
BigDecimal totalOriginalPrice = new BigDecimal(0);
for(ProductPackVO packItem : packList){
totalOriginalPrice = totalOriginalPrice.add(packItem.getSalePrice().multiply(new BigDecimal(packItem.getCount())));
}
context.addPriceStep(new PriceStepVO(PriceTypeEnum.ORIGINAL,
null,
null,
totalOriginalPrice,
totalOriginalPrice,
PriceTypeEnum.ORIGINAL.getName()));
context.setOriginalOrderPrice(totalOriginalPrice);
}
@LiteflowMethod(value = LiteFlowMethodEnum.IS_ACCESS, nodeId = "priceStepInitCmp")
public boolean accessPriceStepInitCmp(NodeComponent bindCmp){
PriceContext context = bindCmp.getContextBean(PriceContext.class);
if(CollectionUtil.isNotEmpty(context.getProductPackList())){
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,51 @@
package com.yomahub.liteflow.benchmark.cmp;
import cn.hutool.core.collection.CollectionUtil;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import com.yomahub.liteflow.core.NodeComponent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 会员折扣计算组件
*/
@Component("memberDiscountCmp")
public class MemberDiscountCmp extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
String memberCode = context.getMemberCode();
/***这里Mock下通过memberCode去查会员等级表然后获取的会员折扣为9折的代码***/
BigDecimal memberDiscount = new BigDecimal("0.9");
//进行计算会员折扣
BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice();
BigDecimal currPrice = prePrice.multiply(memberDiscount).setScale(2, RoundingMode.HALF_UP);
//加入到价格步骤中
context.addPriceStep(new PriceStepVO(PriceTypeEnum.MEMBER_DISCOUNT,
memberCode,
prePrice,
currPrice.subtract(prePrice),
currPrice,
PriceTypeEnum.MEMBER_DISCOUNT.getName()));
}
@Override
public boolean isAccess() {
PriceContext context = this.getContextBean(PriceContext.class);
if(CollectionUtil.isNotEmpty(context.getProductPackList())
&& StringUtils.isNotBlank(context.getMemberCode())){
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,32 @@
package com.yomahub.liteflow.benchmark.cmp;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* 境外购运费计算组件
*/
@Component("overseaPostageCmp")
public class OverseaPostageCmp extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
/**这里Mock境外购运费的策略是不管多少钱都要加上15元运费**/
BigDecimal postage = new BigDecimal(15);
BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice();
BigDecimal currPrice = prePrice.add(postage);
context.addPriceStep(new PriceStepVO(PriceTypeEnum.OVERSEAS_POSTAGE,
null,
prePrice,
currPrice.subtract(prePrice),
currPrice,
PriceTypeEnum.OVERSEAS_POSTAGE.getName()));
}
}

View File

@@ -0,0 +1,47 @@
package com.yomahub.liteflow.benchmark.cmp;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* 国内运费计算组件
*/
@Component("postageCmp")
public class PostageCmp extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
/**这里Mock运费的策略是满99免运费不满99需要10块钱运费**/
BigDecimal triggerPrice = new BigDecimal(99);
BigDecimal postage = new BigDecimal(10);
//先把运费加上去
BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice();
BigDecimal currPrice = prePrice.add(postage);
context.addPriceStep(new PriceStepVO(PriceTypeEnum.POSTAGE,
null,
prePrice,
currPrice.subtract(prePrice),
currPrice,
PriceTypeEnum.POSTAGE.getName()));
//判断运费是否满99了满了99就去掉运费
if(prePrice.compareTo(triggerPrice) >= 0){
prePrice = context.getLastestPriceStep().getCurrPrice();
currPrice = currPrice.subtract(postage);
context.addPriceStep(new PriceStepVO(PriceTypeEnum.POSTAGE_FREE,
null,
prePrice,
currPrice.subtract(prePrice),
currPrice,
PriceTypeEnum.POSTAGE_FREE.getName()));
}
}
}

View File

@@ -0,0 +1,23 @@
package com.yomahub.liteflow.benchmark.cmp;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.core.NodeSwitchComponent;
import org.springframework.stereotype.Component;
/**
* 运费条件组件
*/
@Component("postageCondCmp")
public class PostageCondCmp extends NodeSwitchComponent {
@Override
public String processSwitch() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
//根据参数oversea来判断是否境外购转到相应的组件
boolean oversea = context.isOversea();
if(oversea){
return "overseaPostageCmp";
}else{
return "postageCmp";
}
}
}

View File

@@ -0,0 +1,36 @@
package com.yomahub.liteflow.benchmark.cmp;
import cn.hutool.core.collection.CollectionUtil;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* 订单最终价格计算器
*/
@Component("priceResultCmp")
public class PriceResultCmp extends NodeComponent {
@Override
public void process() throws Exception {
//算出订单最后的价格因为priceChange有正负所以这里统一加起来
PriceContext context = this.getContextBean(PriceContext.class);
BigDecimal finalPrice = new BigDecimal(0);
for(PriceStepVO step : context.getPriceStepList()){
finalPrice = finalPrice.add(step.getPriceChange());
}
context.setFinalOrderPrice(finalPrice);
}
@Override
public boolean isAccess() {
PriceContext context = this.getContextBean(PriceContext.class);
if(CollectionUtil.isNotEmpty(context.getPriceStepList())){
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,61 @@
package com.yomahub.liteflow.benchmark.cmp;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import com.yomahub.liteflow.benchmark.bean.ProductPackVO;
import com.yomahub.liteflow.benchmark.bean.PromotionInfoVO;
import com.yomahub.liteflow.benchmark.bean.PromotionPackVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* 把商品包的优惠信息转换成以优惠信息为主要维度的对象,以便于后面优惠信息的计算
*/
@Component("promotionConvertCmp")
public class PromotionConvertCmp extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
List<PromotionPackVO> promotionPackList = new ArrayList<>();
PromotionPackVO promotionPack = null;
for(ProductPackVO pack : context.getProductPackList()){
if(CollectionUtil.isEmpty(pack.getPromotionList())){
continue;
}
for(PromotionInfoVO promotion : pack.getPromotionList()){
promotionPack = new PromotionPackVO();
promotionPack.setId(promotion.getId());
if(promotionPackList.contains(promotionPack)){
promotionPack = promotionPackList.get(promotionPackList.indexOf(promotionPack));
if(promotionPack.getRelatedProductPackList().contains(pack)){
continue;
}else{
promotionPack.getRelatedProductPackList().add(pack);
}
}else{
BeanUtils.copyProperties(promotion,promotionPack);
promotionPack.setRelatedProductPackList(ListUtil.toList(pack));
promotionPackList.add(promotionPack);
}
}
}
context.setPromotionPackList(promotionPackList);
}
@Override
public boolean isAccess() {
PriceContext context = this.getContextBean(PriceContext.class);
if(CollectionUtil.isNotEmpty(context.getProductPackList())){
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,81 @@
package com.yomahub.liteflow.benchmark.cmp;
import cn.hutool.core.collection.CollectionUtil;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.bean.ProductPackVO;
import com.yomahub.liteflow.benchmark.bean.PromotionPackVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import com.yomahub.liteflow.benchmark.enums.PromotionTypeEnum;
import com.yomahub.liteflow.core.NodeComponent;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.stream.Collectors;
/**
* 抢购计算组件
*/
@Component("rushBuyCmp")
public class RushBuyCmp extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
PromotionPackVO promotionPack = getMatchPromotion();
/**
* 这里Mock下根据优惠信息查到的抢购信息为1块钱抢购
* 这里要注意的是,实际情况下,这个抢购活动所关联的商品,每个商品的抢购价格都不同
* 这里为了Mock方便所关联的商品每个SKU抢购价都是1元
* ps:抢购原则上和其他优惠活动互斥,这里就不写出互斥的逻辑了,在设置参数时请注意
**/
BigDecimal rushBuyPrice = new BigDecimal(1);
BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice();
BigDecimal rushBuyDiscountPrice = new BigDecimal(0);
for(ProductPackVO productPack : promotionPack.getRelatedProductPackList()){
rushBuyDiscountPrice = rushBuyDiscountPrice.add(productPack.getSalePrice().subtract(rushBuyPrice)
.multiply(new BigDecimal(productPack.getCount()))).setScale(2, RoundingMode.HALF_UP);
}
BigDecimal currPrice = prePrice.subtract(rushBuyDiscountPrice);
context.addPriceStep(new PriceStepVO(PriceTypeEnum.PROMOTION_DISCOUNT,
promotionPack.getId().toString(),
prePrice,
currPrice.subtract(prePrice),
currPrice,
PriceTypeEnum.PROMOTION_DISCOUNT.getName() + "[抢购]"));
}
@Override
public boolean isAccess() {
//过滤出优惠信息列表中有没有抢购这个活动,如果有,则进入这个组件,反义就不进入
PromotionPackVO promotionPack = getMatchPromotion();
if(promotionPack != null){
return true;
}else{
return false;
}
}
private PromotionPackVO getMatchPromotion(){
PriceContext context = this.getContextBean(PriceContext.class);
List<PromotionPackVO> matchList = context.getPromotionPackList().stream().filter(promotionPackVO -> {
if(promotionPackVO.getPromotionType().equals(PromotionTypeEnum.RUSH_BUY)){
return true;
}else{
return false;
}
}).collect(Collectors.toList());
if(CollectionUtil.isNotEmpty(matchList)){
return matchList.get(0);
}else{
return null;
}
}
}

View File

@@ -0,0 +1,60 @@
package com.yomahub.liteflow.benchmark.cmp;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.bean.ProductPackVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.log.LFLog;
import com.yomahub.liteflow.log.LFLoggerManager;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.MessageFormat;
/**
* 步骤日志生成组件
*/
@Component("stepPrintCmp")
public class StepPrintCmp extends NodeComponent {
private LFLog log = LFLoggerManager.getLogger(getClass());
@Override
public void process() throws Exception {
PriceContext context = this.getContextBean(PriceContext.class);
StringBuilder logStr = new StringBuilder();
logStr.append(MessageFormat.format("订单号[{0}]的价格计算的明细结果:\n", context.getOrderNo()));
logStr.append("|====================================================================\n");
for(ProductPackVO pack : context.getProductPackList()){
logStr.append(MessageFormat.format("| {0} [{1}] [{2}] {3} X {4}\n",
pack.getSkuName(),
pack.getProductCode(),
pack.getSkuCode(),
pack.getSalePrice().setScale(2, RoundingMode.HALF_UP).toString(),
pack.getCount()));
}
logStr.append("|====================================================================\n");
for(PriceStepVO step : context.getPriceStepList()){
logStr.append(MessageFormat.format("| [{0} : {1}]\n",step.getStepDesc(),step.getPriceChange().setScale(2, BigDecimal.ROUND_HALF_UP).toString()));
}
logStr.append(MessageFormat.format("| [最终价 : {0}]\n",context.getFinalOrderPrice().setScale(2, BigDecimal.ROUND_HALF_UP).toString()));
logStr.append("|====================================================================\n");
log.info(logStr.toString());
context.setPrintLog(logStr.toString());
}
@Override
public boolean isAccess() {
PriceContext context = this.getContextBean(PriceContext.class);
if(CollectionUtils.isNotEmpty(context.getPriceStepList())){
return true;
}else{
return false;
}
}
}

View File

@@ -0,0 +1,169 @@
package com.yomahub.liteflow.benchmark.context;
import cn.hutool.core.collection.CollectionUtil;
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.bean.ProductPackVO;
import com.yomahub.liteflow.benchmark.bean.PromotionPackVO;
import com.yomahub.liteflow.benchmark.enums.OrderChannelEnum;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class PriceContext {
/**
* 订单号
*/
private String orderNo;
/**
* 是否境外购
*/
private boolean oversea;
/**
* 商品包
*/
private List<ProductPackVO> productPackList;
/**
* 订单渠道
*/
private OrderChannelEnum orderChannel;
/**
* 会员CODE
*/
private String memberCode;
/**
* 优惠券
*/
private Long couponId;
/**
* 优惠信息
*/
private List<PromotionPackVO> promotionPackList;
/**
* 价格步骤
*/
private List<PriceStepVO> priceStepList = new ArrayList<>();
/**
* 订单原始价格
*/
private BigDecimal originalOrderPrice;
/**
* 订单最终价格
*/
private BigDecimal finalOrderPrice;
/**
* 步骤日志
*/
private String printLog;
public PriceStepVO getLastestPriceStep(){
if(CollectionUtil.isEmpty(priceStepList)){
return null;
}else{
return priceStepList.get(priceStepList.size()-1);
}
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public List<ProductPackVO> getProductPackList() {
return productPackList;
}
public void setProductPackList(List<ProductPackVO> productPackList) {
this.productPackList = productPackList;
}
public OrderChannelEnum getOrderChannel() {
return orderChannel;
}
public void setOrderChannel(OrderChannelEnum orderChannel) {
this.orderChannel = orderChannel;
}
public String getMemberCode() {
return memberCode;
}
public void setMemberCode(String memberCode) {
this.memberCode = memberCode;
}
public Long getCouponId() {
return couponId;
}
public void setCouponId(Long couponId) {
this.couponId = couponId;
}
public List<PriceStepVO> getPriceStepList() {
return priceStepList;
}
public void setPriceStepList(List<PriceStepVO> priceStepList) {
this.priceStepList = priceStepList;
}
public void addPriceStep(PriceStepVO step){
this.priceStepList.add(step);
}
public List<PromotionPackVO> getPromotionPackList() {
return promotionPackList;
}
public void setPromotionPackList(List<PromotionPackVO> promotionPackList) {
this.promotionPackList = promotionPackList;
}
public boolean isOversea() {
return oversea;
}
public void setOversea(boolean oversea) {
this.oversea = oversea;
}
public BigDecimal getFinalOrderPrice() {
return finalOrderPrice;
}
public void setFinalOrderPrice(BigDecimal finalOrderPrice) {
this.finalOrderPrice = finalOrderPrice;
}
public BigDecimal getOriginalOrderPrice() {
return originalOrderPrice;
}
public void setOriginalOrderPrice(BigDecimal originalOrderPrice) {
this.originalOrderPrice = originalOrderPrice;
}
public String getPrintLog() {
return printLog;
}
public void setPrintLog(String printLog) {
this.printLog = printLog;
}
}

View File

@@ -0,0 +1,16 @@
package com.yomahub.liteflow.benchmark.enums;
public enum CategoryEnum {
FOOD(1,"食品"),
CLOTHES(2,"衣服"),
DAILY_USE(3,"生活用品");
private Integer id;
private String name;
CategoryEnum(int id, String name){
this.id = id;
this.name = name;
}
}

View File

@@ -0,0 +1,20 @@
package com.yomahub.liteflow.benchmark.enums;
public enum OrderChannelEnum {
APP(1,"APP渠道"),
MINI_PROGRAM(2,"小程序渠道"),
WX_H5(3,"微信H5"),
MOBILE_H5(4,"移动H5渠道"),
WEB_PORTAL(5,"PC主站渠道"),
OFFLINE_STORE(5,"线下门店渠道");
private Integer id;
private String name;
OrderChannelEnum(int id, String name){
this.id = id;
this.name = name;
}
}

View File

@@ -0,0 +1,28 @@
package com.yomahub.liteflow.benchmark.enums;
public enum PriceTypeEnum {
ORIGINAL(0, "原始价格"),
MEMBER_DISCOUNT(1, "会员折扣"),
PROMOTION_DISCOUNT(2, "促销优惠"),
COUPON_DISCOUNT(3, "优惠券抵扣"),
POSTAGE(4, "国内运费"),
OVERSEAS_POSTAGE(5, "海淘运费"),
POSTAGE_FREE(6, "实付99元免运费");
private Integer code;
private String name;
PriceTypeEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
public Integer getCode() {
return code;
}
public String getName(){
return name;
}
}

View File

@@ -0,0 +1,16 @@
package com.yomahub.liteflow.benchmark.enums;
public enum PromotionTypeEnum {
FULL_CUT(1, "满减"),
FULL_DISCOUNT(2, "满折"),
RUSH_BUY(3, "抢购");
private Integer id;
private String name;
PromotionTypeEnum(int id, String name){
this.id = id;
this.name = name;
}
}

View File

@@ -0,0 +1,27 @@
/**
* <p>Title: beast-price</p>
* <p>Description: 价格计算服务</p>
* <p>Copyright: Copyright (c) 2017</p>
* @author Bryan.Zhang
* @Date 2017-11-27
*/
package com.yomahub.liteflow.benchmark.enums;
/**
* 商品来源枚举
*/
public enum SkuSourceEnum {
RAW(0, "自购"),
GIFT(3, "买赠"),
ADDITION(4,"换购"),
BENEFIT(5,"权益商品");
private Integer code;
private String name;
SkuSourceEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
}

View File

@@ -0,0 +1,2 @@
liteflow.rule-source=flow*.xml
liteflow.print-execution-log=false

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE flow PUBLIC "liteflow" "https://liteflow.cc/liteflow.dtd">
<flow>
<nodes>
<node id="s_memberDiscountCmp" type="script" language="java">
<![CDATA[
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import com.yomahub.liteflow.core.NodeComponent;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Demo extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext context = this.getFirstContextBean();
String memberCode = context.getMemberCode();
/***这里Mock下通过memberCode去查会员等级表然后获取的会员折扣为9折的代码***/
BigDecimal memberDiscount = new BigDecimal("0.9");
//进行计算会员折扣
BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice();
BigDecimal currPrice = prePrice.multiply(memberDiscount).setScale(2, RoundingMode.HALF_UP);
//加入到价格步骤中
context.addPriceStep(new PriceStepVO(PriceTypeEnum.MEMBER_DISCOUNT,
memberCode,
prePrice,
currPrice.subtract(prePrice),
currPrice, PriceTypeEnum.MEMBER_DISCOUNT.getName()));
}
}
]]>
</node>
<node id="s_couponCmp" type="script" language="java">
<![CDATA[
import com.yomahub.liteflow.benchmark.bean.PriceStepVO;
import com.yomahub.liteflow.benchmark.context.PriceContext;
import com.yomahub.liteflow.benchmark.enums.PriceTypeEnum;
import com.yomahub.liteflow.core.NodeComponent;
import java.math.BigDecimal;
public class Demo extends NodeComponent {
@Override
public void process() throws Exception {
PriceContext context = this.getFirstContextBean();
/**这里Mock下根据couponId取到的优惠卷面值为15元**/
Long couponId = context.getCouponId();
BigDecimal couponPrice = new BigDecimal(15);
BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice();
BigDecimal currPrice = prePrice.subtract(couponPrice);
context.addPriceStep(new PriceStepVO(PriceTypeEnum.COUPON_DISCOUNT,
couponId.toString(),
prePrice,
currPrice.subtract(prePrice),
currPrice,
PriceTypeEnum.COUPON_DISCOUNT.getName()));
}
}
]]>
</node>
</nodes>
<chain name="mainChain">
THEN(
checkCmp, slotInitCmp, priceStepInitCmp,
promotionConvertCmp, s_memberDiscountCmp,
promotionChain, s_couponCmp,
SWITCH(postageCondCmp).to(postageCmp, overseaPostageCmp),
priceResultCmp, stepPrintCmp
);
</chain>
</flow>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="promotionChain">
THEN(fullCutCmp, fullDiscountCmp, rushBuyCmp);
</chain>
</flow>

View File

@@ -0,0 +1,91 @@
{
"couponId": 80081,
"memberCode": "M21152",
"orderChannel": "APP",
"orderNo": "SO2020070611120001",
"oversea": false,
"productPackList": [
{
"category": "CLOTHES",
"count": 2,
"productCode": "PD5001XC",
"productId": 5001,
"promotionList": [
{
"id": 1001,
"promotionCode": "PM1001",
"promotionName": "夏季满减活动",
"promotionType": "FULL_CUT"
},
{
"id": 1002,
"promotionCode": "PM1002",
"promotionName": "夏季满折活动",
"promotionType": "FULL_DISCOUNT"
}
],
"salePrice": 139,
"skuCode": "SKU5001XC001",
"skuId": 67001441,
"skuName": "夏季运动女式短裙M",
"skuSource": "RAW"
},
{
"category": "CLOTHES",
"count": 3,
"productCode": "PD6001XC",
"productId": 6001,
"promotionList": [
{
"id": 1001,
"promotionCode": "PM1001",
"promotionName": "夏季满减活动",
"promotionType": "FULL_CUT"
}
],
"salePrice": 59,
"skuCode": "SKU6001XC001",
"skuId": 67002334,
"skuName": "男士迷彩短袜均码",
"skuSource": "RAW"
},
{
"category": "DAILY_USE",
"count": 5,
"productCode": "PD8001XC",
"productId": 8001,
"promotionList": [
{
"id": 1002,
"promotionCode": "PM1002",
"promotionName": "夏季满折活动",
"promotionType": "FULL_DISCOUNT"
}
],
"salePrice": 28,
"skuCode": "SKU8001XC001",
"skuId": 87002001,
"skuName": "纯棉毛巾",
"skuSource": "RAW"
},
{
"category": "DAILY_USE",
"count": 2,
"productCode": "PD9001XC",
"productId": 9001,
"promotionList": [
{
"id": 1003,
"promotionCode": "PM1003",
"promotionName": "618抢购活动",
"promotionType": "RUSH_BUY"
}
],
"salePrice": 30,
"skuCode": "SKU9001XC001",
"skuId": 97552001,
"skuName": "杀菌护手凝胶",
"skuSource": "RAW"
}
]
}

View File

@@ -47,5 +47,6 @@
<module>liteflow-benchmark-script-java</module>
<module>liteflow-benchmark-script-groovy</module>
<module>liteflow-benchmark-common</module>
<module>liteflow-benchmark-common-example</module>
</modules>
</project>