Skip to content
Yizzuide edited this page Nov 3, 2020 · 10 revisions

Instructions(模块说明)

The Pillar provide various solutions to the if/else split problem. it can be apply in both pure java and Spring MVC.

Pillar模块提供了各种用于拆分if/else嵌套地狱的问题,可以应用在纯Java环境或Spring MVC。

Dependencies(依赖)

<dependency>
  <groupId>com.github.yizzuide</groupId>
  <artifactId>milkomeda-spring-boot-starter</artifactId>
  <version>${milkomeda-last-version}</version>
</dependency>

Example of using entry point dispatcher(节点派发案例)

1. Enable with annotation(启用模块)

@EnablePillar
@SpringBootApplication
public class MilkomedaDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(MilkomedaDemoApplication.class, args);
    }
}

2. Define entry point(定义入口节点)

// Add `@PillarEntryHandler` for handle entry point, the tag `market` can be using arbitrary business name.
// 添加`@PillarEntryHandler`用于处理节点派发,`market`的tag名可以是任意的业务名。
@PillarEntryHandler(tag = "market")
@Component
public class MarketServiceImpl implements MarketService {

    @PillarEntryPoint(code = "api.v1.check")
    public String check(Map<String, Object> params) {
        log.info("check: {}", params);
        return "OK";
    }

    @PillarEntryPoint(code = "api.v1.push")
    public String push(Map<String, Object> params) {
        log.info("push: {}", params);
        return "OK";
    }
}

3. Dispatch in request method(在请求方法里使用)

    @RequestMapping("market/api/{method}")
    public String handleCallback(@RequestParam Map<String, Object> params, @PathVariable("method") String code) {
        // The first param "market" is corresponds to the business name above,second param "code" is corresponds to the entry point above.
        // 第一个参数“market”对应上面的业务名(business name),第二个参数“code”对应上面的入口点(entry point)。
        return PillarEntryDispatcher.dispatch("market", code, params);
    }

Example of using execution path (执行分流案例)

1. Define types(定义类型)

The interface PillarType map identifier for key and pillarType name for value.

PillarType接口绑定了identifier标识符和pillarType路径名。

@Getter
@AllArgsConstructor
public enum TradeType implements PillarType {
    PAY(1, "PAY"),
    RECHARGE(2, "RECHARGE"),
    ;

    private final Integer type;
    private final String typeName;


    @Override
    public Object identifier() {
        return type;
    }

    @Override
    public String pillarType() {
        return typeName;
    }
}

2. Config Executor(配置执行器)

The Pillar<P, R> is a branch of a different business path which P is in parameter,R is out result, the PillarExecutor is path executor.

Pillar<P, R>是是一个不同业务路径分支,其中的P表示入参,R表示结果数据,PillarExecutor为路径执行器。

@Configuration
public class PillarConfig {

    // Auto inject Pillar type component
    @Autowired
    private List<Pillar<Map<String, String>, ReturnData>> pillars;

    @Bean
    public PillarExecutor<Map<String, String>, ReturnData> pillarExecutor() {
        PillarExecutor<Map<String, String>, ReturnData> pillarExecutor = new PillarExecutor<>();
        pillarExecutor.addPillarList(pillars);
        return pillarExecutor;
    }
}

3. Register pillar components(注册Pillar组件)

@Component
public class PayPillar implements Pillar<Map<String, String>, ReturnData> {
    @Override
    public String supportType() {
        // return current pillar type name in this hook method
        // 返回勾方法需要的pillarType路径名
        return TradeType.PAY.getTypeName();
    }
    @Override
    public void process(Map<String, String> params, ReturnData result) {
        log.info("invoke for pay:{}", params);
        // Some bussiness code.. 
        // Add response data
        result.setCode("200");
        result.setSuccess(true);
    }
}

@Component
public class RechargePillar implements Pillar<Map<String, String>, ReturnData> {
    @Override
    public String supportType() {
        return TradeType.RECHARGE.getTypeName();
    }
    @Override
    public void process(Map<String, String> params, ReturnData result) {
        log.info("invoke for recharge:{}", params);
        // Some bussiness code.. 
        // Add response data
        result.setCode("200");
        result.setSuccess(true);
    }
}

4. Usage(开始使用)

    @Autowired
    private PillarExecutor<Map<String, String>, ReturnData> pillarExecutor;

    @RequestMapping("bankcardPrepay")
    public ResponseEntity<ReturnData> bankcardPrepay(@RequestParam Map<String, String> params) {
        // Get pillar identifier
        // 获取标识符
        String type = params.get("type");
        // Get pillar type name from pillar identifier
        // 通过标识符从类型映射中解析出路径名
        String pillarType = PillarRecognizer.typeOf(TradeType.values(), type);

        ReturnData returnData = new ReturnData();
        if (pillarType == null) {
            returnData.setCode("400");
            returnData.setSuccess(false);
            returnData.setMsg("type param error");
            return ResponseEntity.ok(returnData);
        }

        // Execute pillar type path
        // 执行业务路径分流
        pillarExecutor.execute(pillarType, params, returnData);

        return ResponseEntity.ok(returnData);
    }

Example of state machine (状态机使用案例)

1. Define state(定义状态)

public enum MarketCallbackState implements PillarState {
    approveFeedback(0) {
        @Override
        public Map<String, Object> buildParams(Map<String, Object> data) {
          // build and return params map...
        }
    },
    orderFeedback(2) {
        @Override
        public Map<String, Object> buildParams(Map<String, Object> data) {
          // build and return params map...
        }
    };
    
    private final int state;

    MarketCallbackState(int state) {
        this.state = state;
    }

    @Override
    public String getState() {
        return String.valueOf(state);
    }

    public abstract Map<String, Object> buildParams(Map<String, Object> data);
}

2. Usage(开始使用)

    Map<String, Object> data = new HashMap<>();
    // The method `getDynamicType` is example of get from data source, such as mysql.
    // 方法`getDynamicType`是从数据源获取记录type,比如: mysql。
    // Add business data...
    Map<String, Object> params = PillarState.of(String.valueOf(getDynamicType()), MarketCallbackState.class, 
        MarketCallbackState.values()).buildParams(data);