日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【代码示例】springboot使用drools实现动态规划

發布時間:2024/9/30 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【代码示例】springboot使用drools实现动态规划 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 實體類
  • service
  • Drools配置
  • 規則文件
  • controller
  • 改進:實現動態規劃


要求:不同的貨物重量有不同的金額,需要根據重量計算金額,且修改規則后動態寫入到數據庫中

實體類

AddressRule

/*** 封裝計算訂單價格所需的參數*/ public class AddressRule {/*** 貨品總重量*/private double totalWeight;/*** 距離*/private double distance;/*** 續重價格*/private double continuedFee;/*** 首重*/private double firstWeight;/*** 首重價格*/private double firstFee;public double getFirstFee() {return firstFee;}public void setFirstFee(double firstFee) {this.firstFee = firstFee;}public double getFirstWeight() {return firstWeight;}public void setFirstWeight(double firstWeight) {this.firstWeight = firstWeight;}public double getTotalWeight() {return totalWeight;}public void setTotalWeight(double totalWeight) {this.totalWeight = totalWeight;}public double getDistance() {return distance;}public void setDistance(double distance) {this.distance = distance;}public double getContinuedFee() {return continuedFee;}public void setContinuedFee(double continuedFee) {this.continuedFee = continuedFee;} }

AddressCheckResult

