提交 7e2a41d8 编写于 作者: 小傅哥's avatar 小傅哥

小傅哥,feat:架构的本质之 DDD 架构

上级
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/.idea/
/*.iml
/*/target/
/docs/.$mvc.drawio.bkp
/docs/.$xfg-frame-ddd.drawio.bkp
/docs/.$xfg-frame-ddd.drawio.dtmp
/*/*.iml
# xfg-frame-ddd
\ No newline at end of file
# /usr/local/bin/docker-compose -f /docs/dev-ops/environment/environment-docker-compose.yml up -d
version: '3'
services:
# MySQL 5.7
mysql:
image: mysql:5.7
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: road-map
MYSQL_USER: xfg
MYSQL_PASSWORD: 123456
ports:
- "3306:3306"
volumes:
- ./mysql-data:/var/lib/mysql
# Zookeeper
zookeeper:
image: 'zookeeper:3.7.1'
container_name: zookeeper
restart: always
ports:
- '2181:2181'
\ No newline at end of file
docker run --rm -t yokogawa/siege
\ No newline at end of file
# https://skywalking.apache.org/downloads/
version: '3.8'
services:
elasticsearch:
image: elasticsearch:7.16.2
container_name: elasticsearch
ports:
- "9200:9200"
healthcheck:
test: [ "CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
environment:
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
# volumes:
# - ./data/es_data:/usr/share/elasticsearch/data
oap:
image: apache/skywalking-oap-server:8.9.0
container_name: oap
depends_on:
elasticsearch:
condition: service_healthy
links:
- elasticsearch
ports:
- "11800:11800"
- "12800:12800"
healthcheck:
test: [ "CMD-SHELL", "/skywalking/bin/swctl ch" ]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
environment:
SW_STORAGE: elasticsearch
SW_STORAGE_ES_CLUSTER_NODES: elasticsearch:9200
SW_HEALTH_CHECKER: default
SW_TELEMETRY: prometheus
JAVA_OPTS: "-Xms1024m -Xmx1024m"
skywalking-ui:
image: apache/skywalking-ui:8.9.0
container_name: skywalking-ui
depends_on:
oap:
condition: service_healthy
links:
- oap
ports:
- "9090:8080"
environment:
SW_OAP_ADDRESS: http://oap:12800
\ No newline at end of file
https://skywalking.apache.org/downloads/
javaAgent https://archive.apache.org/dist/skywalking/java-agent/8.9.0/apache-skywalking-java-agent-8.9.0.tgz
\ No newline at end of file
/*
Navicat Premium Data Transfer
Source Server : 127.0.0.1
Source Server Type : MySQL
Source Server Version : 50639
Source Host : localhost:3306
Source Schema : road-map
Target Server Type : MySQL
Target Server Version : 50639
File Encoding : 65001
Date: 24/06/2023 09:01:16
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for rule_tree
-- ----------------------------
DROP TABLE IF EXISTS `rule_tree`;
CREATE TABLE `rule_tree` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tree_name` varchar(64) DEFAULT NULL COMMENT '规则树Id',
`tree_desc` varchar(128) DEFAULT NULL COMMENT '规则树描述',
`tree_root_node_id` bigint(20) DEFAULT NULL COMMENT '规则树根ID',
`create_time` datetime(3) DEFAULT NULL COMMENT '创建时间',
`update_time` datetime(3) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2110081903 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of rule_tree
-- ----------------------------
BEGIN;
INSERT INTO `rule_tree` VALUES (2110081902, '抽奖活动规则树', '用于决策不同用户可参与的活动', 1, '2021-10-08 15:38:05.000', '2021-10-08 15:38:05.000');
COMMIT;
-- ----------------------------
-- Table structure for rule_tree_node
-- ----------------------------
DROP TABLE IF EXISTS `rule_tree_node`;
CREATE TABLE `rule_tree_node` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tree_id` int(2) DEFAULT NULL COMMENT '规则树ID',
`node_type` int(2) DEFAULT NULL COMMENT '节点类型;1子叶、2果实',
`node_value` varchar(32) DEFAULT NULL COMMENT '节点值[nodeType=2];果实值',
`rule_key` varchar(16) DEFAULT NULL COMMENT '规则Key',
`rule_desc` varchar(32) DEFAULT NULL COMMENT '规则描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=123 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of rule_tree_node
-- ----------------------------
BEGIN;
INSERT INTO `rule_tree_node` VALUES (1, 2110081902, 1, NULL, 'userGender', '用户性别[男/女]');
INSERT INTO `rule_tree_node` VALUES (11, 2110081902, 1, NULL, 'userAge', '用户年龄');
INSERT INTO `rule_tree_node` VALUES (12, 2110081902, 1, NULL, 'userAge', '用户年龄');
INSERT INTO `rule_tree_node` VALUES (111, 2110081902, 2, '100001', NULL, NULL);
INSERT INTO `rule_tree_node` VALUES (112, 2110081902, 2, '100002', NULL, NULL);
INSERT INTO `rule_tree_node` VALUES (121, 2110081902, 2, '100003', NULL, NULL);
INSERT INTO `rule_tree_node` VALUES (122, 2110081902, 2, '100004', NULL, NULL);
COMMIT;
-- ----------------------------
-- Table structure for rule_tree_node_line
-- ----------------------------
DROP TABLE IF EXISTS `rule_tree_node_line`;
CREATE TABLE `rule_tree_node_line` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tree_id` bigint(20) DEFAULT NULL COMMENT '规则树ID',
`node_id_from` bigint(20) DEFAULT NULL COMMENT '节点From',
`node_id_to` bigint(20) DEFAULT NULL COMMENT '节点To',
`rule_limit_type` int(2) DEFAULT NULL COMMENT '限定类型;1:=;2:>;3:<;4:>=;5<=;6:enum[枚举范围];7:果实',
`rule_limit_value` varchar(32) DEFAULT NULL COMMENT '限定值',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of rule_tree_node_line
-- ----------------------------
BEGIN;
INSERT INTO `rule_tree_node_line` VALUES (1, 2110081902, 1, 11, 1, 'man');
INSERT INTO `rule_tree_node_line` VALUES (2, 2110081902, 1, 12, 1, 'woman');
INSERT INTO `rule_tree_node_line` VALUES (3, 2110081902, 11, 111, 3, '25');
INSERT INTO `rule_tree_node_line` VALUES (4, 2110081902, 11, 112, 4, '25');
INSERT INTO `rule_tree_node_line` VALUES (5, 2110081902, 12, 121, 3, '25');
INSERT INTO `rule_tree_node_line` VALUES (6, 2110081902, 12, 122, 4, '25');
COMMIT;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`user_id` varchar(9) DEFAULT NULL COMMENT '用户ID',
`user_nickname` varchar(32) DEFAULT NULL COMMENT '用户昵称',
`user_head` varchar(16) DEFAULT NULL COMMENT '用户头像',
`user_password` varchar(64) DEFAULT NULL COMMENT '用户密码',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES (1, '184172133', '小傅哥', '01_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (2, '980765512', '铁锤', '02_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (3, '796542178', '团团', '03_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (4, '523088136', '哈尼克兔', '04_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (5, '123456001', '比丘卡', '05_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (6, '123456002', '兰兰', '06_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (7, '123456003', 'Alexa', '07_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (8, '123456004', '小白', '08_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (9, '123456005', '铃铛', '09_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (10, '123456006', '马小帅', '10_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (11, '123456007', 'S.A.K', '11_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
INSERT INTO `user` VALUES (12, '123456008', '池鱼有点贤', '12_50', '123456', '2023-06-23 00:00:00', '2023-06-23 00:00:00');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;
<mxfile host="Electron" modified="2023-06-24T04:05:28.008Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.2.8 Chrome/102.0.5005.167 Electron/19.0.15 Safari/537.36" etag="Xu8Jq-ApcfE7csYkc3od" version="20.2.8" type="device" pages="2"><diagram id="Ur8uAWgRvAvGvvzBFZs2" name="1. 抽象">3VnbcpswEP0aPWZGIK6PgEnTadKmTaaXp44CsqGREcEidvr1lUAYE+w0nYIv8XjG0tmVEHv2rBAGKJiv3hU4T65YTCjQYbwCaAJ0XdMcS/xI5KlGbGTXwKxI4xqCLXCT/iZqZIOWaUwWCqshzhjlad4FI5ZlJOIdDBcFW3bdpozGHSDHM9IDbiJM++i3NOZJjboQtvgFSWdJc2Wrscxx46yARYJjttyAUAhQUDDG69Z8FRAqg9eNy/kO63phBcn4awYU762PhpvgqzyaGMaP+yiI8Jli5xHTUt2wWix/aiJAYhEQ1WUFT9iMZZiGLeoXrMxiIi8DRa/1uWQsF6AmwF+E8yfFLi45E1DC51RZpyzjyqgZol+vQV54570qaMHKIiIv3KChcgYXM8Jf8DPXjIhUJmxOePEkxhWEYp4+dteBVU7N1n5t2EVDRf4fWDB6LHgRZ0WPCpFCuWyWc1o7IP+RFDwV6XqJ7wi9ZouUpywTLneMczbfcPBoOpMGLjnZDD4rOU0zEqwFBHcyIuciq5c56cdQDbBQPUIVAt0w6/6ylRVSUkk2FGXBkYLuvvXUN1+Z+vYhU9/ssxA6wLOBZ4HQBM45cLUeL23UZQiXScrJTY6rYCzFNrQ7wnbTV3NV9pTSgFGpJjE3gtDBUJK54AW7Jx2LacNGHBv4tPoMIxLNdP+qEk3fp0yajfjt6sR+pU6cQ+rE3qITIQ8b+BMQWsA1gQ97vIypkynECOK+GmD12aYff2LXlgF0ggznyHTibC1kvqhfoSTICYFn7pUgYmrGi+WqT5AOByPIbJ7zj4YgTdtSyCzKVYQ6xFgPJWsMZ4sq5p5w0Ix8VYWnsYvWTP5+uQ6aucTa6ulqy7CUj7DDIOS+jpjGb3hi9J3ELHKc/RcxF7e31xvM1POdCjPOwZlB40nm6vOpKsY4vGL6B8bBFHPr3Xw4VcUYh1fMtvNMs/vX5xkPDRfHgY7mzzfrI9gTtr2YGijD2+dlycwEeKFkxveAi0ZP/LEIO3zib3mdEorTSSCjKsLrTYDrHH0cD1/a9d1PqcMkfiBTXlYiD3jaqRT658c9hKz98fTJp3r09cL6vPpucP0BxdrP8mxUmlzgim9Vn3zB1OnStM+ytJWmEY8WVXnz5AlfNDwHOJW+fA148FT5Mgx9NL5Et/2vq7Jt/GOIwj8=</diagram><diagram id="leyuxY2PdF12CoQSAcOc" name="2. 架构">7Vxbc5s4FP41ekwGSSDEIzhOu7PtTNrsbptHDNimxZaLcWP3168EwtzkS4IxdptOpoYjIbC+c75zQTLAg9n6Xewuph+ZH0QAaf4a4DuAEISU8A8h2WQSE5uZYBKHfibSCsFj+CuQV+bSVegHSynLRAljURIuqkKPzeeBl1Rkbhyz52q3MYv8imDhToKG4NFzo6b0S+gn00xqaVohfx+Ek2l+Z5K3zNy8sxQsp67PnksiPAR4EDOWZEez9SCIxORV5+V+R+v2weJgnhxzwbvB+vHrr4H/V/A0+/j09cdmOvj3xspG+elGK/mF5cMmm3wGYraa+4EYBALsPE/DJHhcuJ5ofeaYc9k0mUWyeczmyb07CyMB94DNQo8P9ujOl/zj46PsIFGGujgPo2jAIhZzwZzNudxxY0/2MPmZ7y6n27vLpw3iJFjvnAa4nVyulQGbBUm84V3kBTqWeEiFNHSanT8X8OoGzmTTErSWnBpXatRkO3Qx6fxAzrsag5vHT4Pv3v0X69t/znD64+/PC828QQoMSJTIyRJKm802l/5YCW1xmhO7beJHE/G5Hk9uxrE7C27cRZiPxx8vGzLr0x7qMpIFbNx2q8AChEdagAPC5cskZt+DUosWUI3S04CLEK2ACwlsgAtzwMvgGp2BixuzHPicYeQpi5Mpm7C5Gw0LqVPgIGay6POBsYWc/W9BkmzkfLurhFWxCdZh8rV0/CSGujXk2d1ajpyebPKTOf++24vESekqcVpclp7l173Y5LMJEbOwH2U+aWwVS9VXz64uPYIbT4JkTz9TrTVxELlJ+LP6HCoVSC+149jdlDosWDhPlqWRH4SgUEaSjyiVEZk1gj7Q34BWTf2yJyiUcftVWuin3mSfoQEcG1g6GJrif5uCIQW2CWwimug9sCAY3gNnAOhASCwN2Pdpk512JsDiTXe5BCot4IM74qFCRWvdKJzM+bHH9SDg7OAILgi5L7Zlwyz0/cxAgmX4yx2l4wkdlFDwwQ0HGHcqP3NIS3eyj4ws5N0Kf17W1z2mv5OrbrRbQmmVryQLvUwvC0XaKC9g4/GSW0edyU6gPArdOa3nWlyA5xq7vuUbKs/lBjrEqBvPhXS9Z89ldAuuz2ZuOL8MfE3XU+E70omh6d3gi5HZM77wiNj/ykIV85JjFXJkrGLs1SPtFiJCXuMmXhq+6KiaKOmY7A1f6v0xITUdLYUvxdXde6n8ueohzgBYRhHiIC1nJC1thYCiSpRjD4E1FP3pEDi8jw4cB1g4jXLQW9xTJ5Z9cY+G4atUuKFz1YD5hp4r8CHd+sZwzj+5O1p5ySoOLsBHjlyP+ljlIxHWdcPvxkfqeRGwPx9JLsclmr9f+m4e6RKRWm06Tt8NUtFGA6O9/q/eH1Jzt/87FRFBU+nbar6Kf2lRBMycFk/l7xqOzU6bLECt1CPagPL0Q/v8MEivImIc25DZv60uaf0Bjo0cCM0wJjWP1DKhz4mxMuj58nukDmF6oT/0OvpDvwP/7UgJuuU/Q8dV/tP2x//1/ljXQOf8l5vGgfJlIzIv8x8nSArTEicG1BAHQoJLqcEfyXYHgjUexkN81dVL1GtwV9Q4nkotanK7Bo6iLTmqVZyuiIJOmY8lcTiZcJPuPxELsEe1XCXKL1HTf6oEzdEsI23ZyRAtEjRLUn5vCRrtGPjNIlheAOzjsedZlgpeTLCFO8q/DZP0DC9SpTeNbKSZw9Sh4XOSdOesBckvJXgNjOSiFsU6lxf7+PQC+aXgCfCGhl7BG5ro1mggbupNwJHVFeAKg1bEc42g7Q3w1wCODKNvwLGqOG8BGwGarjaw7sXf4dL6G+DHAI4x7R1wqAA8xZkbObdwji3VUsMeAmeYIk+Ac/cG+KsA1xHsHXBVit5cT3Qw634D/BjADU3vHXCspHRu1ZZd8uGmeMfqOKnxDwFtxtNvgB8FODV7B1y1VGhncvTKukmfNRB87DpT1GsVBDdfS/vM+y4KF9o3N25g8mfUMfH+BTWijgmJVY2LwVUVMnP1LOFuewlrAr6cugtxuJpFWYcC21QPHjgjJiETGI9YkrCZAvyE1SoZbJVE4ZxTZ74Bp0XFsl35orbcWm+uHsizjTItEq29OSr31uwvL0t/0sv6uTNxqXJW8k1cJSpV9kNnYlL1Q+5/8Xlq7LQXYKd+0bk9OcVbTnRaxK0jnWfbTRrtEFeEMK0Lyen6ifMXj0/ApTquekRVKZh2VAlW4mNeLJluDVIDl7jwaje5HkHCO3awnMckFXWD9ib5/p9/Hq7UJg2jtiCjb5tUr4y4BJvs07bwkbal92lbihJNe9v6+OlKLYsQ87Isq5ONdXLLQlZyk29RrhIuk8LLggsqXmJV8VrmP2yRgwLL+JTmugRaHT454kjZX9znJruLzTtAtFirR1GU3rNXLJbcFMOFhVqM6nc/pCq/R9H2FJyCcF6X3f7SRLNOm2/lOnWdVq2m561ItM9qTxxEnzivhYooupPlu+1AV4XR3fB7R95YtVUWaWfld9UbLSLeYomlxLveX3W6HiwgnnLPsm9ao1Mt9yNmDQisi11IdSwMBRSY5OR3+rRQa8x0b8t2teNIrcRjT+W2SyQ1xauuPTZx7k0JplkN/TDc/5sqpkb29W+9KWHvHFboorRdWKxma+6hunq6MHV0gXQB91cpOqcLdPwy/xJfoAphXHJ1HxrHEkavBY/81y76UgPzVWrwG2pBL26DGlW3oWvoRW6j1r8jt6FYRnN44evVuw2qnTfK5KfFj25m2BU/XYqH/wM=</diagram></mxfile>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.bugstack</groupId>
<artifactId>xfg-frame-ddd</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>xfg-frame-api</module>
<module>xfg-frame-app</module>
<module>xfg-frame-domain</module>
<module>xfg-frame-trigger</module>
<module>xfg-frame-infrastructure</module>
<module>xfg-frame-types</module>
</modules>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.12</version>
<relativePath/>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!-- # 多数据源路由配置
# mysql 5.x driver-class-name: com.mysql.jdbc.Driver mysql-connector-java 5.1.34
# mysql 8.x driver-class-name: com.mysql.cj.jdbc.Driver mysql-connector-java 8.0.22-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.28</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.curator/curator-x-discovery -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-x-discovery</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
<!-- skywalking 日志追踪 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
<version>8.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>8.1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>xfg-frame</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- 统一设定POM版本信息插件 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.7</version>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<profileActive>dev</profileActive>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<profileActive>test</profileActive>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<profileActive>prod</profileActive>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.codehaus.mojo</groupId>
<artifactId>extra-enforcer-rules</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>enforce-banned-dependencies-app</id>
<phase>install</phase>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<searchTransitive>true</searchTransitive>
<excludes>
<exclude>*:*:[,0.0.1)</exclude>
</excludes>
</bannedDependencies>
</rules>
<fail>true</fail>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>xfg-frame-ddd</artifactId>
<groupId>cn.bugstack</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>xfg-frame-api</artifactId>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>cn.bugstack</groupId>
<artifactId>xfg-frame-types</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<finalName>xfg-frame-api</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.bugstack.xfg.frame.api;
public interface IAccountService {
String queryUserName(String req);
}
\ No newline at end of file
package cn.bugstack.xfg.frame.api;
import cn.bugstack.xfg.frame.api.model.request.DecisionMatterRequest;
import cn.bugstack.xfg.frame.api.model.response.DecisionMatterResponse;
import cn.bugstack.xfg.frame.types.Response;
/**
* @author 小傅哥,微信:fustack
* @description 规则服务
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public interface IRuleService {
Response<DecisionMatterResponse> doRule(DecisionMatterRequest request);
}
package cn.bugstack.xfg.frame.api.model.request;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
/**
* @author 小傅哥,微信:fustack
* @description 决策请求对象
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DecisionMatterRequest {
/**
* 规则树ID
*/
private Long treeId;
/**
* 用户ID
*/
private String userId;
/**
* 决策值
*/
private Map<String, Object> valMap;
}
package cn.bugstack.xfg.frame.api.model.response;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 小傅哥,微信:fustack
* @description 决策结果
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class DecisionMatterResponse {
/** 活动ID */
private Long activityId;
}
/**
* RPC 接口网关定义
*/
package cn.bugstack.xfg.frame.api;
\ No newline at end of file
# 基础镜像
FROM openjdk:8-jre-slim
# 作者
MAINTAINER xiaofuge
# 配置
ENV PARAMS=""
# 时区
ENV TZ=PRC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 添加应用
ADD /target/xfg-frame-app.jar /xfg-frame-app.jar
## 在镜像运行为容器后执行的命令
ENTRYPOINT ["java", "-Xmx512m", "-javaagent:/Users/fuzhengwei1/Documents/develop/skywalking/skywalking-agent-8-9/skywalking-agent.jar", "-Dskywalking.agent.service_name=xfg-frame", "-Dskywalking.collector.backend_service=10.253.3.8:11800", "-jar", "/xfg-frame-app.jar"]
\ No newline at end of file
docker build -f ./Dockerfile -t fuzhengwei/xfg-frame-app:1.3 .
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>xfg-frame-ddd</artifactId>
<groupId>cn.bugstack</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>xfg-frame-app</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- # 多数据源路由配置
# mysql 5.x driver-class-name: com.mysql.jdbc.Driver mysql-connector-java 5.1.34
# mysql 8.x driver-class-name: com.mysql.cj.jdbc.Driver mysql-connector-java 8.0.22-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-x-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- skywalking 日志追踪 -->
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-logback-1.x</artifactId>
</dependency>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 自身模块 begin -->
<dependency>
<groupId>cn.bugstack</groupId>
<artifactId>xfg-frame-trigger</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.bugstack</groupId>
<artifactId>xfg-frame-infrastructure</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 自身模块 end -->
</dependencies>
<build>
<finalName>xfg-frame-app</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.6</version>
<configuration>
<skipTests>true</skipTests>
<testFailureIgnore>false</testFailureIgnore>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>cn.bugstack.xfg.frame.Application</mainClass>
<layout>JAR</layout>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
CONTAINER_NAME=xfg-frame
IMAGE_NAME=fuzhengwei/xfg-frame-app:1.3
PORT=8090
echo "容器部署开始 ${CONTAINER_NAME}"
# 停止容器
docker stop ${CONTAINER_NAME}
# 删除容器
docker rm ${CONTAINER_NAME}
# 启动容器 skywalking-agent 下载:https://archive.apache.org/dist/skywalking/java-agent/8.9.0/apache-skywalking-java-agent-8.9.0.tgz
docker run --name ${CONTAINER_NAME} \
-p ${PORT}:${PORT} \
-v /Users/fuzhengwei1/Documents/develop/skywalking/skywalking-agent-8-9/:/Users/fuzhengwei1/Documents/develop/skywalking/skywalking-agent-8-9/ \
-d ${IMAGE_NAME}
echo "容器部署成功 ${CONTAINER_NAME}"
docker logs -f ${CONTAINER_NAME}
\ No newline at end of file
docker stop xfg-frame-app
\ No newline at end of file
package cn.bugstack.xfg.frame;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* -javaagent:/Users/fuzhengwei1/Documents/develop/skywalking/skywalking-agent-8-9/skywalking-agent.jar -Dskywalking.agent.service_name=xfg-frame-test -Dskywalking.collector.backend_service=127.0.0.1:11800
*/
@SpringBootApplication
@Configurable
@EnableDubbo
public class Application {
public static void main(String[] args){
SpringApplication.run(Application.class);
}
}
package cn.bugstack.xfg.frame.aop;
import cn.bugstack.xfg.frame.types.Constants;
import cn.bugstack.xfg.frame.types.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.shaded.com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
@Slf4j
@Aspect
public class RateLimiterAop {
private final long timeout;
private final double permitsPerSecond;
private final RateLimiter limiter;
public RateLimiterAop(double permitsPerSecond, long timeout) {
this.permitsPerSecond = permitsPerSecond;
this.timeout = timeout;
this.limiter = RateLimiter.create(permitsPerSecond);
}
@Pointcut("execution(* cn.bugstack.xfg.frame.trigger..*.*(..))")
public void pointCut() {
}
@Around(value = "pointCut()", argNames = "jp")
public Object around(ProceedingJoinPoint jp) throws Throwable {
boolean tryAcquire = limiter.tryAcquire(timeout, TimeUnit.MILLISECONDS);
if (!tryAcquire) {
Method method = getMethod(jp);
log.warn("方法 {}.{} 请求已被限流,超过限流配置[{}/秒]", method.getDeclaringClass().getCanonicalName(), method.getName(), permitsPerSecond);
return Response.<Object>builder()
.code(Constants.ResponseCode.RATE_LIMITER.getCode())
.info(Constants.ResponseCode.RATE_LIMITER.getInfo())
.build();
}
return jp.proceed();
}
private Method getMethod(JoinPoint jp) throws NoSuchMethodException {
Signature sig = jp.getSignature();
MethodSignature methodSignature = (MethodSignature) sig;
return jp.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
}
}
\ No newline at end of file
/**
* 统一切面管理
*/
package cn.bugstack.xfg.frame.aop;
\ No newline at end of file
package cn.bugstack.xfg.frame.config;
import cn.bugstack.xfg.frame.aop.RateLimiterAop;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.shaded.com.google.common.util.concurrent.RateLimiter;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
@EnableAsync
@Configuration
@EnableConfigurationProperties(RateLimiterAopConfigProperties.class)
public class RateLimiterAopConfig {
@Bean
@ConditionalOnMissingBean(RateLimiterAop.class)
public RateLimiterAop rateLimiterAop(RateLimiterAopConfigProperties properties) {
return new RateLimiterAop(properties.getPermitsPerSecond(), properties.getTimeout());
}
}
package cn.bugstack.xfg.frame.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "rate-limiter", ignoreInvalidFields = true)
public class RateLimiterAopConfigProperties {
/** 最大调用次数 */
private double permitsPerSecond;
/** 超时等待时间 */
private long timeout;
}
package cn.bugstack.xfg.frame.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.*;
@Slf4j
@EnableAsync
@Configuration
@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
public class ThreadPoolConfig {
@Bean
@ConditionalOnMissingBean(ThreadPoolExecutor.class)
public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties properties) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
// 实例化策略
RejectedExecutionHandler handler;
switch (properties.getPolicy()){
case "AbortPolicy":
handler = new ThreadPoolExecutor.AbortPolicy();
break;
case "DiscardPolicy":
handler = new ThreadPoolExecutor.DiscardPolicy();
break;
case "DiscardOldestPolicy":
handler = new ThreadPoolExecutor.DiscardOldestPolicy();
break;
case "CallerRunsPolicy":
handler = new ThreadPoolExecutor.CallerRunsPolicy();
break;
default:
handler = new ThreadPoolExecutor.AbortPolicy();
break;
}
// 创建线程池
return new ThreadPoolExecutor(properties.getCorePoolSize(),
properties.getMaxPoolSize(),
properties.getKeepAliveTime(),
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(properties.getBlockQueueSize()),
Executors.defaultThreadFactory(),
handler);
}
}
package cn.bugstack.xfg.frame.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Data
@ConfigurationProperties(prefix = "thread.pool.executor.config", ignoreInvalidFields = true)
public class ThreadPoolConfigProperties {
/** 核心线程数 */
private Integer corePoolSize = 20;
/** 最大线程数 */
private Integer maxPoolSize = 200;
/** 最大等待时间 */
private Long keepAliveTime = 10L;
/** 最大队列数 */
private Integer blockQueueSize = 5000;
/*
* AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
* DiscardPolicy:直接丢弃任务,但是不会抛出异常
* DiscardOldestPolicy:将最早进入队列的任务删除,之后再尝试加入队列的任务被拒绝
* CallerRunsPolicy:如果任务添加线程池失败,那么主线程自己执行该任务
* */
private String policy = "AbortPolicy";
}
/**
* 配置启动项
*/
package cn.bugstack.xfg.frame.config;
server:
port: 8091
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/road-map?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true
driver-class-name: com.mysql.jdbc.Driver
mybatis:
mapper-locations: classpath:/mybatis/mapper/*.xml
config-location: classpath:/mybatis/config/mybatis-config.xml
# 线程池配置
thread:
pool:
executor:
config:
core-pool-size: 20
max-pool-size: 200
keep-alive-time: 10
block-queue-size: 5000
policy: CallerRunsPolicy
# 限流配置
rate-limiter:
permits-per-second: 1
timeout: 5
# Dubbo
dubbo:
application:
name: xfg-frame-dev
version: 1.0.0
registry:
address: zookeeper://127.0.0.1:2181
protocol:
name: dubbo
port: 20881
scan:
base-packages: cn.bugstack.xfg.frame.api
# 日志
logging:
level:
root: info
config: classpath:logback-spring.xml
\ No newline at end of file
server:
port: 8093
dubbo:
application:
name: xfg-frame
version: 1.0.0
registry:
address: zookeeper://127.0.0.1:9181
protocol:
name: dubbo
port: 20881
scan:
base-packages: cn.bugstack.xfg.frame.api
logging:
level:
root: info
config: classpath:logback-spring.xml
\ No newline at end of file
server:
port: 8092
dubbo:
application:
name: xfg-frame
version: 1.0.0
registry:
address: zookeeper://192.168.1.100:9181
protocol:
name: dubbo
port: 20881
scan:
base-packages: cn.bugstack.xfg.frame.api
logging:
level:
root: info
config: classpath:logback-spring.xml
\ No newline at end of file
spring:
config:
name: xfg-frame
profiles:
active: dev
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<configuration scan="true" scanPeriod="10 seconds">
<contextName>logback</contextName>
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
<springProperty scope="context" name="log.path" source="logging.path"/>
<!-- 日志格式 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<!-- 输出到控制台 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- 此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>
%black(%d{ISO8601}) [%tid] %highlight(${LOG_LEVEL_PATTERN:-%5p}) [%blue(%t)] %yellow(%C{1.}):%msg%n%throwable
</Pattern>
</layout>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 增加配置日志收集 -->
<appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern>
</layout>
</encoder>
</appender>
<!--输出到文件-->
<!-- 时间滚动输出 level为 INFO 日志 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>./data/log/xfg-frame/log_info.log</file>
<!--日志文件输出格式-->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>
%black(%d{ISO8601}) [%tid] %highlight(${LOG_LEVEL_PATTERN:-%5p}) [%blue(%t)] %yellow(%C{1.}):
%msg%n%throwable
</Pattern>
</layout>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天日志归档路径以及格式 -->
<fileNamePattern>./data/log/xfg-frame/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!--日志文件保留天数-->
<maxHistory>15</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
</appender>
<!-- 时间滚动输出 level为 ERROR 日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>./data/log/xfg-frame/log_error.log</file>
<!--日志文件输出格式-->
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<Pattern>
%black(%d{ISO8601}) [%tid] %highlight(${LOG_LEVEL_PATTERN:-%5p}) [%blue(%t)] %yellow(%C{1.}):
%msg%n%throwable
</Pattern>
</layout>
<charset>UTF-8</charset>
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>./data/log/xfg-frame/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 日志文件保留天数【根据服务器预留,可自行调整】 -->
<maxHistory>7</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
<!-- WARN 级别及以上 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
</appender>
<!-- 异步输出 -->
<appender name="ASYNC_FILE_INFO" class="ch.qos.logback.classic.AsyncAppender">
<!-- 队列剩余容量小于discardingThreshold,则会丢弃TRACT、DEBUG、INFO级别的日志;默认值-1,为queueSize的20%;0不丢失日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>8192</queueSize>
<!-- neverBlock:true 会丢失日志,但业务性能不受影响 -->
<neverBlock>true</neverBlock>
<!--是否提取调用者数据-->
<includeCallerData>false</includeCallerData>
<appender-ref ref="INFO_FILE"/>
</appender>
<appender name="ASYNC_FILE_ERROR" class="ch.qos.logback.classic.AsyncAppender">
<!-- 队列剩余容量小于discardingThreshold,则会丢弃TRACT、DEBUG、INFO级别的日志;默认值-1,为queueSize的20%;0不丢失日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>1024</queueSize>
<!-- neverBlock:true 会丢失日志,但业务性能不受影响 -->
<neverBlock>true</neverBlock>
<!--是否提取调用者数据-->
<includeCallerData>false</includeCallerData>
<appender-ref ref="ERROR_FILE"/>
</appender>
<!-- 开发环境:控制台打印 -->
<springProfile name="dev">
<logger name="com.nmys.view" level="debug"/>
</springProfile>
<root level="info">
<appender-ref ref="CONSOLE"/>
<!-- 增加配置日志收集 -->
<appender-ref ref="grpc-log"/>
<!-- 异步日志-INFO -->
<appender-ref ref="ASYNC_FILE_INFO"/>
<!-- 异步日志-ERROR -->
<appender-ref ref="ASYNC_FILE_ERROR"/>
</root>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 暂时未使用 文档:https://mybatis.org/mybatis-3/zh/configuration.html#typeAliases -->
<typeAliases>
</typeAliases>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bugstack.xfg.frame.infrastructure.dao.RuleTreeNodeLineDao">
<resultMap id="ruleTreeNodeLineResultMap" type="cn.bugstack.xfg.frame.infrastructure.po.RuleTreeNodeLineVO">
<id column="id" property="id"/>
<result column="tree_id" property="treeId"/>
<result column="node_id_from" property="nodeIdFrom"/>
<result column="node_id_to" property="nodeIdTo"/>
<result column="rule_limit_type" property="ruleLimitType"/>
<result column="rule_limit_value" property="ruleLimitValue"/>
</resultMap>
<select id="queryRuleTreeNodeLineList" resultMap="ruleTreeNodeLineResultMap">
SELECT id, tree_id, node_id_from, node_id_to, rule_limit_type, rule_limit_value
FROM rule_tree_node_line
where tree_id = #{treeId} and node_id_from = #{nodeIdFrom}
</select>
<select id="queryTreeNodeLineCount" resultType="java.lang.Integer">
select count(id) from rule_tree_node_line where tree_id = #{treeId}
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bugstack.xfg.frame.infrastructure.dao.RuleTreeNodeDao">
<resultMap id="ruleTreeNodeMap" type="cn.bugstack.xfg.frame.infrastructure.po.RuleTreeNodeVO">
<id column="id" property="id"/>
<result column="tree_id" property="treeId"/>
<result column="node_type" property="nodeType"/>
<result column="node_value" property="nodeValue"/>
<result column="rule_key" property="ruleKey"/>
<result column="rule_desc" property="ruleDesc"/>
</resultMap>
<select id="queryRuleTreeNodeList" resultMap="ruleTreeNodeMap">
SELECT id, tree_id, node_type, node_value, rule_key, rule_desc
FROM rule_tree_node
where tree_id = #{treeId}
</select>
<select id="queryTreeNodeCount" resultType="java.lang.Integer">
select count(id) from rule_tree_node where tree_id = #{treeId}
</select>
<select id="queryTreeRulePoint" resultMap="ruleTreeNodeMap">
SELECT distinct (rule_key), rule_desc
FROM rule_tree_node
where tree_id = #{treeId} and rule_key is not null
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bugstack.xfg.frame.infrastructure.dao.RuleTreeDao">
<resultMap id="ruleTreeMap" type="cn.bugstack.xfg.frame.infrastructure.po.RuleTreeVO">
<id column="id" property="id"/>
<result column="tree_name" property="treeName"/>
<result column="tree_desc" property="treeDesc"/>
<result column="tree_root_node_id" property="treeRootNodeId"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<select id="queryRuleTreeByTreeId" resultMap="ruleTreeMap">
SELECT id, tree_name, tree_desc, tree_root_node_id, create_time, update_time
FROM rule_tree
where id = #{id}
</select>
<select id="queryTreeSummaryInfo" resultMap="ruleTreeMap">
SELECT id, tree_name, tree_desc
FROM rule_tree
where id = #{id}
</select>
</mapper>
package cn.bugstack.xfg.frame.test;
import cn.bugstack.xfg.frame.domain.rule.model.entity.DecisionMatterEntity;
import cn.bugstack.xfg.frame.domain.rule.model.entity.EngineResultEntity;
import cn.bugstack.xfg.frame.domain.rule.service.engine.EngineFilter;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.util.HashMap;
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApiTest {
@Resource
private EngineFilter engineFilter;
@Test
public void test_process() {
DecisionMatterEntity req = new DecisionMatterEntity();
req.setTreeId(2110081902L);
req.setUserId("fustack");
req.setValMap(new HashMap<String, Object>() {{
put("gender", "man");
put("age", "25");
}});
EngineResultEntity res = engineFilter.process(req);
log.info("请求参数:{}", JSON.toJSONString(req));
log.info("测试结果:{}", JSON.toJSONString(res));
}
}
package cn.bugstack.xfg.frame.test;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.rpc.service.GenericService;
/**
* @author 小傅哥,微信:fustack
* @description
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public class RpcTest {
/**
* https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/generic-reference/
* @param args
*/
public static void main(String[] args) {
ApplicationConfig application = new ApplicationConfig();
application.setName("xfg-frame");
application.setQosEnable(false);
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://127.0.0.1:2181");
registry.setRegister(false);
ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
reference.setInterface("cn.bugstack.xfg.frame.api.IAccountService");
reference.setVersion("1.0.0");
reference.setGeneric("true");
DubboBootstrap bootstrap = DubboBootstrap.getInstance();
bootstrap.application(application)
.registry(registry)
.reference(reference)
.start();
//获取服务,由于是泛化调用,所以获取的一定是GenericService类型
GenericService genericService = reference.get();
while (true){
Object user = genericService.$invoke("queryUserName", new String[]{"java.lang.String"}, new Object[]{"world"});
System.out.println(user);
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>xfg-frame-ddd</artifactId>
<groupId>cn.bugstack</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>xfg-frame-domain</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 自身模块 begin -->
<dependency>
<groupId>cn.bugstack</groupId>
<artifactId>xfg-frame-types</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 自身模块 end -->
</dependencies>
<build>
<finalName>xfg-frame-domain</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerVersion>${java.version}</compilerVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.bugstack.xfg.frame.domain.order.model.aggregates;
import cn.bugstack.xfg.frame.domain.order.model.entity.OrderItemEntity;
import cn.bugstack.xfg.frame.domain.order.model.valobj.OrderIdVO;
import java.util.List;
/**
* @author 小傅哥,微信:fustack
* @description 订单聚合对象
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public class OrderAggregate {
private OrderIdVO orderId;
private List<OrderItemEntity> items;
}
package cn.bugstack.xfg.frame.domain.order.model.entity;
/**
* @author 小傅哥,微信:fustack
* @description 订单条目实体
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public class OrderItemEntity {
}
package cn.bugstack.xfg.frame.domain.order.model.entity;
import cn.bugstack.xfg.frame.domain.order.model.valobj.ProductDescriptionVO;
import cn.bugstack.xfg.frame.domain.order.model.valobj.ProductNameVO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 小傅哥,微信:fustack
* @description 产品实体
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductEntity {
private ProductNameVO product;
private ProductDescriptionVO productDescription;
}
/**
* 模型;valobj - 值对象、entity - 实体、aggregate - 聚合根
*
* DDD中,值对象、实体对象和聚合根对象的定义是根据业务领域的语义来进行的。
* 一般来说,实体对象表示具有唯一标识的业务实体,例如订单、商品、用户等;
* 聚合根对象是一组相关的实体对象的根,用于保证实体对象之间的一致性和完整性;
* 而值对象则表示没有唯一标识的业务实体,例如商品的名称、描述、价格等。
*
* 在DDD中,聚合是一个有边界的事物集合,它包含了一个聚合根和一些相关的实体和值对象。聚合根是聚合的入口点,它定义了聚合的边界,并负责保护聚合内的不变量。聚合内的实体和值对象则是聚合根的子对象,它们只能通过聚合根来访问。
* 在聚合中,逻辑应该是与聚合根相关的业务逻辑,而不是将所有的服务功能都放到聚合对象中。聚合对象应该包含与聚合根相关的操作和规则,例如聚合根的创建、修改和删除等操作,以及聚合根的不变量验证等规则。聚合对象还可以包含一些与聚合根相关的查询操作,但是这些查询操作应该是只读的,不应该对聚合根的状态进行修改。
* 至于服务功能,它们可以被实现为应用服务或领域服务,它们可以与聚合对象协同工作,但不应该被包含在聚合对象中。应用服务和领域服务可以调用聚合对象来完成业务逻辑,但是它们不应该直接修改聚合根的状态。
*/
package cn.bugstack.xfg.frame.domain.order.model;
\ No newline at end of file
package cn.bugstack.xfg.frame.domain.order.model.valobj;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 小傅哥,微信:fustack
* @description
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderIdVO {
private String orderId;
}
package cn.bugstack.xfg.frame.domain.order.model.valobj;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 小傅哥,微信:fustack
* @description 产品明细值信息
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductDescriptionVO {
private String description;
}
package cn.bugstack.xfg.frame.domain.order.model.valobj;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 小傅哥,微信:fustack
* @description 产品值信息
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductNameVO {
private String name;
}
package cn.bugstack.xfg.frame.domain.order.repository;
/**
* @author 小傅哥,微信:fustack
* @description
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public interface IOrderRepository {
}
/**
* 仓储接口
*/
package cn.bugstack.xfg.frame.domain.order.repository;
\ No newline at end of file
package cn.bugstack.xfg.frame.domain.order.service;
import org.springframework.stereotype.Service;
/**
* @author 小傅哥,微信:fustack
* @description
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Service
public class OrderService {
}
/**
* 具体业务实现
*/
package cn.bugstack.xfg.frame.domain.order.service;
\ No newline at end of file
package cn.bugstack.xfg.frame.domain.rule.model.aggregates;
import cn.bugstack.xfg.frame.domain.rule.model.valobj.TreeNodeVO;
import cn.bugstack.xfg.frame.domain.rule.model.valobj.TreeRootVO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
/**
* @description: 规则树聚合
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TreeRuleAggregate {
/** 树根信息 */
private TreeRootVO treeRoot;
/** 树节点ID -> 子节点 */
private Map<Long, TreeNodeVO> treeNodeMap;
}
package cn.bugstack.xfg.frame.domain.rule.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Map;
/**
* @author 小傅哥,微信:fustack
* @description 决策物料实体
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class DecisionMatterEntity {
/**
* 规则树ID
*/
private Long treeId;
/**
* 用户ID
*/
private String userId;
/**
* 决策值
*/
private Map<String, Object> valMap;
}
package cn.bugstack.xfg.frame.domain.rule.model.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 决策结果实体
* @author: 小傅哥,微信:fustack
* @date: 2021/10/8
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class EngineResultEntity {
/** 执行结果 */
private boolean isSuccess;
/** 用户ID */
private String userId;
/** 规则树ID */
private Long treeId;
/** 果实节点ID */
private Long nodeId;
/** 果实节点值 */
private String nodeValue;
public EngineResultEntity(String userId, Long treeId, Long nodeId, String nodeValue) {
this.isSuccess = true;
this.userId = userId;
this.treeId = treeId;
this.nodeId = nodeId;
this.nodeValue = nodeValue;
}
}
/**
* 模型;vo、dto、entity、aggregate
*/
package cn.bugstack.xfg.frame.domain.rule.model;
\ No newline at end of file
package cn.bugstack.xfg.frame.domain.rule.model.valobj;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 规则树线信息
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TreeNodeLineVO {
/** 节点From */
private Long nodeIdFrom;
/** 节点To */
private Long nodeIdTo;
/** 限定类型;1:=;2:>;3:<;4:>=;5<=;6:enum[枚举范围] */
private Integer ruleLimitType;
/** 限定值 */
private String ruleLimitValue;
}
package cn.bugstack.xfg.frame.domain.rule.model.valobj;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @description: 规则树节点信息
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TreeNodeVO {
/** 规则树ID */
private Long treeId;
/** 规则树节点ID */
private Long treeNodeId;
/** 节点类型;1子叶、2果实 */
private Integer nodeType;
/** 节点值[nodeType=2];果实值 */
private String nodeValue;
/** 规则Key */
private String ruleKey;
/** 规则描述 */
private String ruleDesc;
/** 节点链路 */
private List<TreeNodeLineVO> treeNodeLineInfoList;
}
package cn.bugstack.xfg.frame.domain.rule.model.valobj;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 规则树根配置
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TreeRootVO {
/** 规则树ID */
private Long treeId;
/** 规则树根ID */
private Long treeRootNodeId;
/** 规则树名称 */
private String treeName;
}
package cn.bugstack.xfg.frame.domain.rule.repository;
import cn.bugstack.xfg.frame.domain.rule.model.aggregates.TreeRuleAggregate;
/**
* @description: 规则信息仓储服务接口
* @author: 小傅哥,微信:fustack
* @date: 2021/10/8
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public interface IRuleRepository {
/**
* 查询规则决策树配置
*
* @param treeId 决策树ID
* @return 决策树配置
*/
TreeRuleAggregate queryTreeRuleRich(Long treeId);
}
/**
* 仓储接口
*/
package cn.bugstack.xfg.frame.domain.rule.repository;
\ No newline at end of file
package cn.bugstack.xfg.frame.domain.rule.service.engine;
import cn.bugstack.xfg.frame.domain.rule.model.aggregates.TreeRuleAggregate;
import cn.bugstack.xfg.frame.domain.rule.model.entity.DecisionMatterEntity;
import cn.bugstack.xfg.frame.domain.rule.model.entity.EngineResultEntity;
import cn.bugstack.xfg.frame.domain.rule.model.valobj.TreeNodeVO;
import cn.bugstack.xfg.frame.domain.rule.model.valobj.TreeRootVO;
import cn.bugstack.xfg.frame.domain.rule.service.logic.LogicFilter;
import cn.bugstack.xfg.frame.types.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* @description: 规则引擎基础类
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public abstract class EngineBase extends EngineConfig implements EngineFilter {
private Logger logger = LoggerFactory.getLogger(EngineBase.class);
@Override
public EngineResultEntity process(DecisionMatterEntity matter) {
throw new RuntimeException("未实现规则引擎服务");
}
protected TreeNodeVO engineDecisionMaker(TreeRuleAggregate treeRuleRich, DecisionMatterEntity matter) {
TreeRootVO treeRoot = treeRuleRich.getTreeRoot();
Map<Long, TreeNodeVO> treeNodeMap = treeRuleRich.getTreeNodeMap();
// 规则树根ID
Long rootNodeId = treeRoot.getTreeRootNodeId();
TreeNodeVO treeNodeInfo = treeNodeMap.get(rootNodeId);
// 节点类型[NodeType];1子叶、2果实
while (Constants.NodeType.STEM.equals(treeNodeInfo.getNodeType())) {
String ruleKey = treeNodeInfo.getRuleKey();
LogicFilter logicFilter = logicFilterMap.get(ruleKey);
String matterValue = logicFilter.matterValue(matter);
Long nextNode = logicFilter.filter(matterValue, treeNodeInfo.getTreeNodeLineInfoList());
treeNodeInfo = treeNodeMap.get(nextNode);
logger.info("决策树引擎=>{} userId:{} treeId:{} treeNode:{} ruleKey:{} matterValue:{}", treeRoot.getTreeName(), matter.getUserId(), matter.getTreeId(), treeNodeInfo.getTreeNodeId(), ruleKey, matterValue);
}
return treeNodeInfo;
}
}
package cn.bugstack.xfg.frame.domain.rule.service.engine;
import cn.bugstack.xfg.frame.domain.rule.service.logic.LogicFilter;
import cn.bugstack.xfg.frame.domain.rule.service.logic.impl.UserAgeFilter;
import cn.bugstack.xfg.frame.domain.rule.service.logic.impl.UserGenderFilter;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description: 规则配置
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public class EngineConfig {
protected static Map<String, LogicFilter> logicFilterMap = new ConcurrentHashMap<>();
@Resource
private UserAgeFilter userAgeFilter;
@Resource
private UserGenderFilter userGenderFilter;
@PostConstruct
public void init() {
logicFilterMap.put("userAge", userAgeFilter);
logicFilterMap.put("userGender", userGenderFilter);
}
}
package cn.bugstack.xfg.frame.domain.rule.service.engine;
import cn.bugstack.xfg.frame.domain.rule.model.entity.DecisionMatterEntity;
import cn.bugstack.xfg.frame.domain.rule.model.entity.EngineResultEntity;
/**
* @description: 规则过滤器引擎
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public interface EngineFilter {
/**
* 规则过滤器接口
*
* @param matter 规则决策物料
* @return 规则决策结果
*/
EngineResultEntity process(final DecisionMatterEntity matter);
}
package cn.bugstack.xfg.frame.domain.rule.service.engine.impl;
import cn.bugstack.xfg.frame.domain.rule.model.aggregates.TreeRuleAggregate;
import cn.bugstack.xfg.frame.domain.rule.model.entity.DecisionMatterEntity;
import cn.bugstack.xfg.frame.domain.rule.model.entity.EngineResultEntity;
import cn.bugstack.xfg.frame.domain.rule.model.valobj.TreeNodeVO;
import cn.bugstack.xfg.frame.domain.rule.repository.IRuleRepository;
import cn.bugstack.xfg.frame.domain.rule.service.engine.EngineBase;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @description: 规则引擎处理器
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Service("ruleEngineHandle")
public class RuleEngineHandle extends EngineBase {
@Resource
private IRuleRepository ruleRepository;
@Override
public EngineResultEntity process(DecisionMatterEntity matter) {
// 决策规则树
TreeRuleAggregate treeRuleRich = ruleRepository.queryTreeRuleRich(matter.getTreeId());
if (null == treeRuleRich) {
throw new RuntimeException("Tree Rule is null!");
}
// 决策节点
TreeNodeVO treeNodeInfo = engineDecisionMaker(treeRuleRich, matter);
// 决策结果
return new EngineResultEntity(matter.getUserId(), treeNodeInfo.getTreeId(), treeNodeInfo.getTreeNodeId(), treeNodeInfo.getNodeValue());
}
}
package cn.bugstack.xfg.frame.domain.rule.service.logic;
import cn.bugstack.xfg.frame.domain.rule.model.entity.DecisionMatterEntity;
import cn.bugstack.xfg.frame.domain.rule.model.valobj.TreeNodeLineVO;
import cn.bugstack.xfg.frame.types.Constants;
import java.util.List;
/**
* @description: 规则基础抽象类
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public abstract class BaseLogic implements LogicFilter {
@Override
public Long filter(String matterValue, List<TreeNodeLineVO> treeNodeLineInfoList) {
for (TreeNodeLineVO nodeLine : treeNodeLineInfoList) {
if (decisionLogic(matterValue, nodeLine)) {
return nodeLine.getNodeIdTo();
}
}
return Constants.Global.TREE_NULL_NODE;
}
/**
* 获取规则比对值
* @param decisionMatter 决策物料
* @return 比对值
*/
@Override
public abstract String matterValue(DecisionMatterEntity decisionMatter);
private boolean decisionLogic(String matterValue, TreeNodeLineVO nodeLine) {
switch (nodeLine.getRuleLimitType()) {
case Constants.RuleLimitType.EQUAL:
return matterValue.equals(nodeLine.getRuleLimitValue());
case Constants.RuleLimitType.GT:
return Double.parseDouble(matterValue) > Double.parseDouble(nodeLine.getRuleLimitValue());
case Constants.RuleLimitType.LT:
return Double.parseDouble(matterValue) < Double.parseDouble(nodeLine.getRuleLimitValue());
case Constants.RuleLimitType.GE:
return Double.parseDouble(matterValue) >= Double.parseDouble(nodeLine.getRuleLimitValue());
case Constants.RuleLimitType.LE:
return Double.parseDouble(matterValue) <= Double.parseDouble(nodeLine.getRuleLimitValue());
default:
return false;
}
}
}
package cn.bugstack.xfg.frame.domain.rule.service.logic;
import cn.bugstack.xfg.frame.domain.rule.model.entity.DecisionMatterEntity;
import cn.bugstack.xfg.frame.domain.rule.model.valobj.TreeNodeLineVO;
import java.util.List;
/**
* @description: 规则过滤器接口
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public interface LogicFilter {
/**
* 逻辑决策器
* @param matterValue 决策值
* @param treeNodeLineInfoList 决策节点
* @return 下一个节点Id
*/
Long filter(String matterValue, List<TreeNodeLineVO> treeNodeLineInfoList);
/**
* 获取决策值
*
* @param decisionMatter 决策物料
* @return 决策值
*/
String matterValue(DecisionMatterEntity decisionMatter);
}
package cn.bugstack.xfg.frame.domain.rule.service.logic.impl;
import cn.bugstack.xfg.frame.domain.rule.model.entity.DecisionMatterEntity;
import cn.bugstack.xfg.frame.domain.rule.service.logic.BaseLogic;
import org.springframework.stereotype.Component;
/**
* @description: 年龄规则
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Component
public class UserAgeFilter extends BaseLogic {
@Override
public String matterValue(DecisionMatterEntity decisionMatter) {
return decisionMatter.getValMap().get("age").toString();
}
}
package cn.bugstack.xfg.frame.domain.rule.service.logic.impl;
import cn.bugstack.xfg.frame.domain.rule.model.entity.DecisionMatterEntity;
import cn.bugstack.xfg.frame.domain.rule.service.logic.BaseLogic;
import org.springframework.stereotype.Component;
/**
* @description: 性别规则
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Component
public class UserGenderFilter extends BaseLogic {
@Override
public String matterValue(DecisionMatterEntity decisionMatter) {
return decisionMatter.getValMap().get("gender").toString();
}
}
/**
* 具体业务实现
*/
package cn.bugstack.xfg.frame.domain.rule.service;
\ No newline at end of file
package cn.bugstack.xfg.frame.domain.user.model.valobj;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserVO {
/** 用户名称 */
private String userId;
/** 用户昵称 */
private String userNickname;
/** 创建时间 */
private Date createTime;
}
package cn.bugstack.xfg.frame.domain.user.repository;
import cn.bugstack.xfg.frame.domain.user.model.valobj.UserVO;
import java.util.List;
/**
* @author 小傅哥,微信:fustack
* @description 仓储接口
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public interface IUserRepository {
List<UserVO> queryUserList();
}
package cn.bugstack.xfg.frame.domain.user.service;
import cn.bugstack.xfg.frame.domain.user.model.valobj.UserVO;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author 小傅哥,微信:fustack
* @description
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
public interface UserService {
List<UserVO> queryUserList();
}
package cn.bugstack.xfg.frame.domain.user.service.impl;
import cn.bugstack.xfg.frame.domain.user.model.valobj.UserVO;
import cn.bugstack.xfg.frame.domain.user.repository.IUserRepository;
import cn.bugstack.xfg.frame.domain.user.service.UserService;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @author 小傅哥,微信:fustack
* @description
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Service
public class UserServiceImpl implements UserService {
@Resource
private IUserRepository userRepository;
@Override
public List<UserVO> queryUserList() {
return null;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>xfg-frame-ddd</artifactId>
<groupId>cn.bugstack</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>xfg-frame-infrastructure</artifactId>
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 自身模块 begin -->
<dependency>
<groupId>cn.bugstack</groupId>
<artifactId>xfg-frame-domain</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.bugstack</groupId>
<artifactId>xfg-frame-types</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 自身模块 end -->
</dependencies>
<build>
<finalName>xfg-frame-infrastructure</finalName>
<plugins>
<!-- 编译plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerVersion>${java.version}</compilerVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.bugstack.xfg.frame.infrastructure.dao;
import cn.bugstack.xfg.frame.infrastructure.po.UserPO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface IUserDao {
List<UserPO> queryUserList();
}
package cn.bugstack.xfg.frame.infrastructure.dao;
import cn.bugstack.xfg.frame.infrastructure.po.RuleTreeVO;
import org.apache.ibatis.annotations.Mapper;
/**
* @description: 规则树配置DAO
* @author: 小傅哥,微信:fustack
* @date: 2021/9/22
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Mapper
public interface RuleTreeDao {
/**
* 规则树查询
* @param id ID
* @return 规则树
*/
RuleTreeVO queryRuleTreeByTreeId(Long id);
/**
* 规则树简要信息查询
* @param treeId 规则树ID
* @return 规则树
*/
RuleTreeVO queryTreeSummaryInfo(Long treeId);
}
package cn.bugstack.xfg.frame.infrastructure.dao;
import cn.bugstack.xfg.frame.infrastructure.po.RuleTreeNodeVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @description: 规则树节点DAO
* @author: 小傅哥,微信:fustack
* @date: 2021/9/22
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Mapper
public interface RuleTreeNodeDao {
/**
* 查询规则树节点
* @param treeId 规则树ID
* @return 规则树节点集合
*/
List<RuleTreeNodeVO> queryRuleTreeNodeList(Long treeId);
/**
* 查询规则树节点数量
* @param treeId 规则树ID
* @return 节点数量
*/
int queryTreeNodeCount(Long treeId);
/**
* 查询规则树节点
*
* @param treeId 规则树ID
* @return 节点集合
*/
List<RuleTreeNodeVO> queryTreeRulePoint(Long treeId);
}
package cn.bugstack.xfg.frame.infrastructure.dao;
import cn.bugstack.xfg.frame.infrastructure.po.RuleTreeNodeLineVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @description: 规则树节点连线DAO
* @author: 小傅哥,微信:fustack
* @date: 2021/9/22
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Mapper
public interface RuleTreeNodeLineDao {
/**
* 查询规则树节点连线集合
* @param req 入参
* @return 规则树节点连线集合
*/
List<RuleTreeNodeLineVO> queryRuleTreeNodeLineList(RuleTreeNodeLineVO req);
/**
* 查询规则树连线数量
*
* @param treeId 规则树ID
* @return 规则树连线数量
*/
int queryTreeNodeLineCount(Long treeId);
}
/**
* 数据库操作
*/
package cn.bugstack.xfg.frame.infrastructure;
\ No newline at end of file
package cn.bugstack.xfg.frame.infrastructure.po;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 规则树节点连线
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RuleTreeNodeLineVO {
/** 主键ID */
private Long id;
/** 规则树ID */
private Long treeId;
/** 节点From */
private Long nodeIdFrom;
/** 节点To */
private Long nodeIdTo;
/** 限定类型;1:=;2:>;3:<;4:>=;5<=;6:enum[枚举范围] */
private Integer ruleLimitType;
/** 限定值 */
private String ruleLimitValue;
}
package cn.bugstack.xfg.frame.infrastructure.po;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 规则树节点
* @author: 小傅哥,微信:fustack
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RuleTreeNodeVO {
/** 主键ID */
private Long id;
/** 规则树ID */
private Long treeId;
/** 节点类型;1子叶、2果实 */
private Integer nodeType;
/** 节点值[nodeType=2];果实值 */
private String nodeValue;
/** 规则Key */
private String ruleKey;
/** 规则描述 */
private String ruleDesc;
}
package cn.bugstack.xfg.frame.infrastructure.po;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @description: 规则树
* @author: 小傅哥,微信:fustack
* @date: 2021/9/22
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RuleTreeVO {
/** 主键ID */
private Long id;
/** 规则树名称 */
private String treeName;
/** 规则树描述 */
private String treeDesc;
/** 规则树根ID */
private Long treeRootNodeId;
/** 创建时间 */
private Date createTime;
/** 更新时间 */
private Date updateTime;
}
package cn.bugstack.xfg.frame.infrastructure.po;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserPO {
/** 用户ID */
private Long id;
/** 用户名称 */
private String userId;
/** 用户昵称 */
private String userNickname;
/** 用户头像 */
private String userHead;
/** 账号密码 */
private String userPassword;
/** 创建时间 */
private Date createTime;
/** 修改时间 */
private Date updateTime;
}
package cn.bugstack.xfg.frame.infrastructure.repository;
import cn.bugstack.xfg.frame.domain.rule.model.aggregates.TreeRuleAggregate;
import cn.bugstack.xfg.frame.domain.rule.model.valobj.TreeNodeLineVO;
import cn.bugstack.xfg.frame.domain.rule.model.valobj.TreeNodeVO;
import cn.bugstack.xfg.frame.domain.rule.model.valobj.TreeRootVO;
import cn.bugstack.xfg.frame.domain.rule.repository.IRuleRepository;
import cn.bugstack.xfg.frame.infrastructure.dao.RuleTreeDao;
import cn.bugstack.xfg.frame.infrastructure.dao.RuleTreeNodeDao;
import cn.bugstack.xfg.frame.infrastructure.dao.RuleTreeNodeLineDao;
import cn.bugstack.xfg.frame.infrastructure.po.RuleTreeNodeLineVO;
import cn.bugstack.xfg.frame.infrastructure.po.RuleTreeNodeVO;
import cn.bugstack.xfg.frame.infrastructure.po.RuleTreeVO;
import cn.bugstack.xfg.frame.types.Constants;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @description: 规则信息仓储服务
* @author: 小傅哥,微信:fustack
* @date: 2021/10/8
* @github: https://github.com/fuzhengwei
* @Copyright: 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Repository
public class RuleRepository implements IRuleRepository {
@Resource
private RuleTreeDao ruleTreeDao;
@Resource
private RuleTreeNodeDao ruleTreeNodeDao;
@Resource
private RuleTreeNodeLineDao ruleTreeNodeLineDao;
@Override
public TreeRuleAggregate queryTreeRuleRich(Long treeId) {
// 规则树
RuleTreeVO ruleTree = ruleTreeDao.queryRuleTreeByTreeId(treeId);
TreeRootVO treeRoot = new TreeRootVO();
treeRoot.setTreeId(ruleTree.getId());
treeRoot.setTreeRootNodeId(ruleTree.getTreeRootNodeId());
treeRoot.setTreeName(ruleTree.getTreeName());
// 树节点->树连接线
Map<Long, TreeNodeVO> treeNodeMap = new HashMap<>();
List<RuleTreeNodeVO> ruleTreeNodeList = ruleTreeNodeDao.queryRuleTreeNodeList(treeId);
for (RuleTreeNodeVO treeNode : ruleTreeNodeList) {
List<TreeNodeLineVO> treeNodeLineInfoList = new ArrayList<>();
if (Constants.NodeType.STEM.equals(treeNode.getNodeType())) {
RuleTreeNodeLineVO ruleTreeNodeLineReq = new RuleTreeNodeLineVO();
ruleTreeNodeLineReq.setTreeId(treeId);
ruleTreeNodeLineReq.setNodeIdFrom(treeNode.getId());
List<RuleTreeNodeLineVO> ruleTreeNodeLineList = ruleTreeNodeLineDao.queryRuleTreeNodeLineList(ruleTreeNodeLineReq);
for (RuleTreeNodeLineVO nodeLine : ruleTreeNodeLineList) {
TreeNodeLineVO treeNodeLineInfo = new TreeNodeLineVO();
treeNodeLineInfo.setNodeIdFrom(nodeLine.getNodeIdFrom());
treeNodeLineInfo.setNodeIdTo(nodeLine.getNodeIdTo());
treeNodeLineInfo.setRuleLimitType(nodeLine.getRuleLimitType());
treeNodeLineInfo.setRuleLimitValue(nodeLine.getRuleLimitValue());
treeNodeLineInfoList.add(treeNodeLineInfo);
}
}
TreeNodeVO treeNodeInfo = new TreeNodeVO();
treeNodeInfo.setTreeId(treeNode.getTreeId());
treeNodeInfo.setTreeNodeId(treeNode.getId());
treeNodeInfo.setNodeType(treeNode.getNodeType());
treeNodeInfo.setNodeValue(treeNode.getNodeValue());
treeNodeInfo.setRuleKey(treeNode.getRuleKey());
treeNodeInfo.setRuleDesc(treeNode.getRuleDesc());
treeNodeInfo.setTreeNodeLineInfoList(treeNodeLineInfoList);
treeNodeMap.put(treeNode.getId(), treeNodeInfo);
}
TreeRuleAggregate treeRuleRich = new TreeRuleAggregate();
treeRuleRich.setTreeRoot(treeRoot);
treeRuleRich.setTreeNodeMap(treeNodeMap);
return treeRuleRich;
}
}
package cn.bugstack.xfg.frame.infrastructure.repository;
import cn.bugstack.xfg.frame.domain.user.model.valobj.UserVO;
import cn.bugstack.xfg.frame.domain.user.repository.IUserRepository;
import cn.bugstack.xfg.frame.infrastructure.dao.IUserDao;
import cn.bugstack.xfg.frame.infrastructure.po.UserPO;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @author 小傅哥,微信:fustack
* @description
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Repository
public class UserRepository implements IUserRepository {
@Resource
private IUserDao userDao;
@Override
public List<UserVO> queryUserList() {
List<UserVO> userInfoList = new ArrayList<>();
List<UserPO> users = userDao.queryUserList();
for (UserPO user : users) {
UserVO userInfo = UserVO.builder()
.userId(user.getUserId())
.userNickname(user.getUserNickname())
.createTime(user.getCreateTime())
.build();
userInfoList.add(userInfo);
}
return userInfoList;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>xfg-frame-ddd</artifactId>
<groupId>cn.bugstack</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>xfg-frame-trigger</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<!-- 自身模块 begin -->
<dependency>
<groupId>cn.bugstack</groupId>
<artifactId>xfg-frame-domain</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.bugstack</groupId>
<artifactId>xfg-frame-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.bugstack</groupId>
<artifactId>xfg-frame-types</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 自身模块 end -->
</dependencies>
<build>
<finalName>xfg-frame-trigger</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerVersion>${java.version}</compilerVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.bugstack.xfg.frame.trigger.http;
import cn.bugstack.xfg.frame.types.Constants;
import cn.bugstack.xfg.frame.types.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Random;
import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
@RestController
public class Controller {
@Resource
private ThreadPoolExecutor threadPoolExecutor;
/**
* http://localhost:8090/success
*/
@RequestMapping("/success")
public Response<String> success() {
log.info("测试调用");
try {
// 随机休眠
Thread.sleep(new Random().nextInt(1000));
// 开启线程
threadPoolExecutor.execute(() -> {
log.info("开启线程");
});
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (new Random().nextInt(100) == 1) throw new RuntimeException("异常");
return Response.<String>builder()
.code(Constants.ResponseCode.SUCCESS.getCode())
.info(Constants.ResponseCode.SUCCESS.getInfo())
.data("查询用户信息,小傅哥")
.build();
}
}
/**
* 触发器;接收http请求
*/
package cn.bugstack.xfg.frame.trigger.http;
\ No newline at end of file
/**
* 触发器;接收mq消费
*/
package cn.bugstack.xfg.frame.trigger.mq;
\ No newline at end of file
package cn.bugstack.xfg.frame.trigger.rpc;
import cn.bugstack.xfg.frame.api.IAccountService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import java.util.Random;
@Slf4j
@DubboService(version = "1.0.0")
public class AccountService implements IAccountService {
public String queryUserName(String req) {
log.info("查询用户信息 reqStr:{}", JSON.toJSONString(req));
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "花花";
}
}
package cn.bugstack.xfg.frame.trigger.rpc;
import cn.bugstack.xfg.frame.api.IRuleService;
import cn.bugstack.xfg.frame.api.model.request.DecisionMatterRequest;
import cn.bugstack.xfg.frame.api.model.response.DecisionMatterResponse;
import cn.bugstack.xfg.frame.domain.rule.model.entity.DecisionMatterEntity;
import cn.bugstack.xfg.frame.domain.rule.model.entity.EngineResultEntity;
import cn.bugstack.xfg.frame.domain.rule.service.engine.EngineFilter;
import cn.bugstack.xfg.frame.types.Constants;
import cn.bugstack.xfg.frame.types.Response;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import javax.annotation.Resource;
/**
* @author 小傅哥,微信:fustack
* @description
* @github https://github.com/fuzhengwei
* @Copyright 公众号:bugstack虫洞栈 | 博客:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
*/
@Slf4j
@DubboService(version = "1.0.0")
public class RuleService implements IRuleService {
@Resource
private EngineFilter engineFilter;
@Override
public Response<DecisionMatterResponse> doRule(DecisionMatterRequest request) {
log.info("规则引擎过滤 reqStr:{}", JSON.toJSONString(request));
try {
// 1. 构建参数
DecisionMatterEntity entity = DecisionMatterEntity.builder()
.userId(request.getUserId())
.treeId(request.getTreeId())
.valMap(request.getValMap()).build();
// 2. 调用规则
EngineResultEntity process = engineFilter.process(entity);
DecisionMatterResponse DecisionMatter = DecisionMatterResponse.builder().activityId(process.getTreeId()).build();
// 3. 封装结果
return Response.<DecisionMatterResponse>builder()
.code(Constants.ResponseCode.SUCCESS.getCode())
.info(Constants.ResponseCode.SUCCESS.getInfo())
.data(DecisionMatter).build();
} catch (Exception e) {
log.error("规则引擎过滤失败 reqStr:{}", JSON.toJSONString(request), e);
return Response.<DecisionMatterResponse>builder()
.code(Constants.ResponseCode.UN_ERROR.getCode())
.info(Constants.ResponseCode.UN_ERROR.getInfo()).build();
}
}
}
/**
* 触发器;接收rpc调用
*/
package cn.bugstack.xfg.frame.trigger.rpc;
\ No newline at end of file
/**
* 触发器;接收调度任务
*/
package cn.bugstack.xfg.frame.trigger.task;
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>xfg-frame-ddd</artifactId>
<groupId>cn.bugstack</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>xfg-frame-types</artifactId>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
</dependency>
</dependencies>
<build>
<finalName>xfg-frame-types</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package cn.bugstack.xfg.frame.types;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
public class Constants {
@AllArgsConstructor
@NoArgsConstructor
@Getter
public enum ResponseCode {
SUCCESS("0000", "成功"),
UN_ERROR("0001", "未知失败"),
ILLEGAL_PARAMETER("0002", "非法参数"),
INDEX_DUP("0003", "主键冲突"),
RATE_LIMITER("0004", "请求已被限流,超过限流配置");
private String code;
private String info;
}
/**
* 全局属性
*/
public static final class Global {
/**
* 空节点值
*/
public static final Long TREE_NULL_NODE = 0L;
}
/**
* 决策树节点
*/
public static final class NodeType {
/**
* 树茎
*/
public static final Integer STEM = 1;
/**
* 果实
*/
public static final Integer FRUIT = 2;
}
/**
* 规则限定类型
*/
public static final class RuleLimitType {
/**
* 等于
*/
public static final int EQUAL = 1;
/**
* 大于
*/
public static final int GT = 2;
/**
* 小于
*/
public static final int LT = 3;
/**
* 大于&等于
*/
public static final int GE = 4;
/**
* 小于&等于
*/
public static final int LE = 5;
/**
* 枚举
*/
public static final int ENUM = 6;
}
}
package cn.bugstack.xfg.frame.types;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Response<T> implements Serializable {
private String code;
private String info;
private T data;
}
/**
* 通用类型设定
*/
package cn.bugstack.xfg.frame.types;
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册