Easyrule是个规则引擎,类似于drools,我们来熟悉一下这个东西

  • [ ] 一个简单实例规则,这个规则会被一直触发,然后行为是打印helloWorld

    @Rule(name="helloWorld",description = "总是打印helloWorld")
    public class HelloWorldRule {
    @Condition
    public boolean when(){
    return true;
    } @Action
    public void then(){
    System.out.println("hello world");
    }
    }

      

    public class DemoLauncher {
    public static void main(String[] args) {
    Facts facts=new Facts();
    //规则集合定义并注册
    Rules rules=new Rules();
    rules.register(new HelloWorldRule()); //创建一个规则引擎,并驱动rules
    RulesEngine rulesEngine=new DefaultRulesEngine();
    //执行
    rulesEngine.fire(rules,facts);
    }
    } 
    日志打印:
  • hello world
  • 配上日志包,观察下框架的日志

    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'helloWorld', description = '总是打印helloWorld', priority = '2147483646'}
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'helloWorld' triggered
    [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'helloWorld' performed successfully
    hello world
    org.slf4j.simpleLogger.defaultLogLevel=debug
  • [ ] FizzBuzz : 数字从一到100 当能被5整除的时候发出fizz,被7整除时候发出buzz,同时被5和7整除就发出fizzbuzz

    1. java简单实现:循环然后用ifelse判断该怎么处理

      public class JavaDeme {
      public static void main(String[] args) {
      for(int i=0;i<100;i++){
      if(i%5==0&&i%7==0){
      System.out.println("fizzbuzz"+":"+i);
      }else if(i%5==0){
      System.out.println("fizz:"+i);
      }else if(i%7==0){
      System.out.println("buzz:"+i);
      }else{
      //System.out.println("啥也不是"+i);
      }
      // System.out.println();
      }
      }
      }
    2. easyrule实现先为每个规则写个rule

      • FizzRule

        @Rule
        public class FizzRule { @Condition
        public boolean isFizz(@Fact("number") Integer number) {
        return number % 5 == 0;
        } @Action
        public void printFizz() {
        System.out.print("fizz");
        }
        // 优先级为1
        @Priority
        public int getPriority() {
        return 1;
        }
        }
      • BuzzRule

        @Rule
        public classBuzzRule { @Condition
        public booleanisBuzz(@Fact("number") Integer number) {
        returnnumber % 7 == 0;
        } @Action
        public voidprintBuzz() {
        System.out.print("buzz");
        }
        //优先级2
        @Priority
        public intgetPriority() {
        return2;
        }
        }
      • FizzBuzzRule :BuzzRule,和FizzRule 整合的规则

        public class FizzBuzzRule extends UnitRuleGroup {
        public FizzBuzzRule(Object... rules){
        for(Object rule:rules){
        addRule(rule);
        }
        } @Override
        public int getPriority(){
        return 0;
        }
        }
      • 两个规则都不符合

        @Rule
        public class NonFizzBuzzRule {
        @Condition
        public boolean isNotFizzNorBuzz(@Fact("number") Integer number){
        // can return true, because this is the latest rule to trigger according to assigned priorities
        // and in which case, the number is not fizz nor buzz
        return number % 5 != 0 || number % 7 != 0;
        }
        @Action
        public void printInput(@Fact("number") Integer number) {
        System.out.print(number);
        } @Priority
        public int getPriority() {
        return 3;
        }
        }
      • 主方法入口:

        public class FizzBuzzWithEasyRules {
        public static void main(String[] args) {
        RulesEngineParameters parameters=new RulesEngineParameters();
        // 满足第一个规则就退出
        parameters.setSkipOnFirstAppliedRule(true); // 引擎
        RulesEngine rulesEngine=new DefaultRulesEngine();
        //RulesEngine rulesEngine=new DefaultRulesEngine(parameters); // 规则
        Rules rules=new Rules();
        rules.register(new FizzRule());
        rules.register(new BuzzRule());
        rules.register(new FizzBuzzRule(new FizzRule(),new BuzzRule()));
        rules.register(new NonFizzBuzzRule()); //匹配规则
        Facts facts=new Facts();
        for(int i=0;i<100;i++){
        facts.put("number",i);
        rulesEngine.fire(rules,facts);
        System.out.println();
        } }
        }
      • 日志

        31
        32
        33
        34
        fizzbuzzfizzbuzz // 这里打印了两边,因为引擎参数没有把跳出判断加上
        36
        37
        38
        39
        fizz40
        31
        32
        33
        34
        fizzbuzz
        36
        37
        38
  • [ ] shop:这个示例展示MVEL表达式在EasyRules中的应用,这里示例我们实现一个功能: 小商店卖酒,不能卖给未成年人(法定年龄小于18岁的人)

    • 定义一个人的对象
    @Data
    public class Person {
    private String name; private int age; private boolean adult; }
    • MVEL 表达式来写一个规则,这个规则做两件事,首先判断人是不是18岁以上,如果是我们将人的adult属性修改为true,成年人。买酒的行为判断人是否成年如果未成年则拒绝。

      Rule ageRule=new MVELRule()
      .name("年龄规则")
      .description("检查用户年龄是否大于18岁")
      .priority(1)
      .when("person.age > 18")
      .then("person.setAdult(true);");
    • 另外一个规则,是否可以买酒,这次用一个另外的方式来配置规则,写yml文件的方式代码如下:

      name: "alcohol rule"
      description: "小孩子不能喝酒"
      priority: 2
      condition: "person.isAdult()==false"
      # 这里是actions数组类型-容易写成action
      actions:
      - "System.out.println(\\"Shop: Sorry, you are not allowed to buy alcohol\\");"
    • 运行:用MVELRuleFactory加载规则

      public class MvelRuleDemo {
      public static void main(String[] args) throws Exception {
      Rule ageRule=new MVELRule()
      .name("年龄规则")
      .description("检查用户年龄是否大于18岁")
      .priority(1)
      .when("person.age > 18")
      .then("person.setAdult(true);");
      //定义工厂类
      MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
      URL url = MvelRuleDemo.class.getClassLoader().getResource("rule/alcohol-rule.yml");
      Rule alcoholRule = ruleFactory.createRule(new FileReader(url.getPath())); // 规则合集
      Rules rules=new Rules();
      rules.register(ageRule);
      rules.register(alcoholRule); //规则引擎
      RulesEngine rulesEngine=new DefaultRulesEngine();
      // 实例
      System.out.println("来判断接下来的客人能不能买酒");
      Person p=new Person();
      p.setAge(17);
      p.setName("小李"); Facts facts=new Facts();
      facts.put("person",p); // 执行
      rulesEngine.fire(rules,facts);
      }
      }
      来判断接下来的客人能不能买酒
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '年龄规则', description = '检查用户年龄是否大于18岁', priority = '1'}
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'alcohol rule', description = '小孩子不能喝酒', priority = '2'}
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { person : Person(name=小李, age=17, adult=false) }
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '年龄规则' has been evaluated to false, it has not been executed
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'alcohol rule' triggered
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'alcohol rule' performed successfully
      Shop: Sorry, you are not allowed to buy alcohol
    • 修改为19岁后执行-执行完打印一下用户信息,发现用户的成年状态被修改了

      来判断接下来的客人能不能买酒
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '年龄规则', description = '检查用户年龄是否大于18岁', priority = '1'}
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = 'alcohol rule', description = '小孩子不能喝酒', priority = '2'}
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { person : Person(name=小李, age=19, adult=false) }
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '年龄规则' triggered
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '年龄规则' performed successfully
      [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule 'alcohol rule' has been evaluated to false, it has not been executed
      Person(name=小李, age=19, adult=true)
    • [ ] InferenceRulesEngine 持续对已知事实应用规则,直到不再应用规则为止,上面的例子们引擎由默认改为这个的话,代码停不下来,可以试一下,源码也可以读一下处理方式由很大不同。

      • default

        @Override
        public void fire(Rules rules, Facts facts) {
        triggerListenersBeforeRules(rules, facts);
        doFire(rules, facts);
        triggerListenersAfterRules(rules, facts);
        } void doFire(Rules rules, Facts facts) {
        if (rules.isEmpty()) {
        LOGGER.warn("No rules registered! Nothing to apply");
        return;
        }
        logEngineParameters();
        log(rules);
        log(facts);
        LOGGER.debug("Rules evaluation started");
        for (Rule rule : rules) {
        final String name = rule.getName();
        final int priority = rule.getPriority();
        if (priority > parameters.getPriorityThreshold()) {
        LOGGER.debug("Rule priority threshold ({}) exceeded at rule '{}' with priority={}, next rules will be skipped",
        parameters.getPriorityThreshold(), name, priority);
        break;
        }
        if (!shouldBeEvaluated(rule, facts)) {
        LOGGER.debug("Rule '{}' has been skipped before being evaluated",
        name);
        continue;
        }
        if (rule.evaluate(facts)) {
        LOGGER.debug("Rule '{}' triggered", name);
        triggerListenersAfterEvaluate(rule, facts, true);
        try {
        triggerListenersBeforeExecute(rule, facts);
        rule.execute(facts);
        LOGGER.debug("Rule '{}' performed successfully", name);
        triggerListenersOnSuccess(rule, facts);
        if (parameters.isSkipOnFirstAppliedRule()) {
        LOGGER.debug("Next rules will be skipped since parameter skipOnFirstAppliedRule is set");
        break;
        }
        } catch (Exception exception) {
        LOGGER.error("Rule '" + name + "' performed with error", exception);
        triggerListenersOnFailure(rule, exception, facts);
        if (parameters.isSkipOnFirstFailedRule()) {
        LOGGER.debug("Next rules will be skipped since parameter skipOnFirstFailedRule is set");
        break;
        }
        }
        } else {
        LOGGER.debug("Rule '{}' has been evaluated to false, it has not been executed", name);
        triggerListenersAfterEvaluate(rule, facts, false);
        if (parameters.isSkipOnFirstNonTriggeredRule()) {
        LOGGER.debug("Next rules will be skipped since parameter skipOnFirstNonTriggeredRule is set");
        break;
        }
        }
        }
        }
      • inferenceRulesEngine: 只是在默认的执行外包装了以下一下代码

        @Override
        public void fire(Rules rules, Facts facts) {
        Set<Rule> selectedRules;
        do {
        LOGGER.debug("Selecting candidate rules based on the following facts: {}", facts);
        selectedRules = selectCandidates(rules, facts);
        if(!selectedRules.isEmpty()) {
        // 这个delegate就是上面默认的规则引擎
        delegate.fire(new Rules(selectedRules), facts);
        } else {
        LOGGER.debug("No candidate rules found for facts: {}", facts);
        }
        } while (!selectedRules.isEmpty());
        } private Set<Rule> selectCandidates(Rules rules, Facts facts) {
        Set<Rule> candidates = new TreeSet<>();
        for (Rule rule : rules) {
        if (rule.evaluate(facts)) {
        candidates.add(rule);
        }
        }
        return candidates;
        }

      示例展示一个空调系统,当温度过高时不断降温操作直至温度降低到合适的度数,

      • 创建一个条件类,来决定什么时候是热

        public class HighTemperatureConditon implements org.jeasy.rules.api.Condition {
        // 中文意思评估评定-
        @Override
        public boolean evaluate(Facts facts) {
        Integer temperature=facts.get("temperature"); return temperature>25;
        } static HighTemperatureConditon itIsHot(){
        return new HighTemperatureConditon();
        }
        }
      • action类,满足条件后的执行内容

        public class DecreaseTemperactureAction implements org.jeasy.rules.api.Action {
        @Override
        public void execute(Facts facts) throws Exception {
        System.out.println("温度过高-降温");
        Integer temperature=facts.get("temperature");
        facts.put("temperature",temperature-1);
        }
        static DecreaseTemperactureAction decreaseTemperacture(){
        return new DecreaseTemperactureAction();
        }
        }
      • 执行类-我们注册规则指定规则的触发条件为温度过高,rule.evaluate 方法,然后then执行的结果是:action.execute

        public class AirLauncherDemo {
        public static void main(String[] args) {
        Facts facts=new Facts();
        facts.put("temperature",30); // 规则
        Rule airRule= new RuleBuilder()
        .name("空调测试")
        .when(HighTemperatureConditon.itIsHot())
        .then(DecreaseTemperactureAction.decreaseTemperacture())
        .build(); Rules rules=new Rules();
        rules.register(airRule); //inference引擎,持续不断的执行
        RulesEngine rulesEngine=new InferenceRulesEngine(); rulesEngine.fire(rules,facts);
        System.out.println(facts.get("temperature").toString());
        }
        }
      • 日志-我们发现一直降温到25度

        [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 30 } ]
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '空调测试', description = 'description', priority = '2147483646'}
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { temperature : 30 }
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' triggered
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' performed successfully
        [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 29 } ]
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '空调测试', description = 'description', priority = '2147483646'}
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { temperature : 29 }
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' triggered
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' performed successfully
        [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 28 } ]
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '空调测试', description = 'description', priority = '2147483646'}
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { temperature : 28 }
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' triggered
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' performed successfully
        [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 27 } ]
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '空调测试', description = 'description', priority = '2147483646'}
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { temperature : 27 }
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' triggered
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' performed successfully
        [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 26 } ]
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Engine parameters { skipOnFirstAppliedRule = false, skipOnFirstNonTriggeredRule = false, skipOnFirstFailedRule = false, priorityThreshold = 2147483647 }
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Registered rules:
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule { name = '空调测试', description = 'description', priority = '2147483646'}
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Known facts:
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Fact { temperature : 26 }
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rules evaluation started
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' triggered
        [main] DEBUG org.jeasy.rules.core.DefaultRulesEngine - Rule '空调测试' performed successfully
        [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - Selecting candidate rules based on the following facts: [ { temperature : 25 } ]
        [main] DEBUG org.jeasy.rules.core.InferenceRulesEngine - No candidate rules found for facts: [ { temperature : 25 } ]
        温度过高-降温
        温度过高-降温
        温度过高-降温
        温度过高-降温
        温度过高-降温
        25

      这个示例说明,InferenceRulesEngine 会不断的重新进行判断执行,所以必须在满足条件执行的操作中修改自身实例。不然会崩溃

easy-rule 学习的更多相关文章

  1. jquery easy ui 学习 (6) basic validatebox

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. jquery easy ui 学习 (9)Pagination in TreeGrid 分页

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. jquery easy ui 学习 (8)basic treegrid

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. jquery easy ui 学习 (7) TreeGrid Actions

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  5. jquery easy ui 学习 (5) windowlayout

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. jquery easy ui 学习 (4) window 打开之后 限制操纵后面元素属性

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. jquery easy ui 学习 (3) window 限制在父类窗体内

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. jquery easy ui 学习 (2) customtools window

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. jquery easy ui 学习 (1)Basic Window

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. easy ui 学习笔记,不断整理中............

    $.message.show({//浏览器右下角弹框,我列出了几个属性,具体请看API                   title: '提示',                   msg: '恭 ...

随机推荐

  1. Java File常见用法

    一.构造方法 File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例. File(String pathname) 通过将给定的路径名字符 ...

  2. 四:HttpServletRequest对象

    一.HttpServletRequest介绍 HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象 ...

  3. 使用HttpURLConnection多线程下载

    1 import java.io.IOException; 2 import java.io.InputStream; 3 import java.io.RandomAccessFile; 4 imp ...

  4. 多线程编程<五>

    1 /** 2 * 中断线程:当线程由于调用sleep(),join(),wait()而暂停时,如果中断它,则会收到一个InterruptedException异常. 3 * 调用Thread.isI ...

  5. HCNP Routing&Switching之OSPF LSA类型

    前文我们了解了OSPF中的虚连接相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15202348.html:今天我们来聊一聊OSPF数据包中LSA类型相 ...

  6. 检测一个页面所用的时间的js

    window.onload = function () { var loadTime = window.performance.timing.domContentLoadedEventEnd-wind ...

  7. uni-app 小程序从零开始的开发流程

    前言 本文基于 HBuilderX 3.1.22 + 微信开发者工具 1.05.2106300为主要内容进行说明. 文档版本:1.0.0 更新时间:2021-09-03 15:32 一.准备 uni- ...

  8. PyCharm——滚动鼠标调整字体大小

  9. Flask(2)- 第一个 Flask Application

    安装 flask Flask 是一个 Web 框架,使用它首先需要安装 pip3 install flask 导入 Flask 模块 import flask 最简单的一个栗子 主代码 from fl ...

  10. JDK 1.7 正式发布,Oracle 官宣免费提供!“新版任你发,我用JDK 8”或成历史?

    Oracle公司JDK 17正式发布,JDK 17属于长期支持(LTS)版本,也就是获得8年的技术支持,自2021年9月至2029年9月截止. JDK 17版本更新了很多比较实用的新特性,关于此版本的 ...