/*** 封裝訂單價格計算后的結果*/ public class AddressCheckResult {private boolean postCodeResult = false; // true:通過校驗;false:未通過校驗private String result;public String getResult() {return result;}public void setResult(String result) {this.result = result;}public boolean isPostCodeResult() {return postCodeResult;}public void setPostCodeResult(boolean postCodeResult) {this.postCodeResult = postCodeResult;} }

service

public interface DroolsRulesService {/*** 根據條件計算訂單價格* @param addressRule* @return*/String calcFee(AddressRule addressRule); } public class DroolsRulesServiceImpl implements DroolsRulesService {/*** 根據條件計算訂單價格* @param addressRule* @return*/@Overridepublic String calcFee(AddressRule addressRule) {//貨物總重量BigDecimal totalWeight = new BigDecimal(addressRule.getTotalWeight());//首重BigDecimal firstWeight = new BigDecimal(addressRule.getFirstWeight());//首重價格BigDecimal firstFee = new BigDecimal(addressRule.getFirstFee());//續重價格BigDecimal continuedFee = new BigDecimal((addressRule.getContinuedFee()));//超過首重部分重量=總重量-首重BigDecimal lost = totalWeight.subtract(firstWeight);//3.5//只保留整數部分lost = lost.setScale(0,BigDecimal.ROUND_DOWN);return continuedFee.multiply(lost).add(firstFee).toString();} //這個main函數是用來測試的public static void main(String[] args) {AddressRule addressRule = new AddressRule();addressRule.setTotalWeight(10.3);addressRule.setFirstWeight(1);addressRule.setFirstFee(20);addressRule.setContinuedFee(6);String s = new DroolsRulesServiceImpl().calcFee(addressRule);System.out.println(s);} }

Drools配置

@Configuration public class DroolsAutoConfiguration {private static final String RULES_PATH = "rules/";@Bean@ConditionalOnMissingBean(KieFileSystem.class)public KieFileSystem kieFileSystem() throws IOException {KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();for (Resource file : getRuleFiles()) {kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));}return kieFileSystem;}private Resource[] getRuleFiles() throws IOException {ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");}@Bean@ConditionalOnMissingBean(KieContainer.class)public KieContainer kieContainer() throws IOException {final KieRepository kieRepository = getKieServices().getRepository();kieRepository.addKieModule(new KieModule() {@Overridepublic ReleaseId getReleaseId() {return kieRepository.getDefaultReleaseId();}});KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());kieBuilder.buildAll();KieContainer kieContainer=getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());return kieContainer;}private KieServices getKieServices() {return KieServices.Factory.get();}@Bean@ConditionalOnMissingBean(KieBase.class)public KieBase kieBase() throws IOException {return kieContainer().getKieBase();}@Bean@ConditionalOnMissingBean(KieSession.class)public KieSession kieSession() throws IOException {return kieContainer().newKieSession();}@Bean@ConditionalOnMissingBean(KModuleBeanFactoryPostProcessor.class)public KModuleBeanFactoryPostProcessor kiePostProcessor() {return new KModuleBeanFactoryPostProcessor();} }

規則文件

在rule包下寫規則文件:

package rules;import com.itheima.pinda.entity.fact.AddressRule import com.itheima.pinda.entity.fact.AddressCheckResult import com.itheima.pinda.service.DroolsRulesService import com.itheima.pinda.service.impl.DroolsRulesServiceImpldialect "java"rule "1千克以內20元"activation-group "mygroup"salience 10whenaddressRule : AddressRule(totalWeight != null && totalWeight <= 1.00)checkResult : AddressCheckResult()thencheckResult.setPostCodeResult(true);checkResult.setResult("20");System.out.println("1千克以內20元"); endrule "1千克以上,訂單距離在200公里以下的,首重1千克,首重價格20元,續重每1千克資費為6元"activation-group "mygroup"salience 9whenaddressRule : AddressRule(totalWeight != null && totalWeight > 1.00 && distance <= 200.00)checkResult : AddressCheckResult()thenaddressRule.setFirstFee(20.00);addressRule.setFirstWeight(1.00);addressRule.setContinuedFee(6.00);DroolsRulesService droolsRulesService = new DroolsRulesServiceImpl();String orderAmount = droolsRulesService.calcFee(addressRule);checkResult.setPostCodeResult(true);checkResult.setResult(orderAmount);System.out.println("1千克以上,訂單距離在200公里以下的,首重1千克,首重價格20元,續重每1千克資費為6元"); endrule "1千克以上,訂單距離在200~500公里的,首重1千克,首重價格20元,續重每1千克資費為9元"activation-group "mygroup"salience 8whenaddressRule : AddressRule(totalWeight != null && totalWeight > 1.00 && distance <= 500.00)checkResult : AddressCheckResult()thenaddressRule.setFirstFee(20.00);addressRule.setFirstWeight(1.00);addressRule.setContinuedFee(9.00);DroolsRulesService droolsRulesService = new DroolsRulesServiceImpl();String orderAmount = droolsRulesService.calcFee(addressRule);checkResult.setPostCodeResult(true);checkResult.setResult(orderAmount);System.out.println("1千克以上,訂單距離在200~500公里的,首重1千克,首重價格20元,續重每1千克資費為9元"); endrule "1千克以上,訂單距離在500公里以上的,首重1千克,首重價格20元,續重每1千克資費為15元"activation-group "mygroup"salience 7whenaddressRule : AddressRule(totalWeight != null && totalWeight > 1.00 && distance > 500.00)checkResult : AddressCheckResult()thenaddressRule.setFirstFee(20.00);addressRule.setFirstWeight(1.00);addressRule.setContinuedFee(15.00);DroolsRulesService droolsRulesService = new DroolsRulesServiceImpl();String orderAmount = droolsRulesService.calcFee(addressRule);checkResult.setPostCodeResult(true);checkResult.setResult(orderAmount);System.out.println("1千克以上,訂單距離在500公里以上的,首重1千克,首重價格20元,續重每1千克資費為15元"); end

controller

/*** 新增訂單** @param orderDTO 訂單信息* @return 訂單信息*/@PostMapping("")public OrderDTO save(@RequestBody OrderDTO orderDTO, HttpServletResponse res) {log.info("保存訂單信息:{}", JSON.toJSONString(orderDTO));Order order = new Order();order.setEstimatedArrivalTime(LocalDateTime.now().plus(2, ChronoUnit.DAYS));Map map = orderService.calculateAmount(orderDTO);log.info("實時計算運費:{}", map);orderDTO = (OrderDTO) map.get("orderDto");BeanUtils.copyProperties(orderDTO, order);if ("send error msg".equals(orderDTO.getSenderAddress()) || "receive error msg".equals(orderDTO.getReceiverAddress())) {return orderDTO;}order.setAmount(new BigDecimal(map.getOrDefault("amount", "23").toString()));orderService.saveOrder(order);log.info("訂單信息入庫:{}", order);OrderDTO result = new OrderDTO();BeanUtils.copyProperties(order, result);return result;}

orderService.calculateAmount方法:

/*** 計算訂單價格* @param orderDTO* @return*/@Overridepublic Map calculateAmount(OrderDTO orderDTO) {//計算訂單距離orderDTO = this.getDistance(orderDTO);if("sender error msg".equals(orderDTO.getSenderAddress()) || "receiver error msg".equals(orderDTO.getReceiverAddress())){//地址解析失敗,直接返回Map map = new HashMap();map.put("amount","0");map.put("errorMsg","無法計算訂單距離和訂單價格,請輸入真實地址");map.put("orderDto",orderDTO);return map;}KieSession session = KieContainer.newKieSession();//ReloadDroolsRulesService.kieContainer.newKieSession();//設置Fact對象AddressRule addressRule = new AddressRule();addressRule.setTotalWeight(orderDTO.getOrderCargoDto().getTotalWeight().doubleValue());addressRule.setDistance(orderDTO.getDistance().doubleValue());//將對象加入到工作內存session.insert(addressRule);AddressCheckResult addressCheckResult = new AddressCheckResult();session.insert(addressCheckResult);int i = session.fireAllRules();System.out.println("觸發了" + i + "條規則");session.destroy();if(addressCheckResult.isPostCodeResult()){System.out.println("規則匹配成功,訂單價格為:" + addressCheckResult.getResult());orderDTO.setAmount(new BigDecimal(addressCheckResult.getResult()));Map map = new HashMap();map.put("orderDto",orderDTO);map.put("amount",addressCheckResult.getResult());return map;}return null;}/*** 調用百度地圖服務接口,根據寄件人地址和收件人地址計算訂單距離* @param orderDTO* @return*/public OrderDTO getDistance(OrderDTO orderDTO){//調用百度地圖服務接口獲取寄件人地址對應的坐標經緯度String begin = BaiduMapUtils.getCoordinate(orderDTO.getSenderAddress());if(begin == null){orderDTO.setSenderAddress("sender error msg");return orderDTO;}//調用百度地圖服務接口獲取收件人地址對應的坐標經緯度String end = BaiduMapUtils.getCoordinate(orderDTO.getReceiverAddress());if(end == null){orderDTO.setReceiverAddress("receiver error msg");return orderDTO;}Double distance = BaiduMapUtils.getDistance(begin, end);DecimalFormat decimalFormat = new DecimalFormat("#.##");String distanceStr = decimalFormat.format(distance/1000);orderDTO.setDistance(new BigDecimal(distanceStr));return orderDTO;}

改進:實現動態規劃

思路:
1、將規則文件的內容存儲在數據庫中

2、Drools相關對象(例如KieContainer對象)的創建都基于數據庫中存儲的規則來創建

3、提供HTTP訪問接口,當規則發生變化時調用此接口重新加載數據庫中的規則,重新創建KieContainer等對象
第一步:在pd_oms數據庫中創建數據表rule,用于存儲規則內容

CREATE TABLE `rule` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`create_time` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`last_modify_time` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`rule_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,`version` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,PRIMARY KEY (`id`) USING BTREE,UNIQUE INDEX `UK_9yepjak9olg92holwkr8p3l0f`(`rule_key`) USING BTREE,UNIQUE INDEX `UK_ilmbp99kyt6gy10224pc9bl6n`(`version`) USING BTREE,UNIQUE INDEX `UK_ei48upwykmhx9r5p7p4ndxvgn`(`last_modify_time`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

第二步:創建Rule實體類,和上面的rule表對應

package com.itheima.pinda.entity; ? import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; import lombok.experimental.Accessors; import java.io.Serializable; ? @Data @ToString @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @TableName("rule") @ApiModel public class Rule implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "id", type = IdType.INPUT)private Long id;private String ruleKey;private String content;private String version;private String lastModifyTime;private String createTime; }

第三步:創建RuleMapper接口

package com.itheima.pinda.mapper; ? import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.itheima.pinda.entity.Order; import com.itheima.pinda.entity.Rule; import org.apache.ibatis.annotations.Mapper; ? /*** 規則*/ @Mapper public interface RuleMapper extends BaseMapper<Rule> { }

第四步:創建ReloadDroolsRulesService,用于重新加載數據庫中的規則

package com.itheima.pinda.service.impl; ? import com.itheima.pinda.entity.Address; import com.itheima.pinda.entity.Rule; import com.itheima.pinda.mapper.RuleMapper; import org.kie.api.KieServices; import org.kie.api.builder.KieBuilder; import org.kie.api.builder.KieFileSystem; import org.kie.api.builder.KieRepository; import org.kie.api.builder.Message; import org.kie.api.runtime.KieContainer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; ? /***重新加載規則*/ @Service public class ReloadDroolsRulesService {public static KieContainer kieContainer; ?@Autowiredprivate RuleMapper ruleMapper; ?public void reload() {KieContainer kieContainer = loadContainerFromString(loadRules());this.kieContainer = kieContainer;} ?private List<Rule> loadRules() {List<Rule> rules = ruleMapper.selectList(null);return rules;} ?public KieContainer loadContainerFromString(List<Rule> rules) {long startTime = System.currentTimeMillis();KieServices ks = KieServices.Factory.get();KieRepository kr = ks.getRepository();KieFileSystem kfs = ks.newKieFileSystem(); ?for (Rule rule : rules) {String drl = rule.getContent();kfs.write("src/main/resources/" + drl.hashCode() + ".drl", drl);} ?KieBuilder kb = ks.newKieBuilder(kfs); ?kb.buildAll();if (kb.getResults().hasMessages(Message.Level.ERROR)) {throw new RuntimeException("Build Errors:\n" + kb.getResults().toString());}long endTime = System.currentTimeMillis();System.out.println("Time to build rules : " + (endTime - startTime) + " ms");startTime = System.currentTimeMillis();KieContainer kContainer = ks.newKieContainer(kr.getDefaultReleaseId());endTime = System.currentTimeMillis();System.out.println("Time to load container: " + (endTime - startTime) + " ms");return kContainer;} }

第五步:創建CommandLineRunnerImpl,在項目啟動時加載數據庫中最新規則

package com.itheima.pinda.service.impl; ? import com.itheima.pinda.service.ReloadDroolsRulesService; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; import javax.annotation.Resource; ? /*** 項目啟動時加載最新規則**/ @Component @Slf4j public class CommandLineRunnerImpl implements CommandLineRunner {@Resourceprivate ReloadDroolsRulesService rules; ?@Overridepublic void run(String... args) throws Exception {rules.reload();} }

第六步:創建RulesReloadController

package com.itheima.pinda.controller; ? import com.itheima.pinda.service.ReloadDroolsRulesService; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.Resource; import java.io.IOException; ? @RequestMapping("/rules") @Controller public class RulesReloadController {@Resourceprivate ReloadDroolsRulesService rules; ?/*** 從數據庫加載最新規則** @return* @throws IOException*/@ResponseBody@RequestMapping("/reload")public String reload() throws IOException {rules.reload();return "ok";} }

第七步:注釋掉DroolsAutoConfiguration上面的configuration注解

第八步:修改OrderServiceImpl的calculateAmount方法,修改KieSession的獲取方式
KieSession session = KieContainer.newKieSession();
改為
KieSession session = ReloadDroolsRulesService.kieContainer.newKieSession();

總結

以上是生活随笔為你收集整理的【代码示例】springboot使用drools实现动态规划的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。