From fb4134cc276b0ee24a1fa4222a6f2e04f79cd6ef Mon Sep 17 00:00:00 2001 From: bunny <1319900154@qq.com> Date: Sat, 17 May 2025 20:32:12 +0800 Subject: [PATCH] init --- .gitignore | 65 + drools/.gitlab-ci.yml | 49 + drools/Dockerfile | 29 + drools/Gitlab安装.md | 256 ++ drools/ReadMe.md | 3 + drools/pom.xml | 126 + drools/push.sh | 5 + .../cn/bunny/drools/DroolsApplication.java | 13 + .../bunny/drools/bean/demo/BookDisCount.java | 20 + .../bunny/drools/bean/demo/demo1/Order.java | 37 + .../drools/bean/demo/demo2/AccessRequest.java | 26 + .../bunny/drools/bean/demo/demo2/Content.java | 18 + .../drools/bean/demo/demo2/ContentType.java | 8 + .../cn/bunny/drools/bean/demo/demo2/User.java | 20 + .../bean/demo/demo3/ApprovalDecision.java | 16 + .../demo/demo3/CreditCardApplication.java | 37 + .../bean/exercise/ComparisonOperation.java | 22 + .../drools/config/DroolsConfiguration.java | 30 + .../src/main/resources/META-INF/kmodule.xml | 13 + drools/src/main/resources/application.yml | 10 + drools/src/main/resources/banner.txt | 10 + drools/src/main/resources/logback.xml | 69 + .../main/resources/rules/demo/age-verify.drl | 51 + .../resources/rules/demo/book-discount.drl | 40 + .../rules/demo/credit-card-approval.drl | 89 + .../src/main/resources/rules/demo/order.drl | 34 + .../rules/exercise/exercise-01-contains.drl | 20 + .../rules/exercise/exercise-02-contains.drl | 16 + .../rules/exercise/exercise-03-contains.drl | 23 + .../rules/exercise/exercise-04-contains.drl | 23 + .../drools/demo/_00BookDisCountTest.java | 29 + .../cn/bunny/drools/demo/_01OrderTest.java | 26 + .../bunny/drools/demo/_02AgeVerifyTest.java | 61 + .../demo/_03CreditCardApplicationTest.java | 72 + .../Exercise01ComparisonOperationTest.java | 148 + .../drools/tutorials/_01InitDroolsTest.java | 20 + .../tutorials/_02GetKModuleXmlTest.java | 28 + .../drools/tutorials/_03KieModuleTest.java | 44 + vue-tutorials/.editorconfig | 9 + vue-tutorials/.eslintcache | 1 + vue-tutorials/.gitattributes | 1 + vue-tutorials/.prettierignore | 11 + vue-tutorials/.prettierrc.js | 46 + vue-tutorials/README.md | 39 + vue-tutorials/env.d.ts | 1 + vue-tutorials/eslint.config.ts | 174 + vue-tutorials/index.html | 13 + vue-tutorials/package.json | 49 + vue-tutorials/pnpm-lock.yaml | 3843 +++++++++++++++++ vue-tutorials/public/favicon.ico | Bin 0 -> 4286 bytes vue-tutorials/src/App.vue | 71 + vue-tutorials/src/assets/base.css | 86 + vue-tutorials/src/assets/logo.svg | 1 + vue-tutorials/src/assets/main.css | 35 + vue-tutorials/src/main.ts | 14 + vue-tutorials/src/router/index.ts | 24 + vue-tutorials/src/stores/counter.ts | 12 + vue-tutorials/src/views/AboutView.vue | 61 + vue-tutorials/src/views/HomeView.vue | 48 + vue-tutorials/tsconfig.app.json | 12 + vue-tutorials/tsconfig.json | 11 + vue-tutorials/tsconfig.node.json | 19 + vue-tutorials/vite.config.ts | 16 + 63 files changed, 6203 insertions(+) create mode 100644 .gitignore create mode 100644 drools/.gitlab-ci.yml create mode 100644 drools/Dockerfile create mode 100644 drools/Gitlab安装.md create mode 100644 drools/ReadMe.md create mode 100644 drools/pom.xml create mode 100644 drools/push.sh create mode 100644 drools/src/main/java/cn/bunny/drools/DroolsApplication.java create mode 100644 drools/src/main/java/cn/bunny/drools/bean/demo/BookDisCount.java create mode 100644 drools/src/main/java/cn/bunny/drools/bean/demo/demo1/Order.java create mode 100644 drools/src/main/java/cn/bunny/drools/bean/demo/demo2/AccessRequest.java create mode 100644 drools/src/main/java/cn/bunny/drools/bean/demo/demo2/Content.java create mode 100644 drools/src/main/java/cn/bunny/drools/bean/demo/demo2/ContentType.java create mode 100644 drools/src/main/java/cn/bunny/drools/bean/demo/demo2/User.java create mode 100644 drools/src/main/java/cn/bunny/drools/bean/demo/demo3/ApprovalDecision.java create mode 100644 drools/src/main/java/cn/bunny/drools/bean/demo/demo3/CreditCardApplication.java create mode 100644 drools/src/main/java/cn/bunny/drools/bean/exercise/ComparisonOperation.java create mode 100644 drools/src/main/java/cn/bunny/drools/config/DroolsConfiguration.java create mode 100644 drools/src/main/resources/META-INF/kmodule.xml create mode 100644 drools/src/main/resources/application.yml create mode 100644 drools/src/main/resources/banner.txt create mode 100644 drools/src/main/resources/logback.xml create mode 100644 drools/src/main/resources/rules/demo/age-verify.drl create mode 100644 drools/src/main/resources/rules/demo/book-discount.drl create mode 100644 drools/src/main/resources/rules/demo/credit-card-approval.drl create mode 100644 drools/src/main/resources/rules/demo/order.drl create mode 100644 drools/src/main/resources/rules/exercise/exercise-01-contains.drl create mode 100644 drools/src/main/resources/rules/exercise/exercise-02-contains.drl create mode 100644 drools/src/main/resources/rules/exercise/exercise-03-contains.drl create mode 100644 drools/src/main/resources/rules/exercise/exercise-04-contains.drl create mode 100644 drools/src/test/java/cn/bunny/drools/demo/_00BookDisCountTest.java create mode 100644 drools/src/test/java/cn/bunny/drools/demo/_01OrderTest.java create mode 100644 drools/src/test/java/cn/bunny/drools/demo/_02AgeVerifyTest.java create mode 100644 drools/src/test/java/cn/bunny/drools/demo/_03CreditCardApplicationTest.java create mode 100644 drools/src/test/java/cn/bunny/drools/exercise/Exercise01ComparisonOperationTest.java create mode 100644 drools/src/test/java/cn/bunny/drools/tutorials/_01InitDroolsTest.java create mode 100644 drools/src/test/java/cn/bunny/drools/tutorials/_02GetKModuleXmlTest.java create mode 100644 drools/src/test/java/cn/bunny/drools/tutorials/_03KieModuleTest.java create mode 100644 vue-tutorials/.editorconfig create mode 100644 vue-tutorials/.eslintcache create mode 100644 vue-tutorials/.gitattributes create mode 100644 vue-tutorials/.prettierignore create mode 100644 vue-tutorials/.prettierrc.js create mode 100644 vue-tutorials/README.md create mode 100644 vue-tutorials/env.d.ts create mode 100644 vue-tutorials/eslint.config.ts create mode 100644 vue-tutorials/index.html create mode 100644 vue-tutorials/package.json create mode 100644 vue-tutorials/pnpm-lock.yaml create mode 100644 vue-tutorials/public/favicon.ico create mode 100644 vue-tutorials/src/App.vue create mode 100644 vue-tutorials/src/assets/base.css create mode 100644 vue-tutorials/src/assets/logo.svg create mode 100644 vue-tutorials/src/assets/main.css create mode 100644 vue-tutorials/src/main.ts create mode 100644 vue-tutorials/src/router/index.ts create mode 100644 vue-tutorials/src/stores/counter.ts create mode 100644 vue-tutorials/src/views/AboutView.vue create mode 100644 vue-tutorials/src/views/HomeView.vue create mode 100644 vue-tutorials/tsconfig.app.json create mode 100644 vue-tutorials/tsconfig.json create mode 100644 vue-tutorials/tsconfig.node.json create mode 100644 vue-tutorials/vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..753a89a --- /dev/null +++ b/.gitignore @@ -0,0 +1,65 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ +logs +docs + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo diff --git a/drools/.gitlab-ci.yml b/drools/.gitlab-ci.yml new file mode 100644 index 0000000..ade5a0d --- /dev/null +++ b/drools/.gitlab-ci.yml @@ -0,0 +1,49 @@ +# 定义CI/CD流水线的阶段 +stages: + - build # 第一阶段:构建应用程序 + - build-docker # 第二阶段:构建Docker镜像 + - deploy # 第三阶段:部署应用程序 + +# 定义全局变量 +variables: + CONTAINER_NAME: "bunny-auth-server" # Docker容器名称 + DOCKER_TAG: "4.0.0" # Docker镜像标签版本 + +# 构建任务 +build-job: + stage: build # 指定此任务属于build阶段 + script: + # 打印编译开始信息 + - echo "Compiling the code..." + # 使用Maven编译Java项目,跳过测试 + - mvn clean package -DskipTests + # 打印编译完成信息 + - echo "Compile complete." + # 从Docker Hub拉取OpenJDK基础镜像 + - docker pull openjdk:24-ea-17-jdk-oraclelinux9 + # 打印拉取完成信息 + - echo "docker pull complete." + # 使用Dockerfile构建Docker镜像,并打上标签 + - docker build -f Dockerfile -t $CONTAINER_NAME:$DOCKER_TAG . + # 打印构建成功信息 + - echo "Application successfully deployed." + +# 部署任务 +deploy-job: + stage: deploy # 指定此任务属于deploy阶段 + environment: production # 指定部署环境为production + script: + # 打印部署开始信息 + - echo "Deploying application..." + # 停止正在运行的容器(如果存在),|| true确保命令失败不会中断脚本 + - docker stop $CONTAINER_NAME || true + # 删除容器(如果存在) + - docker rm $CONTAINER_NAME || true + # 运行新的Docker容器 + # -d: 后台运行 + # -p: 端口映射(7070和8000) + # --name: 容器名称 + # --restart always: 总是自动重启 + - docker run -d -p 7070:7070 -p 8000:8000 --name $CONTAINER_NAME --restart always $CONTAINER_NAME:$DOCKER_TAG + # 打印部署成功信息 + - echo "Application successfully deployed." \ No newline at end of file diff --git a/drools/Dockerfile b/drools/Dockerfile new file mode 100644 index 0000000..703cbbe --- /dev/null +++ b/drools/Dockerfile @@ -0,0 +1,29 @@ +FROM openjdk:24-ea-17-jdk-oraclelinux9 +LABEL maintainer="server" + +#系统编码 +ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 + +# 设置时区,构建镜像时执行的命令 +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime +RUN echo "Asia/Shanghai" > /etc/timezone + +# 设定工作目录 +WORKDIR /home/server + +# 复制jar包 +COPY target/*.jar /home/server/app.jar + +# 启动容器时的进程 +ENTRYPOINT ["java","-jar","/home/server/app.jar"] + +#暴露 8080 端口 +EXPOSE 8080 +EXPOSE 7070 + +# 生产环境 +# mvn clean package -Pprod -DskipTests + +# 测试环境 +# mvn clean package -Ptest -DskipTests + diff --git a/drools/Gitlab安装.md b/drools/Gitlab安装.md new file mode 100644 index 0000000..aafa181 --- /dev/null +++ b/drools/Gitlab安装.md @@ -0,0 +1,256 @@ +# Gitlab安装 + +完全笔记《安装GitLabel》 :https://www.yuque.com/bunny-6ixda/bgxtva/wtw4x4r8kbvxwgac?singleDoc# + +## Docker安装 + +- docker镜像: + +- https://hub.docker.com/r/gitlab/gitlab-ee/tags?name=17.9.6 +- https://hub.docker.com/r/gitlab/gitlab-runner/tags?name=17.11.0 + +```bash +sudo apt-get remove docker docker-engine docker.io containerd runc +sudo apt update +sudo apt upgrade +sudo apt-get install ca-certificates curl gnupg lsb-release +# 添加Docker官方GPG密钥 +sudo curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add - +sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" +# 安装docker +sudo apt-get install docker-ce docker-ce-cli containerd.io +# 默认情况下,只有root用户和docker组的用户才能运行Docker命令。我们可以将当前用户添加到docker组,以避免每次使用Docker时都需要使用sudo,设置完成后退出当前用户之后再进入既可 +sudo usermod -aG docker $USER +# 运行docker +sudo systemctl start docker +# 安装工具 +sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common +# 重启docker +sudo service docker restart +# 重启终端生效 +exit +``` + +配置镜像源 + +```bash +# 创建目录 +sudo mkdir -p /etc/docker +# 写入配置文件 +sudo tee /etc/docker/daemon.json <<-'EOF' +{ + "registry-mirrors": [ + "https://docker-0.unsee.tech", + "https://docker-cf.registry.cyou", + "https://docker.1panel.live" + ] +} +EOF + +# 重启docker服务 +sudo systemctl daemon-reload && sudo systemctl restart docker +``` + +## 环境搭建 + +### 安装JDK21 + +```bash +# 安装JDK21 +wget https://download.oracle.com/java/21/latest/jdk-21_linux-x64_bin.deb +sudo dpkg -i jdk-21_linux-x64_bin.deb +java --version +``` + +### Maven 3.8.8安装 + +#### 安装 + +```bash +# 安装maven +wget https://archive.apache.org/dist/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz +sudo mkdir -p /opt/maven +sudo tar -xzf apache-maven-3.8.8-bin.tar.gz -C /opt/maven +sudo mv /opt/maven/apache-maven-3.8.8 /opt/maven/maven-3.8.8 + +# 修改镜像配置 +cd /opt/maven/maven-3.8.8/conf +# 赋予权限修改 +sudo chmod 666 settings.xml + +# 编写配置 +sudo vim /etc/profile + +# 添加以下内容 +# export PATH=$PATH:/opt/maven/maven-3.8.8/bin + +# 刷新配置 +source /etc/profile +mvn -V +``` + +#### maven的镜像 + +```xml + + aliyun + Aliyun Maven Mirror + https://maven.aliyun.com/repository/public + central + +``` + +## 安装Gitlab + +```bash +# Ubuntu +wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu/pool/focal/main/g/gitlab-ce/gitlab-ce_18.0.0-ce.0_amd64.deb + +# dpkg +sudo dpkg -i gitlab-ce_18.0.0-ce.0_amd64.deb +``` + +### 编辑配置 + +```bash +# 编辑站点 +sudo vim /etc/gitlab/gitlab.rb +``` + +修改下面内容 + +```bash +external_url 'http://192.168.95.134:3001' +``` + +应用配置 + +```bash +# 应用配置 +sudo gitlab-ctl reconfigure +``` + +### 常用命令 + +```bash +# 服务控制 +sudo gitlab-ctl start +sudo gitlab-ctl status +sudo gitlab-ctl stop + +# 应用配置 +sudo gitlab-ctl reconfigure + +# 重启 +sudo gitlab-ctl restart +``` + +### 查看密码 + +```bash +# 24 小时后自动删除 +sudo cat /etc/gitlab/initial_root_password +``` + +## 安装Gitlab-Runner + +```bash +# 需要 gitlab-runner-helper-images +wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-runner/ubuntu/pool/focal/main/g/gitlab-runner-helper-images/gitlab-runner-helper-images_18.0.1-1_all.deb +sudo dpkg -i gitlab-runner-helper-images_18.0.1-1_all.deb + +# 之后安装 gitlab-runner +wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-runner/ubuntu/pool/focal/main/g/gitlab-runner/gitlab-runner_18.0.1-1_amd64.deb +sudo dpkg -i gitlab-runner_18.0.1-1_amd64.deb +``` + +### 先下载后安装 + +```bash +# Ubuntu +wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-runner/ubuntu/pool/focal/main/g/gitlab-runner-helper-images/gitlab-runner-helper-images_18.0.1-1_all.deb +wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-runner/ubuntu/pool/focal/main/g/gitlab-runner/gitlab-runner_18.0.1-1_amd64.deb + +# dpkg +sudo dpkg -i gitlab-runner-helper-images_18.0.1-1_all.deb +sudo dpkg -i gitlab-runner_18.0.1-1_amd64.deb +``` + +### 配置Gitlab-Runner用户 + +> [!NOTE] +> +> 如果有需要清理缓存:`sudo rm -rf /opt/maven/maven-3.8.8/conf/builds/**`** +> +> gitlab-ce:https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu/pool/focal/main/g/gitlab-ce/ +> +> gitlab-runner-helper-images:https://mirrors.tuna.tsinghua.edu.cn/gitlab-runner/ubuntu/pool/focal/main/g/gitlab-runner-helper-images/ +> +> gitlab-runner:https://mirrors.tuna.tsinghua.edu.cn/gitlab-runner/ubuntu/pool/focal/main/g/gitlab-runner/ + +```bash +sudo gitlab-runner uninstall +sudo gitlab-runner install --working-directory /home/gitlab-runner --user root +sudo systemctl restart gitlab-runner +``` + +### 检查 GitLab Runner 配置 + +```bash +sudo vim /etc/gitlab-runner/config.toml +``` + +修改文件 + +```bash +[[runners]] + name = "my-runner" + executor = "shell" + shell = "bash" + user = "gitlab-runner" # 确保用户有权限 + working_directory = "/home/gitlab-runner" +``` + +### 检查 Maven 安装目录权限 + +```bash +sudo chmod 777 -R /opt/maven/maven-3.8.8 +sudo chmod 777 -R /opt/maven/maven-3.8.8/ +sudo chown -R gitlab-runner:gitlab-runner /opt/maven/maven-3.8.8/ +``` + +## CI/CD脚本示例 + +如果构建出现`pending`情况大部分情况下,是文件写错了,要么是`Gitlab-Runner`标签没写对 + +```yml +stages: + - build + - build-docker + - deploy + +variables: + CONTAINER_NAME: "bunny-auth-server" + DOCKER_TAG: "4.0.0" + +build-job: + stage: build + script: + - echo "Compiling the code..." + - mvn clean package -DskipTests + - echo "Compile complete." + - docker pull openjdk:24-ea-17-jdk-oraclelinux9 + - echo "docker pull complete." + - docker build -f Dockerfile -t $CONTAINER_NAME:$DOCKER_TAG . + - echo "Application successfully deployed." + +deploy-job: + stage: deploy + environment: production + script: + - echo "Deploying application..." + - docker stop $CONTAINER_NAME || true + - docker rm $CONTAINER_NAME || true + - docker run -d -p 7070:7070 -p 8000:8000 --name $CONTAINER_NAME --restart always $CONTAINER_NAME:$DOCKER_TAG + - echo "Application successfully deployed." +``` \ No newline at end of file diff --git a/drools/ReadMe.md b/drools/ReadMe.md new file mode 100644 index 0000000..ef02224 --- /dev/null +++ b/drools/ReadMe.md @@ -0,0 +1,3 @@ +# Drools + +包含Gitlab部署 \ No newline at end of file diff --git a/drools/pom.xml b/drools/pom.xml new file mode 100644 index 0000000..c06524a --- /dev/null +++ b/drools/pom.xml @@ -0,0 +1,126 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + + cn.bunny + drools + 0.0.1-SNAPSHOT + drools + drools + + + + + + + + + + 17 + 10.0.0 + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.drools + drools-ruleunits-engine + ${drools.version} + + + org.drools + drools-model-compiler + ${drools.version} + + + org.drools + drools-core + ${drools.version} + + + org.drools + drools-compiler + ${drools.version} + + + org.drools + drools-decisiontables + ${drools.version} + + + org.drools + drools-xml-support + ${drools.version} + + + org.drools + drools-mvel + ${drools.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.projectlombok + lombok + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + org.kie + kie-maven-plugin + 7.73.0.Final + true + + + + + diff --git a/drools/push.sh b/drools/push.sh new file mode 100644 index 0000000..c373f2c --- /dev/null +++ b/drools/push.sh @@ -0,0 +1,5 @@ +git checkout master +git merge dev +git push --all +git push --tags +git checkout dev \ No newline at end of file diff --git a/drools/src/main/java/cn/bunny/drools/DroolsApplication.java b/drools/src/main/java/cn/bunny/drools/DroolsApplication.java new file mode 100644 index 0000000..3813e16 --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/DroolsApplication.java @@ -0,0 +1,13 @@ +package cn.bunny.drools; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DroolsApplication { + + public static void main(String[] args) { + SpringApplication.run(DroolsApplication.class, args); + } + +} diff --git a/drools/src/main/java/cn/bunny/drools/bean/demo/BookDisCount.java b/drools/src/main/java/cn/bunny/drools/bean/demo/BookDisCount.java new file mode 100644 index 0000000..0350bf0 --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/bean/demo/BookDisCount.java @@ -0,0 +1,20 @@ +package cn.bunny.drools.bean.demo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class BookDisCount { + + /* 订单原始价格,即优惠前价格 */ + private Double originalPrice; + + /* 订单真实价格,即优惠后价格 */ + private Double realPrice; + +} diff --git a/drools/src/main/java/cn/bunny/drools/bean/demo/demo1/Order.java b/drools/src/main/java/cn/bunny/drools/bean/demo/demo1/Order.java new file mode 100644 index 0000000..917283e --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/bean/demo/demo1/Order.java @@ -0,0 +1,37 @@ +package cn.bunny.drools.bean.demo.demo1; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class Order { + + /* 金额 */ + private BigDecimal amount; + + /* 最终金额 */ + private BigDecimal finalAmount; + + /* 是否是vip */ + private Boolean vip; + + /* 积分 */ + private double score; + + /* 折扣 */ + private double discount; + + public void applyDiscount(double additionalDiscount) { + this.discount += additionalDiscount; + this.finalAmount = this.amount.multiply(new BigDecimal(1 - this.discount)) + .setScale(2, RoundingMode.HALF_UP); + } +} diff --git a/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/AccessRequest.java b/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/AccessRequest.java new file mode 100644 index 0000000..c48c687 --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/AccessRequest.java @@ -0,0 +1,26 @@ +package cn.bunny.drools.bean.demo.demo2; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class AccessRequest { + + /* 用户 */ + private User user; + + /* 访问的内容 */ + private Content content; + + /* 有权访问 */ + private boolean granted; + + /* 拒绝的理由 */ + private String denialReason; + +} \ No newline at end of file diff --git a/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/Content.java b/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/Content.java new file mode 100644 index 0000000..5d8636d --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/Content.java @@ -0,0 +1,18 @@ +package cn.bunny.drools.bean.demo.demo2; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Content { + + private String id; + + /* 内容类型 */ + private ContentType type; + + +} \ No newline at end of file diff --git a/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/ContentType.java b/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/ContentType.java new file mode 100644 index 0000000..40e5414 --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/ContentType.java @@ -0,0 +1,8 @@ +package cn.bunny.drools.bean.demo.demo2; + +/* 类容类型 */ +public enum ContentType { + GENERAL, // 普通内容 + R_RATED, // R级内容 + ALCOHOL // 酒精类产品 +} \ No newline at end of file diff --git a/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/User.java b/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/User.java new file mode 100644 index 0000000..3174e5e --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/bean/demo/demo2/User.java @@ -0,0 +1,20 @@ +package cn.bunny.drools.bean.demo.demo2; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class User { + + /* 用户名 */ + private String username; + + /* 年龄 */ + private Integer age; + +} diff --git a/drools/src/main/java/cn/bunny/drools/bean/demo/demo3/ApprovalDecision.java b/drools/src/main/java/cn/bunny/drools/bean/demo/demo3/ApprovalDecision.java new file mode 100644 index 0000000..1c29942 --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/bean/demo/demo3/ApprovalDecision.java @@ -0,0 +1,16 @@ +package cn.bunny.drools.bean.demo.demo3; + +public interface ApprovalDecision { + + /* 最高额度 */ + String APPROVED_HIGH = "APPROVED_HIGH"; + + /* 中等额度 */ + String APPROVED_MEDIUM = "APPROVED_MEDIUM"; + + /* 最低额度 */ + String APPROVED_LOW = "APPROVED_LOW"; + + /* 拒绝 */ + String REJECTED = "REJECTED"; +} \ No newline at end of file diff --git a/drools/src/main/java/cn/bunny/drools/bean/demo/demo3/CreditCardApplication.java b/drools/src/main/java/cn/bunny/drools/bean/demo/demo3/CreditCardApplication.java new file mode 100644 index 0000000..03c6ec1 --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/bean/demo/demo3/CreditCardApplication.java @@ -0,0 +1,37 @@ +package cn.bunny.drools.bean.demo.demo3; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class CreditCardApplication { + + private String applicantId; + + private String applicantName; + + /* 信用评分(300-850) */ + private int creditScore; + + /* 年收入(美元) */ + private double annualIncome; + + /* 现有负债(美元) */ + private double existingDebt; + + /* 审批结果(APPROVED_HIGH, APPROVED_MEDIUM, APPROVED_LOW, REJECTED) */ + private String decision; + + /* 批准额度 */ + private double approvedLimit; + + public boolean percentage() { + return existingDebt / annualIncome > 0.5; + } + +} \ No newline at end of file diff --git a/drools/src/main/java/cn/bunny/drools/bean/exercise/ComparisonOperation.java b/drools/src/main/java/cn/bunny/drools/bean/exercise/ComparisonOperation.java new file mode 100644 index 0000000..9715e49 --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/bean/exercise/ComparisonOperation.java @@ -0,0 +1,22 @@ +package cn.bunny.drools.bean.exercise; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ComparisonOperation { + + /* 字段名称 */ + private String field; + + /* 操作列表 */ + private List operatorList; + +} diff --git a/drools/src/main/java/cn/bunny/drools/config/DroolsConfiguration.java b/drools/src/main/java/cn/bunny/drools/config/DroolsConfiguration.java new file mode 100644 index 0000000..211159f --- /dev/null +++ b/drools/src/main/java/cn/bunny/drools/config/DroolsConfiguration.java @@ -0,0 +1,30 @@ +package cn.bunny.drools.config; + +import org.kie.api.KieServices; +import org.kie.api.builder.KieBuilder; +import org.kie.api.builder.KieFileSystem; +import org.kie.api.builder.KieModule; +import org.kie.api.runtime.KieContainer; +import org.kie.api.runtime.KieSession; +import org.kie.internal.io.ResourceFactory; + +public class DroolsConfiguration { + + /** + * 读取单个文件内容 + * + * @param filename 规则文件名.后缀名 + * @return KieContainer + */ + public static KieSession createKieSession(String filename) { + KieServices kieServices = KieServices.Factory.get(); + KieFileSystem kfs = kieServices.newKieFileSystem(); + kfs.write(ResourceFactory.newClassPathResource("rules/" + filename)); + + KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll(); + KieModule kieModule = kieBuilder.getKieModule(); + KieContainer container = kieServices.newKieContainer(kieModule.getReleaseId()); + + return container.newKieSession(); + } +} diff --git a/drools/src/main/resources/META-INF/kmodule.xml b/drools/src/main/resources/META-INF/kmodule.xml new file mode 100644 index 0000000..9d46383 --- /dev/null +++ b/drools/src/main/resources/META-INF/kmodule.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/drools/src/main/resources/application.yml b/drools/src/main/resources/application.yml new file mode 100644 index 0000000..cfa5d3c --- /dev/null +++ b/drools/src/main/resources/application.yml @@ -0,0 +1,10 @@ +spring: + application: + name: drools + +logging: + level: + cn.bunny.service.mapper: info + cn.bunny.service.controller: info + cn.bunny.service.service: info + root: info \ No newline at end of file diff --git a/drools/src/main/resources/banner.txt b/drools/src/main/resources/banner.txt new file mode 100644 index 0000000..f8a20fa --- /dev/null +++ b/drools/src/main/resources/banner.txt @@ -0,0 +1,10 @@ + _ _ +| |__ _ _ _ __ _ __ _ _ (_) __ ___ ____ _ +| '_ \| | | | '_ \| '_ \| | | | | |/ _` \ \ / / _` | +| |_) | |_| | | | | | | | |_| | | | (_| |\ V | (_| | +|_.__/ \__,_|_| |_|_| |_|\__, | _/ |\__,_| \_/ \__,_| + |___/ |__/ + +Service Name${spring.application.name} +SpringBoot Version: ${spring-boot.version}${spring-boot.formatted-version} +SpringActive:${spring.profiles.active} diff --git a/drools/src/main/resources/logback.xml b/drools/src/main/resources/logback.xml new file mode 100644 index 0000000..fe0a953 --- /dev/null +++ b/drools/src/main/resources/logback.xml @@ -0,0 +1,69 @@ + + + logback + + + + + + + + + + + + INFO + + + %cyan([%thread %d{yyyy-MM-dd HH:mm:ss}]) %yellow(%-5level) %green(%logger{100}).%boldRed(%method)-%boldMagenta(%line)-%blue(%msg%n) + + ${ENCODING} + + + + + + logs/${datetime}/financial-server.log + true + + %date{yyyy-MM-dd HH:mm:ss} [%-5level] %thread %file:%line %logger %msg%n + ${ENCODING} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/drools/src/main/resources/rules/demo/age-verify.drl b/drools/src/main/resources/rules/demo/age-verify.drl new file mode 100644 index 0000000..4e6a960 --- /dev/null +++ b/drools/src/main/resources/rules/demo/age-verify.drl @@ -0,0 +1,51 @@ +package rules; + +import cn.bunny.drools.bean.demo2.User; +import cn.bunny.drools.bean.demo2.AccessRequest; +import cn.bunny.drools.bean.demo2.Content; +import cn.bunny.drools.bean.demo2.ContentType; + +/** +场景:年龄限制内容访问控制 + +要求: +18岁以下用户不能访问R级内容 +21岁以下用户不能购买酒精类产品 +需要处理用户年龄和访问内容类型两个维度 +*/ + +rule "Deny R-rated content for under 18" + when + $request: AccessRequest( + user.age < 18, + content.type == ContentType.R_RATED, + granted == true + ) + then + $request.setGranted(false); + $request.setDenialReason("未满18岁禁止访问R级内容"); + System.out.println("拒绝R级内容访问: 用户年龄 " + $request.getUser().getAge()); +end + +rule "Deny alcohol purchase for under 21" + when + $request: AccessRequest( + user.age < 21, + content.type == ContentType.ALCOHOL, + granted == true + ) + then + $request.setGranted(false); + $request.setDenialReason("未满21岁禁止购买酒精类产品"); + System.out.println("拒绝酒精购买: 用户年龄 " + $request.getUser().getAge()); +end + +// 规则3: 默认允许访问 +rule "Default access grant" + when + $request: AccessRequest(granted == false) + then + // 如果没有被前面的规则拒绝,则允许访问 + $request.setGranted(true); + System.out.println("允许访问: " + $request.getContent().getType()); +end \ No newline at end of file diff --git a/drools/src/main/resources/rules/demo/book-discount.drl b/drools/src/main/resources/rules/demo/book-discount.drl new file mode 100644 index 0000000..d345b90 --- /dev/null +++ b/drools/src/main/resources/rules/demo/book-discount.drl @@ -0,0 +1,40 @@ +package rules; +import cn.bunny.drools.bean.demo.BookDisCount + +/* + 入门示例 +*/ +rule "There is no discount for books purchased with a total price below 100 yuan" + when + $bookDisCount:BookDisCount(originalPrice < 100) + then + $bookDisCount.setRealPrice($bookDisCount.getOriginalPrice()); + System.out.println("小于100没有优惠"); +end + +rule "20 yuan off the total price of 100 to 200 yuan" + when + $bookDisCount:BookDisCount(originalPrice > 100 && originalPrice < 200 ) + then + Double originalPrice = $bookDisCount.getOriginalPrice(); + $bookDisCount.setRealPrice(originalPrice - 20); + System.out.println("所购图书总价在100到200元的优惠20元"); +end + +rule "50 yuan off the total book price of 200 to 300 yuan" + when + $bookDisCount:BookDisCount(originalPrice > 200 && originalPrice < 300) + then + Double originalPrice = $bookDisCount.getOriginalPrice(); + $bookDisCount.setRealPrice(originalPrice - 50); + System.out.println("所购图书总价在200到300元的优惠50元"); +end + +rule "A discount of 100 yuan will be given if the total price is over 300 yuan" + when + $bookDisCount:BookDisCount(originalPrice > 300) + then + Double originalPrice = $bookDisCount.getOriginalPrice(); + $bookDisCount.setRealPrice(originalPrice - 100); + System.out.println("所购图书总价在300元以上的优惠100元"); +end \ No newline at end of file diff --git a/drools/src/main/resources/rules/demo/credit-card-approval.drl b/drools/src/main/resources/rules/demo/credit-card-approval.drl new file mode 100644 index 0000000..b7a28a6 --- /dev/null +++ b/drools/src/main/resources/rules/demo/credit-card-approval.drl @@ -0,0 +1,89 @@ +package rules; + +import cn.bunny.drools.bean.demo3.ApprovalDecision +import cn.bunny.drools.bean.demo3.CreditCardApplication +import cn.bunny.drools.bean.demo.demo3.ApprovalDecision; + +/** +根据申请人的信用评分、收入和现有负债自动决策 +信用评分>700且收入>5万:批准高额度 +信用评分600-700:批准中等额度 +信用评分<600但收入>10万:批准低额度 +其他情况拒绝 +*/ + +// 规则1: 高额度批准 +rule "Approve High Limit - Excellent Credit" + salience 9 // 提高优先级 + when + $application: CreditCardApplication( + creditScore > 700, + annualIncome > 50000, + decision == null, + existingDebt / annualIncome <= 0.5 + ) + then + $application.setDecision(ApprovalDecision.APPROVED_HIGH); + $application.setApprovedLimit(20000); + System.out.println("批准高额度信用卡: " + $application.getApplicantName()); + drools.halt(); +end + +// 规则2: 中等额度批准 +rule "Approve Medium Limit - Good Credit" + salience 8 + when + $application: CreditCardApplication( + creditScore >= 600 && creditScore <= 700, + decision == null, + existingDebt / annualIncome <= 0.5 + ) + then + $application.setDecision(ApprovalDecision.APPROVED_MEDIUM); + $application.setApprovedLimit(10000); + System.out.println("批准中等额度信用卡: " + $application.getApplicantName()); + drools.halt(); +end + +// 规则3: 低额度批准 +rule "Approve Low Limit - High Income with Low Credit" + salience 6 + when + $application: CreditCardApplication( + creditScore < 600, + annualIncome > 100000, + decision == null, + existingDebt / annualIncome <= 0.5 + ) + then + $application.setDecision(ApprovalDecision.APPROVED_LOW); + $application.setApprovedLimit(5000); + System.out.println("批准低额度信用卡(高收入特殊情况): " + $application.getApplicantName()); + drools.halt(); +end + +// 规则4: 负债过高拒绝 +rule "Reject Application - High Debt Ratio" + salience 10 // 最高优先级 + when + $application: CreditCardApplication( + existingDebt / annualIncome > 0.5, + decision == null + ) + then + $application.setDecision(ApprovalDecision.REJECTED); + $application.setApprovedLimit(0); + System.out.println("拒绝申请: 负债过高 - " + $application.getApplicantName()); + drools.halt(); +end + +// 规则5: 默认拒绝 +rule "Default Rejection" + salience 1 // 最低优先级 + when + $application: CreditCardApplication(decision == null) + then + $application.setDecision(ApprovalDecision.REJECTED); + $application.setApprovedLimit(0); + System.out.println("拒绝申请: 不满足任何批准条件 - " + $application.getApplicantName()); +end \ No newline at end of file diff --git a/drools/src/main/resources/rules/demo/order.drl b/drools/src/main/resources/rules/demo/order.drl new file mode 100644 index 0000000..2f95f95 --- /dev/null +++ b/drools/src/main/resources/rules/demo/order.drl @@ -0,0 +1,34 @@ +package rules; + +import cn.bunny.drools.bean.demo1.Order; + +/** +* 当订单金额超过100元时,给予5%折扣 +* VIP客户额外获得2%折扣 +* 两种折扣可以叠加 +*/ +// 大于100元 5折优惠 +rule "Give 5% discount for orders over 100" + when + $order: Order(amount > 100) + then + $order.applyDiscount(0.05); + System.out.println("当订单金额超过100元时,给予5%折扣"); +end + +// VIP客户额外获得2%折扣 +rule "Give additional 2% discount for VIP customers" + when + $order: Order(amount > 100,vip == true) + then + $order.applyDiscount(0.02); + System.out.println("是个Vip"); +end + +// 没有优惠 +rule "No discount for small orders" + when + $order: Order(amount <= 100) + then + System.out.println("没有优惠"); +end \ No newline at end of file diff --git a/drools/src/main/resources/rules/exercise/exercise-01-contains.drl b/drools/src/main/resources/rules/exercise/exercise-01-contains.drl new file mode 100644 index 0000000..b2c16ca --- /dev/null +++ b/drools/src/main/resources/rules/exercise/exercise-01-contains.drl @@ -0,0 +1,20 @@ +package rules.exercise; + +import cn.bunny.drools.bean.exercise.ComparisonOperation; + +/* + 使用 contains 匹配 +*/ +rule "exercise-01-contains" + when + $comparisonOperation:ComparisonOperation(field contains "张三名称") + then + System.out.println("01 field 匹配到"); +end + +rule "exercise list" + when + $comparisonOperation:ComparisonOperation(operatorList contains field) + then + System.out.println("01 operatorList 匹配到"); +end diff --git a/drools/src/main/resources/rules/exercise/exercise-02-contains.drl b/drools/src/main/resources/rules/exercise/exercise-02-contains.drl new file mode 100644 index 0000000..36fb865 --- /dev/null +++ b/drools/src/main/resources/rules/exercise/exercise-02-contains.drl @@ -0,0 +1,16 @@ +package rules.exercise; +import cn.bunny.drools.bean.exercise.ComparisonOperation; + +rule "exercise-02-contains" + when + $comparisonOperation:ComparisonOperation(field not contains "zxc") + then + System.out.println("02 field 匹配到"); +end + +rule "exercise list 02" + when + $comparisonOperation:ComparisonOperation(operatorList not contains field) + then + System.out.println("02 operatorList 匹配到"); +end diff --git a/drools/src/main/resources/rules/exercise/exercise-03-contains.drl b/drools/src/main/resources/rules/exercise/exercise-03-contains.drl new file mode 100644 index 0000000..a631d02 --- /dev/null +++ b/drools/src/main/resources/rules/exercise/exercise-03-contains.drl @@ -0,0 +1,23 @@ +package rules.exercise; +import cn.bunny.drools.bean.exercise.ComparisonOperation; + +rule "exercise-03-contains" + when + $comparisonOperation:ComparisonOperation(field memberOf "qwe") + then + System.out.println("03 field 匹配到"); +end + +rule "exercise list 03 memberOf" + when + $comparisonOperation:ComparisonOperation("sss" memberOf operatorList) + then + System.out.println("03 operatorList memberOf 匹配到"); +end + +rule "exercise list 03" + when + $comparisonOperation:ComparisonOperation(operatorList not memberOf field) + then + System.out.println("03 not memberOf 匹配到"); +end diff --git a/drools/src/main/resources/rules/exercise/exercise-04-contains.drl b/drools/src/main/resources/rules/exercise/exercise-04-contains.drl new file mode 100644 index 0000000..801a72d --- /dev/null +++ b/drools/src/main/resources/rules/exercise/exercise-04-contains.drl @@ -0,0 +1,23 @@ +package rules.exercise; +import cn.bunny.drools.bean.exercise.ComparisonOperation; + +rule "exercise-04-contains" + activation-group "group_1" + enabled false + // 方言 + // dialect "mvel" + when + // 让其返回 ture 表示匹配成功 + // eval(true) + $comparisonOperation:ComparisonOperation(field matches "q.*") + then + System.out.println("04 field matches q.* 匹配到"); +end + +rule "exercise-04-contains-1" + activation-group "group_1" + when + $comparisonOperation:ComparisonOperation(field not matches "q.*") + then + System.out.println("04 field not matches q.* 匹配到"); +end diff --git a/drools/src/test/java/cn/bunny/drools/demo/_00BookDisCountTest.java b/drools/src/test/java/cn/bunny/drools/demo/_00BookDisCountTest.java new file mode 100644 index 0000000..e23957b --- /dev/null +++ b/drools/src/test/java/cn/bunny/drools/demo/_00BookDisCountTest.java @@ -0,0 +1,29 @@ +package cn.bunny.drools.demo; + +import cn.bunny.drools.bean.demo.BookDisCount; +import org.kie.api.KieServices; +import org.kie.api.runtime.KieContainer; +import org.kie.api.runtime.KieSession; + +public class _00BookDisCountTest { + public static void main(String[] args) { + KieServices kieServices = KieServices.Factory.get(); + KieContainer container = kieServices.newKieClasspathContainer(); + KieSession kieSession = container.newKieSession(); + + BookDisCount order = new BookDisCount(); + order.setOriginalPrice(199.0); + + // 插入 Fact + kieSession.insert(order); + + // 激活规则 + kieSession.fireAllRules(); + + // 关闭会话 + kieSession.dispose(); + + System.out.println(order); + kieSession.close(); + } +} diff --git a/drools/src/test/java/cn/bunny/drools/demo/_01OrderTest.java b/drools/src/test/java/cn/bunny/drools/demo/_01OrderTest.java new file mode 100644 index 0000000..6d8e198 --- /dev/null +++ b/drools/src/test/java/cn/bunny/drools/demo/_01OrderTest.java @@ -0,0 +1,26 @@ +package cn.bunny.drools.demo; + +import cn.bunny.drools.bean.demo.demo1.Order; +import cn.bunny.drools.config.DroolsConfiguration; +import org.kie.api.runtime.KieSession; + +import java.math.BigDecimal; + +class _01OrderTest { + public static void main(String[] args) { + try (KieSession kieSession = DroolsConfiguration.createKieSession("order.drl")) { + + Order order = new Order(); + order.setAmount(new BigDecimal(99)); + order.setAmount(new BigDecimal(101)); + // order.setVip(true); + + // 插入order + kieSession.insert(order); + kieSession.fireAllRules(); + kieSession.dispose(); + + System.out.println(order); + } + } +} \ No newline at end of file diff --git a/drools/src/test/java/cn/bunny/drools/demo/_02AgeVerifyTest.java b/drools/src/test/java/cn/bunny/drools/demo/_02AgeVerifyTest.java new file mode 100644 index 0000000..4a7244c --- /dev/null +++ b/drools/src/test/java/cn/bunny/drools/demo/_02AgeVerifyTest.java @@ -0,0 +1,61 @@ +package cn.bunny.drools.demo; + +import cn.bunny.drools.bean.demo.demo2.AccessRequest; +import cn.bunny.drools.bean.demo.demo2.Content; +import cn.bunny.drools.bean.demo.demo2.ContentType; +import cn.bunny.drools.bean.demo.demo2.User; +import cn.bunny.drools.config.DroolsConfiguration; +import org.kie.api.runtime.KieSession; + +public class _02AgeVerifyTest { + private static AccessRequest verifyAccess(User adult, Content rRatedMovie) { + // 测试1: 成人可以访问所有内容 + AccessRequest request = AccessRequest.builder().user(adult).content(rRatedMovie).build(); + // 默认允许 + request.setGranted(true); + + try (KieSession kieSession = DroolsConfiguration.createKieSession("age-verify.drl")) { + + kieSession.insert(request); + kieSession.insert(adult); + kieSession.insert(rRatedMovie); + + kieSession.fireAllRules(); + kieSession.dispose(); + } + + return request; + } + + public static void main(String[] args) { + User adult = new User("成人用户", 25); + User teen = new User("青少年", 17); + User youngAdult = new User("年轻成人", 20); + + Content rRatedMovie = new Content("R级电影", ContentType.R_RATED); + Content alcohol = new Content("啤酒", ContentType.ALCOHOL); + Content general = new Content("普通内容", ContentType.GENERAL); + + // 测试1: 成人可以访问所有内容 + AccessRequest request1 = verifyAccess(adult, alcohol); + System.out.println(request1.isGranted()); + + AccessRequest request2 = verifyAccess(adult, rRatedMovie); + System.out.println(request2.isGranted()); + + // 测试2: 青少年不能访问R级内容 + AccessRequest request3 = verifyAccess(teen, rRatedMovie); + System.out.println(request3.isGranted()); + System.out.println(request3.getDenialReason()); + + // 测试3: 20岁用户不能购买酒精 + AccessRequest request4 = verifyAccess(youngAdult, alcohol); + System.out.println(request4.isGranted()); + System.out.println(request4.getDenialReason()); + + // 测试4: 所有用户都可以访问普通内容 + AccessRequest request5 = verifyAccess(teen, general); + System.out.println(request5.isGranted()); + System.out.println(request5.getDenialReason()); + } +} diff --git a/drools/src/test/java/cn/bunny/drools/demo/_03CreditCardApplicationTest.java b/drools/src/test/java/cn/bunny/drools/demo/_03CreditCardApplicationTest.java new file mode 100644 index 0000000..0d8711e --- /dev/null +++ b/drools/src/test/java/cn/bunny/drools/demo/_03CreditCardApplicationTest.java @@ -0,0 +1,72 @@ +package cn.bunny.drools.demo; + +import cn.bunny.drools.bean.demo.demo3.CreditCardApplication; +import cn.bunny.drools.config.DroolsConfiguration; +import org.kie.api.runtime.KieSession; + +public class _03CreditCardApplicationTest { + public static void main(String[] args) { + // 测试1: 高额度批准 + CreditCardApplication app1 = CreditCardApplication.builder() + .applicantId("001") + .applicantName("张三") + .creditScore(750) + .annualIncome(60000) // 修正为符合条件 + .existingDebt(5000) + .build(); + app1 = processApplication(app1); + System.out.println("结果1: " + app1.getDecision() + ", 额度: " + app1.getApprovedLimit()); + + // 测试2: 中等额度批准 + CreditCardApplication app2 = CreditCardApplication.builder() + .applicantId("002") + .applicantName("李四") + .creditScore(650) + .annualIncome(45000) + .existingDebt(10000) + .build(); + app2 = processApplication(app2); + System.out.println("结果2: " + app2.getDecision() + ", 额度: " + app2.getApprovedLimit()); + + // 测试3: 低额度批准(高收入但低信用分) + CreditCardApplication app3 = CreditCardApplication.builder() + .applicantId("003") + .applicantName("王五") + .creditScore(550) + .annualIncome(120000) + .existingDebt(20000) + .build(); + app3 = processApplication(app3); + System.out.println("结果3: " + app3.getDecision() + ", 额度: " + app3.getApprovedLimit()); + + // 测试4: 负债过高拒绝 + CreditCardApplication app4 = CreditCardApplication.builder() + .applicantId("004") + .applicantName("赵六") + .creditScore(720) + .annualIncome(50000) + .existingDebt(30000) + .build(); + app4 = processApplication(app4); + System.out.println("结果4: " + app4.getDecision() + ", 额度: " + app4.getApprovedLimit()); + + // 测试5: 默认拒绝 + CreditCardApplication app5 = CreditCardApplication.builder() + .applicantId("005") + .applicantName("钱七") + .creditScore(580) + .annualIncome(40000) + .existingDebt(5000) + .build(); + app5 = processApplication(app5); + System.out.println("结果5: " + app5.getDecision() + ", 额度: " + app5.getApprovedLimit()); + } + + public static CreditCardApplication processApplication(CreditCardApplication application) { + try (KieSession kieSession = DroolsConfiguration.createKieSession("credit-card-approval.drl")) { + kieSession.insert(application); + kieSession.fireAllRules(); + return application; + } + } +} \ No newline at end of file diff --git a/drools/src/test/java/cn/bunny/drools/exercise/Exercise01ComparisonOperationTest.java b/drools/src/test/java/cn/bunny/drools/exercise/Exercise01ComparisonOperationTest.java new file mode 100644 index 0000000..dbee2de --- /dev/null +++ b/drools/src/test/java/cn/bunny/drools/exercise/Exercise01ComparisonOperationTest.java @@ -0,0 +1,148 @@ +package cn.bunny.drools.exercise; + +import cn.bunny.drools.bean.exercise.ComparisonOperation; +import org.drools.core.base.RuleNameEndsWithAgendaFilter; +import org.drools.core.base.RuleNameMatchesAgendaFilter; +import org.drools.core.base.RuleNameStartsWithAgendaFilter; +import org.junit.jupiter.api.Test; +import org.kie.api.KieBase; +import org.kie.api.KieServices; +import org.kie.api.runtime.KieContainer; +import org.kie.api.runtime.KieSession; + +import java.util.List; + +public class Exercise01ComparisonOperationTest { + + /* contains */ + @Test + void test1() { + KieServices kieServices = KieServices.Factory.get(); + KieContainer container = kieServices.getKieClasspathContainer(); + KieBase kieBase = container.getKieBase("Exercise"); + KieSession session = kieBase.newKieSession(); + + ComparisonOperation zxc = ComparisonOperation.builder().field("张三名称").build(); + zxc.setOperatorList(List.of(zxc.getField())); + + // 插入匹配 + session.insert(zxc); + session.fireAllRules(); + session.dispose(); + + session.close(); + } + + /* not contains */ + @Test + void test2() { + KieServices kieServices = KieServices.Factory.get(); + KieContainer container = kieServices.getKieClasspathContainer(); + KieBase kieBase = container.getKieBase("Exercise"); + KieSession session = kieBase.newKieSession(); + + ComparisonOperation zxc = ComparisonOperation.builder().field("qwe").build(); + zxc.setOperatorList(List.of(zxc.getField())); + + // 插入匹配 + session.insert(zxc); + session.fireAllRules(); + session.dispose(); + + session.close(); + } + + /* memberOf */ + @Test + void test3() { + KieServices kieServices = KieServices.Factory.get(); + KieContainer container = kieServices.getKieClasspathContainer(); + KieBase kieBase = container.getKieBase("Exercise"); + KieSession session = kieBase.newKieSession(); + + ComparisonOperation zxc = ComparisonOperation.builder().field("qwe").build(); + zxc.setOperatorList(List.of(zxc.getField(), "sss")); + + // 插入匹配 + session.insert(zxc); + session.fireAllRules(); + session.dispose(); + + session.close(); + } + + /* matches & not matches */ + @Test + void test4() { + KieServices kieServices = KieServices.Factory.get(); + KieContainer container = kieServices.getKieClasspathContainer(); + KieBase kieBase = container.getKieBase("Exercise"); + KieSession session = kieBase.newKieSession(); + + ComparisonOperation zxc = ComparisonOperation.builder().field("qwe").build(); + zxc.setOperatorList(List.of(zxc.getField(), "sss")); + + // 插入匹配 + session.insert(zxc); + session.fireAllRules(); + session.dispose(); + + session.close(); + } + + /* 指定规则后缀进行匹配 */ + @Test + void test5() { + KieServices kieServices = KieServices.Factory.get(); + KieContainer container = kieServices.getKieClasspathContainer(); + KieBase kieBase = container.getKieBase("Exercise"); + KieSession session = kieBase.newKieSession(); + + ComparisonOperation zxc = ComparisonOperation.builder().field("qwe").build(); + zxc.setOperatorList(List.of(zxc.getField(), "sss")); + + // 插入匹配 + session.insert(zxc); + session.fireAllRules(new RuleNameEndsWithAgendaFilter("exercise-04-contains")); + session.dispose(); + + session.close(); + } + + /* 以什么前缀匹配 */ + @Test + void test6() { + KieServices kieServices = KieServices.Factory.get(); + KieContainer container = kieServices.getKieClasspathContainer(); + KieBase kieBase = container.getKieBase("Exercise"); + KieSession session = kieBase.newKieSession(); + + ComparisonOperation zxc = ComparisonOperation.builder().field("qwe").build(); + zxc.setOperatorList(List.of(zxc.getField(), "sss")); + + // 插入匹配 + session.insert(zxc); + session.fireAllRules(new RuleNameStartsWithAgendaFilter("exercise-0")); + session.dispose(); + session.close(); + } + + /* 以正则匹配regexp */ + @Test + void test7() { + KieServices kieServices = KieServices.Factory.get(); + KieContainer container = kieServices.getKieClasspathContainer(); + KieBase kieBase = container.getKieBase("Exercise"); + KieSession session = kieBase.newKieSession(); + + ComparisonOperation zxc = ComparisonOperation.builder().field("qwe").build(); + zxc.setOperatorList(List.of(zxc.getField(), "sss")); + + // 插入匹配 + session.insert(zxc); + session.fireAllRules(new RuleNameMatchesAgendaFilter("exercise-0.*?")); + session.dispose(); + + session.close(); + } +} diff --git a/drools/src/test/java/cn/bunny/drools/tutorials/_01InitDroolsTest.java b/drools/src/test/java/cn/bunny/drools/tutorials/_01InitDroolsTest.java new file mode 100644 index 0000000..a7f60cc --- /dev/null +++ b/drools/src/test/java/cn/bunny/drools/tutorials/_01InitDroolsTest.java @@ -0,0 +1,20 @@ +package cn.bunny.drools.tutorials; + +import org.kie.api.KieBase; +import org.kie.api.KieServices; +import org.kie.api.builder.ReleaseId; +import org.kie.api.runtime.KieContainer; + +public class _01InitDroolsTest { + public static void main(String[] args) { + KieServices kieServices = KieServices.Factory.get(); + KieContainer container = kieServices.getKieClasspathContainer(); + + ClassLoader classLoader = container.getClassLoader(); + ReleaseId releaseId = container.getReleaseId(); + + + KieBase kieBase = container.getKieBase(); + // KieBase kieBase1 = container.newKieBase(); + } +} diff --git a/drools/src/test/java/cn/bunny/drools/tutorials/_02GetKModuleXmlTest.java b/drools/src/test/java/cn/bunny/drools/tutorials/_02GetKModuleXmlTest.java new file mode 100644 index 0000000..9c9cdc7 --- /dev/null +++ b/drools/src/test/java/cn/bunny/drools/tutorials/_02GetKModuleXmlTest.java @@ -0,0 +1,28 @@ +package cn.bunny.drools.tutorials; + +import lombok.extern.slf4j.Slf4j; +import org.kie.api.KieBase; +import org.kie.api.KieServices; +import org.kie.api.runtime.KieContainer; +import org.kie.api.runtime.KieSession; +import org.kie.api.runtime.StatelessKieSession; + +@Slf4j +public class _02GetKModuleXmlTest { + public static void main(String[] args) { + KieServices kieServices = KieServices.Factory.get(); + KieContainer container = kieServices.getKieClasspathContainer(); + + // 验证所有可用KieBase + log.info("Available KieBases: {}", container.getKieBaseNames()); + + KieBase kieBase = container.getKieBase("KBase1"); + log.info("kieBase--->: {}", kieBase); + + KieSession kieSession = container.newKieSession("KSession2_1"); + log.info("kieSession--->: {}", kieSession); + + StatelessKieSession kSession2_2 = container.newStatelessKieSession("KSession2_2"); + log.info("kSession2_2--->: {}", kSession2_2); + } +} diff --git a/drools/src/test/java/cn/bunny/drools/tutorials/_03KieModuleTest.java b/drools/src/test/java/cn/bunny/drools/tutorials/_03KieModuleTest.java new file mode 100644 index 0000000..b147ee9 --- /dev/null +++ b/drools/src/test/java/cn/bunny/drools/tutorials/_03KieModuleTest.java @@ -0,0 +1,44 @@ +package cn.bunny.drools.tutorials; + +import lombok.SneakyThrows; +import org.kie.api.KieServices; +import org.kie.api.builder.KieFileSystem; +import org.kie.api.builder.model.KieBaseModel; +import org.kie.api.builder.model.KieModuleModel; +import org.kie.api.builder.model.KieSessionModel; +import org.kie.api.conf.EqualityBehaviorOption; +import org.kie.api.conf.EventProcessingOption; +import org.kie.api.runtime.conf.ClockTypeOption; + +public class _03KieModuleTest { + /** + * 动态化规则管理 + * 传统限制:kmodule.xml声明式配置需预定义规则路径,修改需重新部署 + * 编程优势:通过KieFileSystem/KieModuleModel可实现: + * 运行时动态加载规则(如从数据库/网络获取DRL文件) + * 热更新规则而不重启服务(结合KieScanner) + */ + @SneakyThrows + public static void main(String[] args) { + KieServices kieServices = KieServices.Factory.get(); + KieModuleModel kieModuleModel = kieServices.newKieModuleModel(); + + KieBaseModel kBase1 = kieModuleModel.newKieBaseModel("kBase1") + .setDefault(true) + .setEqualsBehavior(EqualityBehaviorOption.EQUALITY) + .setEventProcessingMode(EventProcessingOption.STREAM); + + kBase1.newKieSessionModel("KSession1") + .setDefault(true) + .setType(KieSessionModel.KieSessionType.STATEFUL) + .setClockType(ClockTypeOption.get("realtime")); + + KieFileSystem kfs = kieServices.newKieFileSystem(); + kfs.writeKModuleXML(kieModuleModel.toXML()); + + + System.out.println(kieModuleModel.toXML()); + + Thread.sleep(10000000); + } +} diff --git a/vue-tutorials/.editorconfig b/vue-tutorials/.editorconfig new file mode 100644 index 0000000..5a5809d --- /dev/null +++ b/vue-tutorials/.editorconfig @@ -0,0 +1,9 @@ +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +end_of_line = lf +max_line_length = 100 diff --git a/vue-tutorials/.eslintcache b/vue-tutorials/.eslintcache new file mode 100644 index 0000000..e900108 --- /dev/null +++ b/vue-tutorials/.eslintcache @@ -0,0 +1 @@ +[{"D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\App.vue":"1","D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\main.ts":"2","D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\router\\index.ts":"3","D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\stores\\counter.ts":"4","D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\views\\AboutView.vue":"5","D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\views\\HomeView.vue":"6"},{"size":1073,"mtime":1747308619237,"results":"7","hashOfConfig":"8"},{"size":251,"mtime":1747308619237,"results":"9","hashOfConfig":"10"},{"size":596,"mtime":1747308619237,"results":"11","hashOfConfig":"10"},{"size":313,"mtime":1747308619237,"results":"12","hashOfConfig":"10"},{"size":220,"mtime":1747308086660,"results":"13","hashOfConfig":"8"},{"size":100,"mtime":1747308280013,"results":"14","hashOfConfig":"8"},{"filePath":"15","messages":"16","suppressedMessages":"17","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"v5kcfw",{"filePath":"18","messages":"19","suppressedMessages":"20","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"ou3ylh",{"filePath":"21","messages":"22","suppressedMessages":"23","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"24","messages":"25","suppressedMessages":"26","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"27","messages":"28","suppressedMessages":"29","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"30","messages":"31","suppressedMessages":"32","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\App.vue",[],[],"D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\main.ts",[],[],"D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\router\\index.ts",[],[],"D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\stores\\counter.ts",[],[],"D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\views\\AboutView.vue",[],[],"D:\\Project\\Study\\Code\\Web\\vue-tutorials\\src\\views\\HomeView.vue",[],[]] \ No newline at end of file diff --git a/vue-tutorials/.gitattributes b/vue-tutorials/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/vue-tutorials/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/vue-tutorials/.prettierignore b/vue-tutorials/.prettierignore new file mode 100644 index 0000000..f3e9850 --- /dev/null +++ b/vue-tutorials/.prettierignore @@ -0,0 +1,11 @@ +dist +node_modules +public +.husky +.vscode +.idea +*.sh +*.md + +src/assets +stats.html diff --git a/vue-tutorials/.prettierrc.js b/vue-tutorials/.prettierrc.js new file mode 100644 index 0000000..10eefe5 --- /dev/null +++ b/vue-tutorials/.prettierrc.js @@ -0,0 +1,46 @@ +export default { + // (x)=>{},单个参数箭头函数是否显示小括号。(always:始终显示;avoid:省略括号。默认:always) + arrowParens: 'always', + // 开始标签的右尖括号是否跟随在最后一行属性末尾,默认false + bracketSameLine: false, + // 对象字面量的括号之间打印空格 (true - Example: { foo: bar } ; false - Example: {foo:bar}) + bracketSpacing: true, + // 是否格式化一些文件中被嵌入的代码片段的风格(auto|off;默认auto) + embeddedLanguageFormatting: 'auto', + // 指定 HTML 文件的空格敏感度 (css|strict|ignore;默认css) + htmlWhitespaceSensitivity: 'ignore', + // 当文件已经被 Prettier 格式化之后,是否会在文件顶部插入一个特殊的 @format 标记,默认false + insertPragma: false, + // 在 JSX 中使用单引号替代双引号,默认false + jsxSingleQuote: false, + // 每行最多字符数量,超出换行(默认100) + printWidth: 100, + // 超出打印宽度 (always | never | preserve ) + proseWrap: 'preserve', + // 对象属性是否使用引号(as-needed | consistent | preserve;默认as-needed:对象的属性需要加引号才添加;) + quoteProps: 'as-needed', + // 是否只格式化在文件顶部包含特定注释(@prettier| @format)的文件,默认false + requirePragma: false, + // 结尾添加分号 + semi: true, + // 使用单引号 (true:单引号;false:双引号) + singleQuote: true, + // 缩进空格数,默认2个空格 + tabWidth: 2, + // 元素末尾是否加逗号,默认es5: ES5中的 objects, arrays 等会添加逗号,TypeScript 中的 type 后不加逗号 + trailingComma: 'es5', + // 指定缩进方式,空格或tab,默认false,即使用空格 + useTabs: false, + // vue 文件中是否缩进 diff --git a/vue-tutorials/src/assets/base.css b/vue-tutorials/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/vue-tutorials/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/vue-tutorials/src/assets/logo.svg b/vue-tutorials/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/vue-tutorials/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/vue-tutorials/src/assets/main.css b/vue-tutorials/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/vue-tutorials/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/vue-tutorials/src/main.ts b/vue-tutorials/src/main.ts new file mode 100644 index 0000000..b3448d0 --- /dev/null +++ b/vue-tutorials/src/main.ts @@ -0,0 +1,14 @@ +import './assets/main.css'; + +import { createPinia } from 'pinia'; +import { createApp } from 'vue'; + +import App from './App.vue'; +import router from './router'; + +const app = createApp(App); + +app.use(createPinia()); +app.use(router); + +app.mount('#app'); diff --git a/vue-tutorials/src/router/index.ts b/vue-tutorials/src/router/index.ts new file mode 100644 index 0000000..c07f23b --- /dev/null +++ b/vue-tutorials/src/router/index.ts @@ -0,0 +1,24 @@ +import { createRouter, createWebHistory } from 'vue-router'; + +import HomeView from '../views/HomeView.vue'; + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: '/', + name: 'home', + component: HomeView, + }, + { + path: '/about', + name: 'about', + // route level code-splitting + // this generates a separate chunk (About.[hash].js) for this route + // which is lazy-loaded when the route is visited. + component: () => import('../views/AboutView.vue'), + }, + ], +}); + +export default router; diff --git a/vue-tutorials/src/stores/counter.ts b/vue-tutorials/src/stores/counter.ts new file mode 100644 index 0000000..8fc7634 --- /dev/null +++ b/vue-tutorials/src/stores/counter.ts @@ -0,0 +1,12 @@ +import { defineStore } from 'pinia'; +import { computed, ref } from 'vue'; + +export const useCounterStore = defineStore('counter', () => { + const count = ref(0); + const doubleCount = computed(() => count.value * 2); + function increment() { + count.value++; + } + + return { count, doubleCount, increment }; +}); diff --git a/vue-tutorials/src/views/AboutView.vue b/vue-tutorials/src/views/AboutView.vue new file mode 100644 index 0000000..404cefe --- /dev/null +++ b/vue-tutorials/src/views/AboutView.vue @@ -0,0 +1,61 @@ + + + + + 子页面 + + childCount:{{ childCount }} + childCount2:{{ childCount2 }} + 时间戳:{{ timestamp }} + + + + diff --git a/vue-tutorials/src/views/HomeView.vue b/vue-tutorials/src/views/HomeView.vue new file mode 100644 index 0000000..149455e --- /dev/null +++ b/vue-tutorials/src/views/HomeView.vue @@ -0,0 +1,48 @@ + + + + + + 父页面 + + parentCount:{{ parentCount }} + parentCount2:{{ parentCount2 }} + + + + + + + diff --git a/vue-tutorials/tsconfig.app.json b/vue-tutorials/tsconfig.app.json new file mode 100644 index 0000000..913b8f2 --- /dev/null +++ b/vue-tutorials/tsconfig.app.json @@ -0,0 +1,12 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/vue-tutorials/tsconfig.json b/vue-tutorials/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/vue-tutorials/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/vue-tutorials/tsconfig.node.json b/vue-tutorials/tsconfig.node.json new file mode 100644 index 0000000..a83dfc9 --- /dev/null +++ b/vue-tutorials/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node22/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*", + "eslint.config.*" + ], + "compilerOptions": { + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/vue-tutorials/vite.config.ts b/vue-tutorials/vite.config.ts new file mode 100644 index 0000000..61899cd --- /dev/null +++ b/vue-tutorials/vite.config.ts @@ -0,0 +1,16 @@ +import { fileURLToPath, URL } from 'node:url'; + +import vue from '@vitejs/plugin-vue'; +import vueJsx from '@vitejs/plugin-vue-jsx'; +import { defineConfig } from 'vite'; +import vueDevTools from 'vite-plugin-vue-devtools'; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [vue(), vueJsx(), vueDevTools()], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, + }, +});
childCount:{{ childCount }}
childCount2:{{ childCount2 }}
时间戳:{{ timestamp }}
parentCount:{{ parentCount }}
parentCount2:{{ parentCount2 }}