├── .idea
└── uiDesigner.xml
├── drools_kie_demo
├── pom.xml
└── src
│ └── main
│ └── java
│ └── com
│ └── canthny
│ └── drools_kie_demo
│ ├── domain
│ ├── Assets.java
│ └── UserInfo.java
│ └── test
│ └── DroolKieTestDemo.java
├── tanghao-bigdata-drools
├── README.md
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── tanghao
│ │ │ └── bigdata
│ │ │ └── drools
│ │ │ ├── DroolsStarter.java
│ │ │ ├── controller
│ │ │ └── TestPayRule.java
│ │ │ ├── domain
│ │ │ ├── DefeatMapReduceObject.java
│ │ │ ├── MobilePaymentInfo.java
│ │ │ ├── PhoneNoBlackObject.java
│ │ │ ├── request
│ │ │ │ ├── BaseRequest.java
│ │ │ │ └── MobilePaymentRequest.java
│ │ │ └── response
│ │ │ │ └── RuleResponse.java
│ │ │ ├── enums
│ │ │ └── EnumRuleResponseLevel.java
│ │ │ ├── kafka
│ │ │ ├── config
│ │ │ │ └── MobilePaymentInfoConfig.java
│ │ │ └── listener
│ │ │ │ └── MobilePaymentInfoListener.java
│ │ │ ├── mongodb
│ │ │ ├── config
│ │ │ │ └── SpringMongoConfig.java
│ │ │ └── service
│ │ │ │ ├── MobilePaymentInfoService.java
│ │ │ │ └── impl
│ │ │ │ └── MobilePaymentInfoServiceImpl.java
│ │ │ ├── redis
│ │ │ └── RedisConfig.java
│ │ │ ├── service
│ │ │ ├── MobilePaymentRuleService.java
│ │ │ └── PhoneNoBlacklistService.java
│ │ │ └── util
│ │ │ └── DateUtil.java
│ └── resources
│ │ ├── META-INF
│ │ └── kmodule.xml
│ │ ├── application.properties
│ │ ├── com.tanghao.bigdata.drools.rules
│ │ └── pay_rule.drl
│ │ ├── drools
│ │ ├── pay_rule.drl
│ │ └── pay_rule2.drl
│ │ └── mapreduce
│ │ ├── mobile_payment_info_map.js
│ │ └── mobile_payment_info_reduce.js
│ └── test
│ └── java
│ └── com
│ └── tanghao
│ └── bigdata
│ └── drools
│ └── test
│ ├── TestDrools.java
│ ├── TestKafkaProduct.java
│ ├── TestMongodb.java
│ ├── TestMongodbJob.java
│ └── TestRuleService.java
└── tanghao-flink-demo
├── pom.xml
└── src
├── README.md
└── main
├── java
└── com
│ └── tanghao
│ └── flink
│ └── demo
│ ├── GetPayInfoJob.java
│ ├── TestAction.java
│ ├── api
│ ├── datastream
│ │ ├── FilterApiTest.java
│ │ ├── FlatMapApiTest.java
│ │ ├── KeyByApiTest.java
│ │ ├── MapApiTest.java
│ │ └── UnionAndSplitStreamTest.java
│ ├── others
│ │ └── BroadcastTableTest.java
│ └── window
│ │ ├── GlobalWindowTest.java
│ │ ├── SessionWindowTest.java
│ │ ├── SlidingWindowTest.java
│ │ ├── TumblingWindowAggregateFunctionTest.java
│ │ ├── TumblingWindowProcessWindowFunctionTest.java
│ │ └── TumblingWindowUseEventTimeTest.java
│ ├── common
│ ├── ConstantKafka.java
│ ├── Message.java
│ ├── MessageDeserializationSchema.java
│ ├── TradeCountMinuteResult.java
│ ├── TransTypeInfo.java
│ └── UserConsumerAmountPerMinute.java
│ ├── source
│ ├── InnerSource.java
│ └── KafkaSource.java
│ └── test
│ ├── BroadcastMsgProducerTest.java
│ └── MsgProducerTest.java
└── resources
└── log4j.properties
/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/drools_kie_demo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.canthny
8 | drools_kie_demo
9 | 1.0.0
10 |
11 |
12 |
13 | junit
14 | junit
15 | 3.8.1
16 | test
17 |
18 |
19 |
20 | org.drools
21 | drools-core
22 | 7.6.0.Final
23 |
24 |
25 | org.drools
26 | drools-compiler
27 | 7.6.0.Final
28 |
29 |
30 | org.kie.server
31 | kie-server
32 | 7.6.0.Final
33 |
34 |
35 | org.slf4j
36 | slf4j-api
37 | 1.7.22
38 |
39 |
40 |
41 | com.alibaba
42 | fastjson
43 | 1.2.51
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | nexus-aliyun
59 | Nexus aliyun
60 | http://maven.aliyun.com/nexus/content/groups/public
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/drools_kie_demo/src/main/java/com/canthny/drools_kie_demo/domain/Assets.java:
--------------------------------------------------------------------------------
1 | package com.canthny.drools_kie_demo.domain;
2 |
3 | /**
4 | * This class was automatically generated by the data modeler tool.
5 | */
6 |
7 | public class Assets implements java.io.Serializable {
8 |
9 | static final long serialVersionUID = 1L;
10 |
11 | private java.lang.Long money;
12 | private java.lang.Long stock;
13 | private java.lang.Long fund;
14 |
15 | public Assets() {
16 | }
17 |
18 | public java.lang.Long getMoney() {
19 | return this.money;
20 | }
21 |
22 | public void setMoney(java.lang.Long money) {
23 | this.money = money;
24 | }
25 |
26 | public java.lang.Long getStock() {
27 | return this.stock;
28 | }
29 |
30 | public void setStock(java.lang.Long stock) {
31 | this.stock = stock;
32 | }
33 |
34 | public java.lang.Long getFund() {
35 | return this.fund;
36 | }
37 |
38 | public void setFund(java.lang.Long fund) {
39 | this.fund = fund;
40 | }
41 |
42 | public Assets(java.lang.Long money, java.lang.Long stock,
43 | java.lang.Long fund) {
44 | this.money = money;
45 | this.stock = stock;
46 | this.fund = fund;
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/drools_kie_demo/src/main/java/com/canthny/drools_kie_demo/domain/UserInfo.java:
--------------------------------------------------------------------------------
1 | package com.canthny.drools_kie_demo.domain;
2 |
3 | /**
4 | * This class was automatically generated by the data modeler tool.
5 | */
6 |
7 | public class UserInfo implements java.io.Serializable {
8 |
9 | static final long serialVersionUID = 1L;
10 |
11 | private java.lang.Long id;
12 | private java.lang.String name;
13 | private java.lang.Integer age;
14 | private java.lang.String accountNo;
15 |
16 | private java.lang.String risk_type;
17 |
18 | private com.canthny.drools_kie_demo.domain.Assets assets;
19 |
20 | public UserInfo() {
21 | }
22 |
23 | public java.lang.Long getId() {
24 | return this.id;
25 | }
26 |
27 | public void setId(java.lang.Long id) {
28 | this.id = id;
29 | }
30 |
31 | public java.lang.String getName() {
32 | return this.name;
33 | }
34 |
35 | public void setName(java.lang.String name) {
36 | this.name = name;
37 | }
38 |
39 | public java.lang.Integer getAge() {
40 | return this.age;
41 | }
42 |
43 | public void setAge(java.lang.Integer age) {
44 | this.age = age;
45 | }
46 |
47 | public java.lang.String getAccountNo() {
48 | return this.accountNo;
49 | }
50 |
51 | public void setAccountNo(java.lang.String accountNo) {
52 | this.accountNo = accountNo;
53 | }
54 |
55 | public java.lang.String getRisk_type() {
56 | return this.risk_type;
57 | }
58 |
59 | public void setRisk_type(java.lang.String risk_type) {
60 | this.risk_type = risk_type;
61 | }
62 |
63 | public com.canthny.drools_kie_demo.domain.Assets getAssets() {
64 | return this.assets;
65 | }
66 |
67 | public void setAssets(com.canthny.drools_kie_demo.domain.Assets assets) {
68 | this.assets = assets;
69 | }
70 |
71 | public UserInfo(java.lang.Long id, java.lang.String name,
72 | java.lang.Integer age, java.lang.String accountNo,
73 | java.lang.String risk_type,
74 | com.canthny.drools_kie_demo.domain.Assets assets) {
75 | this.id = id;
76 | this.name = name;
77 | this.age = age;
78 | this.accountNo = accountNo;
79 | this.risk_type = risk_type;
80 | this.assets = assets;
81 | }
82 |
83 | }
--------------------------------------------------------------------------------
/drools_kie_demo/src/main/java/com/canthny/drools_kie_demo/test/DroolKieTestDemo.java:
--------------------------------------------------------------------------------
1 | package com.canthny.drools_kie_demo.test;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.canthny.drools_kie_demo.domain.Assets;
5 | import com.canthny.drools_kie_demo.domain.UserInfo;
6 | import org.kie.api.KieServices;
7 | import org.kie.api.command.Command;
8 | import org.kie.api.command.KieCommands;
9 | import org.kie.api.runtime.ExecutionResults;
10 | import org.kie.server.api.marshalling.MarshallingFormat;
11 | import org.kie.server.api.model.ServiceResponse;
12 | import org.kie.server.client.KieServicesClient;
13 | import org.kie.server.client.KieServicesConfiguration;
14 | import org.kie.server.client.KieServicesFactory;
15 | import org.kie.server.client.RuleServicesClient;
16 |
17 | import java.util.LinkedList;
18 | import java.util.List;
19 |
20 | /**
21 | * Description: kie-server动态部署demo测试
22 | * Created By tanghao on 2019/7/22
23 | */
24 | public class DroolKieTestDemo {
25 |
26 | public static void main(String[] args) {
27 | KieServicesConfiguration kieServicesConfiguration = KieServicesFactory.newRestConfiguration("http://192.168.8.132:8080/kie-server/services/rest/server","kieserver","kieserver1!");
28 | kieServicesConfiguration.setMarshallingFormat(MarshallingFormat.JSON);
29 | KieServicesClient kieServicesClient = KieServicesFactory.newKieServicesClient(kieServicesConfiguration);
30 | RuleServicesClient ruleServicesClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
31 | UserInfo userInfo = new UserInfo();
32 | userInfo.setId(1L);
33 | userInfo.setName("canthny");
34 | userInfo.setAge(31);
35 | Assets assets = new Assets();
36 | assets.setMoney(20L);
37 | assets.setFund(30L);
38 | assets.setStock(50L);
39 | userInfo.setAssets(assets);
40 | KieCommands kieCommands = KieServices.Factory.get().getCommands();
41 | List> commands = new LinkedList<>();
42 | commands.add(kieCommands.newInsert(userInfo, "userInfo"));
43 | commands.add(kieCommands.newFireAllRules());
44 | //kie-server中发布的规则,通过/kie-server/services/rest/server/containers获取容器id,以及在kie-web端设置的kiebase的id
45 | ServiceResponse results = ruleServicesClient.executeCommandsWithResults("drools-kie-demo_1.0.0",
46 | kieCommands.newBatchExecution(commands, "session1"));
47 | UserInfo value = (UserInfo) results.getResult().getValue("userInfo");
48 | System.out.println(JSONObject.toJSON(value).toString());
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/README.md:
--------------------------------------------------------------------------------
1 | # drool规则引擎测试-手机缴费风险控制Demo
2 | ## 1-单笔金额超限;
3 | ## 2-手机号在黑名单中;
4 | ## 3-充值金额不能大于近3天平均值的3倍
5 |
6 | # 启动服务
7 | //mongodb启动命令中的ip跟着本机的动态ip改变
8 | cd /usr/local/mongodb/bin
9 | nohup ./mongod -bind_ip 192.168.0.102 &
10 | //kafka的server.properties中advertised.listeners=PLAINTEXT://192.168.1.113:9092修改一下当前ip
11 | cd /home/canthny/kafka_2.11-0.11.0.3
12 | nohup bin/zookeeper-server-start.sh config/zookeeper.properties &
13 | nohup bin/kafka-server-start.sh config/server.properties &
14 | //redis启动本地windows的
15 |
16 | //tanghao-bigdata-drools工程中配置mongodb和redis的ip为本地或虚拟机的ip
17 | //tanghao-flink-demo工程中配置kafka的地址
18 | # 数据准备
19 | ## 1、插入3天缴费数据十条,金额随机,执行TestMongodb中的testSave()方法插入数据
20 | cd /usr/local/mongodb/bin
21 | ./mongo 192.168.0.102:27017/rule进入命令行查询数据
22 |
23 | Mongodb常用命令
24 | //进入库
25 | use rule
26 | //创建集合
27 | db.createCollection("mobilePaymentInfo")
28 | //查看所有集合
29 | show collections
30 | //查看当前库指定集合所有数据
31 | db.mobilePaymentInfo.find()
32 | //向当前库指定集合插入文档
33 | db.mobilePaymentInfo.insert({"_class" : "com.tanghao.bigdata.drools.mongodb.domain.MobilePaymentInfo", "pay_order_no" : "2018092700001", "account_no" : "1234312412345234", "bank_card_no" : "62260113241234", "mobile" : "18709858763", "amount" : "12.00", "time" : "20180927 16:57:00" })
34 | //删除文档下所有数据
35 | db.mobilePaymentInfo.remove({})
36 | //根据日期查询
37 | db.mobilePaymentInfo.find({time:{'$gte':ISODate("2018-09-27"),'$lt':ISODate("2018-09-28")}})
38 | ## 2、插入手机号黑名单数据,执行TestMongodb中的insertPhoneNoBlackList()方法
39 |
40 | ## 3、计算3天内用户缴费平均金额,执行TestMongodb中的testMapReduce()方法,并将计算结果插入新表用户3日缴费平均金额中
41 | _id即为用户的account_no,value为3日缴费平均金额
42 |
43 |
44 | # 单元测试
45 | *规则引擎测试:tanghao-bigdata-drools工程TestDrools单元测试中的testCase1\2\3\4方法
46 | *规则执行顺序(pay_rule.drl文件中的salience属性):单笔限额>手机号黑名单>充值平均值
47 | testCase1()——单笔金额超限,打印风险,金额自行修改。
48 | testCase2()——风控判断手机号是否在黑名单中,需要事先建立黑名单表数据,TestMongodb类insertPhoneNoBlackList中key插入黑名单数据,修改手机号运行单元测试即可。
49 | testCase3()——判断当前单笔充值额度大于用户最近一个月充值额度平均值的3倍,需要事先进行MapReduce操作,产生一段时间内平均金额数据,插入中间表,在TestMongodb类testMapReduce方法中,自行调整日期参数即可,上节数据准备中第三步已经做过可忽略,也可以自行尝试。
50 | testCase4()——一小时内支付次数或支付金额限制,需要先跑流计算测试,将数据插入缓存中,流程暂未串起来,后续可以写个消息生产者将流计算和规则引擎串起来
51 |
52 | *流计算测试:tanghao-flink-demo工程GetPayInfoJob中main方法
53 | //flink demo测试,kafka生产消息
54 | cd /home/canthny/kafka_2.11-0.11.0.3
55 | bin/kafka-console-producer.sh --broker-list localhost:9092 --topic CountPerHourByAccountNo2
56 |
57 | bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic CountPerHourByAccountNo --from-beginning
58 | {"accountId":"0716","amount":"130","eventTime":"2018/09/30 02:51:00"}
59 | {"accountId":"0718","amount":"130","eventTime":"2018/09/30 02:51:01"}
60 | {"accountId":"0718","amount":"130","eventTime":"2018/09/30 02:51:06"}
61 | {"accountId":"0718","amount":"130","eventTime":"2018/09/30 02:51:07"}
62 | {"accountId":"0716","amount":"140","eventTime":"2018/09/30 02:51:02"}
63 | {"accountId":"0716","amount":"150","eventTime":"2018/09/30 02:51:06"}
64 | {"accountId":"0716","amount":"150","eventTime":"2018/09/30 02:51:12"}
65 |
66 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 1.5.8.RELEASE
9 |
10 | 4.0.0
11 |
12 | tanghao.drools.demo
13 | tanghao-bigdata-drools
14 | 1.0-SNAPSHOT
15 |
16 | 6.5.0.Final
17 |
18 |
19 |
20 |
21 | org.kie
22 | kie-api
23 | ${drools.version}
24 |
25 |
26 | org.drools
27 | drools-core
28 | ${drools.version}
29 |
30 |
31 | org.drools
32 | drools-compiler
33 | ${drools.version}
34 |
35 |
36 | org.drools
37 | drools-decisiontables
38 | ${drools.version}
39 |
40 |
41 | org.drools
42 | drools-templates
43 | ${drools.version}
44 |
45 |
46 | org.springframework.boot
47 | spring-boot-starter-web
48 |
49 |
50 |
51 |
52 | org.springframework.boot
53 | spring-boot-starter
54 |
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-starter-test
59 | test
60 |
61 |
62 |
63 |
64 | org.springframework.boot
65 | spring-boot-starter-data-mongodb
66 |
67 |
68 |
69 |
70 | org.springframework.boot
71 | spring-boot-starter-data-redis
72 |
73 |
74 |
75 |
76 | org.springframework.kafka
77 | spring-kafka
78 |
79 |
80 |
81 | com.alibaba
82 | fastjson
83 | 1.2.34
84 |
85 |
86 |
87 |
88 |
89 |
90 | org.springframework.boot
91 | spring-boot-maven-plugin
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | nexus-aliyun
107 | Nexus aliyun
108 | http://maven.aliyun.com/nexus/content/groups/public
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/DroolsStarter.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.ComponentScan;
6 |
7 | /**
8 | * @Author: Canthny
9 | * @Description: 启动类
10 | * @Date: Created in 2018/9/11 16:43
11 | */
12 | @SpringBootApplication
13 | public class DroolsStarter {
14 |
15 | public static void main(String[] args) {
16 | SpringApplication.run(DroolsStarter.class,args);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/controller/TestPayRule.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.controller;
2 |
3 | import com.tanghao.bigdata.drools.domain.request.MobilePaymentRequest;
4 | import com.tanghao.bigdata.drools.domain.response.RuleResponse;
5 | import com.tanghao.bigdata.drools.util.DateUtil;
6 | import org.kie.api.KieServices;
7 | import org.kie.api.runtime.KieContainer;
8 | import org.kie.api.runtime.KieSession;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 | import org.springframework.web.bind.annotation.RequestMethod;
11 | import org.springframework.web.bind.annotation.RestController;
12 |
13 | import java.util.Date;
14 |
15 | /**
16 | * @Author: Canthny
17 | * @Description: 测试支付风控拦截
18 | * @Date: Created in 2018/9/11 15:18
19 | */
20 | @RequestMapping(value = "/test/rules")
21 | @RestController
22 | public class TestPayRule {
23 |
24 | @RequestMapping(value = "/pay", method = RequestMethod.GET)
25 | public RuleResponse testPayRule(){
26 |
27 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
28 | KieSession ksession = kc.newKieSession("pay_rule");
29 | MobilePaymentRequest payRequest = new MobilePaymentRequest();
30 | payRequest.setAccountNo("1");
31 | payRequest.setAmount(51);
32 | payRequest.setOutTradeDate(DateUtil.convertDateToString("yyyyMMdd",new Date()));
33 | payRequest.setMobile("18709858763");
34 | payRequest.setBankCardNo("62260113241234");
35 | ksession.insert(payRequest);
36 | ksession.fireAllRules();
37 | ksession.dispose();
38 | return payRequest.getResponse();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/domain/DefeatMapReduceObject.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.domain;
2 |
3 | import org.springframework.data.mongodb.core.mapping.Document;
4 | import org.springframework.data.mongodb.core.mapping.Field;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * @Author: Canthny
10 | * @Description: mapreduce后默认输出对象
11 | * @Date: Created in 2018/9/30 0:35
12 | */
13 | public class DefeatMapReduceObject implements Serializable {
14 |
15 | private static final long serialVersionUID = -5403346308235899592L;
16 |
17 | private String id;
18 |
19 | private Integer value;
20 |
21 | public String getId() {
22 | return id;
23 | }
24 |
25 | public void setId(String id) {
26 | this.id = id;
27 | }
28 |
29 | public Integer getValue() {
30 | return value;
31 | }
32 |
33 | public void setValue(Integer value) {
34 | this.value = value;
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return "DefeatMapReduceObject{" +
40 | "id='" + id + '\'' +
41 | ", value=" + value +
42 | '}';
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/domain/MobilePaymentInfo.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.domain;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import org.springframework.data.mongodb.core.mapping.Document;
5 | import org.springframework.data.mongodb.core.mapping.Field;
6 |
7 | import java.io.Serializable;
8 | import java.util.Date;
9 |
10 | /**
11 | * @Author: Canthny
12 | * @Description: 手机缴费信息对象
13 | * @Date: Created in 2018/9/27 14:35
14 | */
15 | @Document(collection="MOBILE_PAYMENT_INFO")
16 | public class MobilePaymentInfo implements Serializable{
17 | private static final long serialVersionUID = -4612172600889702761L;
18 |
19 | @Field("pay_order_no")
20 | private String payOrderNo;
21 |
22 | @Field("account_no")
23 | private String accountNo;
24 |
25 | @Field("bank_card_no")
26 | private String bankCardNo;
27 |
28 | @Field("mobile")
29 | private String mobile;
30 |
31 | @Field("amount")
32 | private Integer amount;
33 |
34 | @Field("time")
35 | private Date time;
36 |
37 | public String getPayOrderNo() {
38 | return payOrderNo;
39 | }
40 |
41 | public void setPayOrderNo(String payOrderNo) {
42 | this.payOrderNo = payOrderNo;
43 | }
44 |
45 | public String getAccountNo() {
46 | return accountNo;
47 | }
48 |
49 | public void setAccountNo(String accountNo) {
50 | this.accountNo = accountNo;
51 | }
52 |
53 | public String getBankCardNo() {
54 | return bankCardNo;
55 | }
56 |
57 | public void setBankCardNo(String bankCardNo) {
58 | this.bankCardNo = bankCardNo;
59 | }
60 |
61 | public String getMobile() {
62 | return mobile;
63 | }
64 |
65 | public void setMobile(String mobile) {
66 | this.mobile = mobile;
67 | }
68 |
69 | public Integer getAmount() {
70 | return amount;
71 | }
72 |
73 | public void setAmount(Integer amount) {
74 | this.amount = amount;
75 | }
76 |
77 | public Date getTime() {
78 | return time;
79 | }
80 |
81 | public void setTime(Date time) {
82 | this.time = time;
83 | }
84 |
85 | @Override
86 | public String toString() {
87 | return "MobilePaymentInfo{" +
88 | "payOrderNo='" + payOrderNo + '\'' +
89 | ", accountNo='" + accountNo + '\'' +
90 | ", bankCardNo='" + bankCardNo + '\'' +
91 | ", mobile='" + mobile + '\'' +
92 | ", amount='" + amount + '\'' +
93 | ", time='" + time + '\'' +
94 | '}';
95 | }
96 |
97 | public static void main(String[] args) {
98 | MobilePaymentInfo info = new MobilePaymentInfo();
99 | info.setAccountNo("1234312412345235");
100 | info.setAmount(120);
101 | info.setBankCardNo("62260113241234");
102 | info.setMobile("18709858763");
103 | info.setPayOrderNo("2018092700002");
104 | info.setTime(new Date());
105 |
106 | String demo = JSONObject.toJSONString(info);
107 | System.out.println(demo);
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/domain/PhoneNoBlackObject.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.domain;
2 |
3 | import org.springframework.data.mongodb.core.mapping.Document;
4 | import org.springframework.data.mongodb.core.mapping.Field;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * @Author: Canthny
10 | * @Description: 手机号黑名单
11 | * @Date: Created in 2018/9/29 16:06
12 | */
13 | @Document(collection="PHONE_NO_BLACK_LIST")
14 | public class PhoneNoBlackObject implements Serializable {
15 |
16 | private static final long serialVersionUID = 9180593713475107020L;
17 |
18 | @Field("phone_no")
19 | private String phoneNo;
20 |
21 | public String getPhoneNo() {
22 | return phoneNo;
23 | }
24 |
25 | public void setPhoneNo(String phoneNo) {
26 | this.phoneNo = phoneNo;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/domain/request/BaseRequest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.domain.request;
2 |
3 | import com.tanghao.bigdata.drools.domain.response.RuleResponse;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * @Author: Canthny
9 | * @Description: 一次支付请求参数
10 | * @Date: Created in 2018/9/11 15:17
11 | */
12 | public class BaseRequest implements Serializable{
13 |
14 |
15 | private static final long serialVersionUID = 3849610254845766744L;
16 | private RuleResponse response;
17 |
18 | public void setResponse(String code,String level,String desc){
19 | this.response = new RuleResponse(code,level,desc);
20 | }
21 |
22 | public RuleResponse getResponse() {
23 | return response;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/domain/request/MobilePaymentRequest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.domain.request;
2 |
3 | import org.springframework.data.mongodb.core.mapping.Field;
4 |
5 | /**
6 | * @Author: Canthny
7 | * @Description: 手机充值请求对象
8 | * @Date: Created in 2018/9/29 19:44
9 | */
10 | public class MobilePaymentRequest extends BaseRequest{
11 |
12 | private static final long serialVersionUID = -5099820860840607608L;
13 |
14 | private String accountNo;
15 |
16 | private String bankCardNo;
17 |
18 | private String mobile;
19 |
20 | private Integer amount;
21 |
22 | private String outTradeDate;
23 |
24 | public String getAccountNo() {
25 | return accountNo;
26 | }
27 |
28 | public void setAccountNo(String accountNo) {
29 | this.accountNo = accountNo;
30 | }
31 |
32 | public String getBankCardNo() {
33 | return bankCardNo;
34 | }
35 |
36 | public void setBankCardNo(String bankCardNo) {
37 | this.bankCardNo = bankCardNo;
38 | }
39 |
40 | public String getMobile() {
41 | return mobile;
42 | }
43 |
44 | public void setMobile(String mobile) {
45 | this.mobile = mobile;
46 | }
47 |
48 | public Integer getAmount() {
49 | return amount;
50 | }
51 |
52 | public void setAmount(Integer amount) {
53 | this.amount = amount;
54 | }
55 |
56 | public String getOutTradeDate() {
57 | return outTradeDate;
58 | }
59 |
60 | public void setOutTradeDate(String outTradeDate) {
61 | this.outTradeDate = outTradeDate;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/domain/response/RuleResponse.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.domain.response;
2 |
3 | import com.tanghao.bigdata.drools.enums.EnumRuleResponseLevel;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * @Author: Canthny
9 | * @Description: 风控响应对象
10 | * @Date: Created in 2018/9/11 15:22
11 | */
12 | public class RuleResponse implements Serializable{
13 |
14 | private static final long serialVersionUID = 8501708883775504510L;
15 |
16 | public RuleResponse(String code, String level, String msg){
17 | this.code = code;
18 | this.level = level;
19 | this.msg = msg;
20 | }
21 |
22 | private String code;
23 |
24 | private String level;
25 |
26 | private String msg;
27 |
28 | public String getCode() {
29 | return code;
30 | }
31 |
32 | public void setCode(String code) {
33 | this.code = code;
34 | }
35 |
36 | public String getLevel() {
37 | return level;
38 | }
39 |
40 | public void setLevel(String level) {
41 | this.level = level;
42 | }
43 |
44 | public String getMsg() {
45 | return msg;
46 | }
47 |
48 | public void setMsg(String msg) {
49 | this.msg = msg;
50 | }
51 |
52 | public static Boolean checkIsNull(RuleResponse response){
53 | if (null==response){
54 | return true;
55 | }else{
56 | return false;
57 | }
58 | }
59 |
60 | @Override
61 | public String toString() {
62 | return "RuleResponse{" +
63 | "code='" + code + '\'' +
64 | ", level='" + EnumRuleResponseLevel.getDescByCode(level) + '\'' +
65 | ", msg='" + msg + '\'' +
66 | '}';
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/enums/EnumRuleResponseLevel.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.enums;
2 |
3 | /**
4 | * @Author: Canthny
5 | * @Description: 风控响应级别
6 | * @Date: Created in 2018/9/11 15:23
7 | */
8 | public enum EnumRuleResponseLevel {
9 |
10 | NONE("0","无风险"),
11 | LOW("1","低风险"),
12 | MIDDLE("2","中风险 "),
13 | HIGH("3","高风险"),
14 | SUPER("4","超高风险");
15 |
16 | private String code;
17 |
18 | private String desc;
19 |
20 | public String getCode() {
21 | return code;
22 | }
23 |
24 | public void setCode(String code) {
25 | this.code = code;
26 | }
27 |
28 | public String getDesc() {
29 | return desc;
30 | }
31 |
32 | public void setDesc(String desc) {
33 | this.desc = desc;
34 | }
35 |
36 | EnumRuleResponseLevel(String code, String desc){
37 | this.code = code;
38 | this.desc = desc;
39 | }
40 |
41 | public static String getDescByCode(String code){
42 | if (code == null) {
43 | return null;
44 | }
45 | for (EnumRuleResponseLevel level : values()) {
46 | if (level.getCode().equals(code)) {
47 | return level.getDesc();
48 | }
49 | }
50 | return null;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/kafka/config/MobilePaymentInfoConfig.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.kafka.config;
2 |
3 | import com.tanghao.bigdata.drools.kafka.listener.MobilePaymentInfoListener;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.kafka.core.ConsumerFactory;
8 | import org.springframework.kafka.listener.KafkaMessageListenerContainer;
9 | import org.springframework.kafka.listener.config.ContainerProperties;
10 | import org.springframework.stereotype.Component;
11 |
12 | /**
13 | * @Author: Canthny
14 | * @Description: 手机充值消息配置
15 | * @Date: Created in 2018/9/29 10:24
16 | */
17 | @Configuration
18 | @Component
19 | public class MobilePaymentInfoConfig {
20 |
21 | @Autowired
22 | MobilePaymentInfoListener mobilePaymentInfoListener;
23 |
24 | @Bean
25 | ContainerProperties containerProperties(){
26 | //配置监听topic
27 | ContainerProperties containerProperties = new ContainerProperties("mobile_pay_info");
28 | containerProperties.setMessageListener(mobilePaymentInfoListener);
29 | return containerProperties;
30 | }
31 | @Bean
32 | KafkaMessageListenerContainer messageListenerContainer(ConsumerFactory consumerFactory,
33 | ContainerProperties containerProperties){
34 | return new KafkaMessageListenerContainer(consumerFactory, containerProperties);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/kafka/listener/MobilePaymentInfoListener.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.kafka.listener;
2 |
3 | import com.tanghao.bigdata.drools.domain.MobilePaymentInfo;
4 | import com.tanghao.bigdata.drools.mongodb.service.MobilePaymentInfoService;
5 | import org.apache.kafka.clients.consumer.ConsumerRecord;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.kafka.listener.MessageListener;
8 | import org.springframework.stereotype.Component;
9 | import com.alibaba.fastjson.JSON;
10 |
11 | /**
12 | * @Author: Canthny
13 | * @Description: 手机充值消息监听者
14 | * @Date: Created in 2018/9/29 10:27
15 | */
16 | @Component
17 | public class MobilePaymentInfoListener implements MessageListener{
18 |
19 | @Autowired
20 | MobilePaymentInfoService mobilePaymentInfoService;
21 |
22 |
23 | @Override
24 | public void onMessage(ConsumerRecord stringStringConsumerRecord) {
25 | String info = stringStringConsumerRecord.value();
26 | System.out.println(info);
27 | MobilePaymentInfo mobilePaymentInfo = JSON.parseObject(info,MobilePaymentInfo.class);
28 | mobilePaymentInfoService.saveMobilePaymentInfo(mobilePaymentInfo);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/mongodb/config/SpringMongoConfig.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.mongodb.config;
2 |
3 | import com.mongodb.MongoClientURI;
4 | import org.springframework.beans.factory.annotation.Value;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.data.mongodb.MongoDbFactory;
8 | import org.springframework.data.mongodb.core.MongoTemplate;
9 | import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
10 | import org.springframework.data.mongodb.core.convert.DbRefResolver;
11 | import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
12 | import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
13 | import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
14 | import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
15 |
16 | /**
17 | * @Author: Canthny
18 | * @Description: mongodb配置
19 | * @Date: Created in 2018/9/29 11:21
20 | */
21 | @Configuration
22 | public class SpringMongoConfig{
23 |
24 | private @Value("${spring.data.mongodb.uri}") String uri;
25 |
26 | public @Bean
27 | MongoDbFactory mongoDbFactory() throws Exception {
28 | return new SimpleMongoDbFactory(new MongoClientURI(uri));
29 | }
30 |
31 | public @Bean
32 | MongoTemplate mongoTemplate() throws Exception {
33 |
34 | // MappingMongoConverter converter =
35 | // new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
36 |
37 | DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
38 | MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, new MongoMappingContext());
39 | //这里是为了去掉插入mongodb时自动添加的_class类
40 | converter.setTypeMapper(new DefaultMongoTypeMapper(null));
41 | MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory(), converter);
42 |
43 | return mongoTemplate;
44 |
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/mongodb/service/MobilePaymentInfoService.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.mongodb.service;
2 |
3 | import com.tanghao.bigdata.drools.domain.MobilePaymentInfo;
4 |
5 | /**
6 | * @Author: Canthny
7 | * @Description: 手机缴费信息接口
8 | * @Date: Created in 2018/9/27 14:46
9 | */
10 | public interface MobilePaymentInfoService {
11 |
12 | public void saveMobilePaymentInfo(MobilePaymentInfo info);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/mongodb/service/impl/MobilePaymentInfoServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.mongodb.service.impl;
2 |
3 | import com.tanghao.bigdata.drools.domain.MobilePaymentInfo;
4 | import com.tanghao.bigdata.drools.mongodb.service.MobilePaymentInfoService;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.data.mongodb.core.MongoOperations;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * @Author: Canthny
11 | * @Description: 手机缴费信息接口实现类
12 | * @Date: Created in 2018/9/27 14:47
13 | */
14 | @Component("mobilePaymentInfoService")
15 | public class MobilePaymentInfoServiceImpl implements MobilePaymentInfoService{
16 |
17 | @Autowired
18 | MongoOperations mongoTemplate;
19 |
20 | public void saveMobilePaymentInfo(MobilePaymentInfo info) {
21 | mongoTemplate.save(info);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/redis/RedisConfig.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.redis;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.data.redis.connection.RedisConnectionFactory;
6 | import org.springframework.data.redis.core.RedisTemplate;
7 | import org.springframework.data.redis.serializer.RedisSerializer;
8 | import org.springframework.data.redis.serializer.StringRedisSerializer;
9 | import org.springframework.util.Assert;
10 |
11 | import java.nio.charset.Charset;
12 |
13 | /**
14 | * @Author: Canthny
15 | * @Description: redis模板类序列化问题配置
16 | * @Date: Created in 2018/9/29 21:40
17 | */
18 | @Configuration
19 | public class RedisConfig {
20 |
21 | /**
22 | * redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类
23 | * @return
24 | */
25 | /**
26 | * redisTemplate默认jdkSerializeable,key会产生\xac\xed\x00\x05t\x00\x13这样的字符,所以设置成StringRedisSerializer
27 | * @return
28 | */
29 | @Bean
30 | public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
31 | RedisTemplate redisTemplate = new RedisTemplate();
32 | RedisSerializer stringSerializer = new StringRedisSerializer();
33 | redisTemplate.setKeySerializer(stringSerializer);
34 | redisTemplate.setValueSerializer(stringSerializer);
35 | redisTemplate.setHashKeySerializer(stringSerializer);
36 | redisTemplate.setHashValueSerializer(new IntegerRedisSerializer());
37 | redisTemplate.setConnectionFactory(factory);
38 | return redisTemplate;
39 | }
40 |
41 | public class IntegerRedisSerializer implements RedisSerializer {
42 |
43 | private final Charset charset;
44 |
45 | public IntegerRedisSerializer() {
46 | this(Charset.forName("UTF8"));
47 | }
48 |
49 | public IntegerRedisSerializer(Charset charset) {
50 | Assert.notNull(charset, "Charset must not be null!");
51 | this.charset = charset;
52 | }
53 |
54 | public Integer deserialize(byte[] bytes) {
55 | return (bytes == null ? null : Integer.parseInt(new String(bytes, charset)));
56 | }
57 |
58 | public byte[] serialize(Integer num) {
59 | return (num == null ? null : String.valueOf(num).getBytes(charset));
60 | }
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/service/MobilePaymentRuleService.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.service;
2 |
3 | import com.mongodb.BasicDBObject;
4 | import com.tanghao.bigdata.drools.domain.DefeatMapReduceObject;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.data.mongodb.core.MongoTemplate;
7 | import org.springframework.data.mongodb.core.query.BasicQuery;
8 | import org.springframework.data.mongodb.core.query.Query;
9 | import org.springframework.data.redis.core.RedisTemplate;
10 | import org.springframework.stereotype.Component;
11 |
12 | import javax.annotation.PostConstruct;
13 | import java.util.List;
14 |
15 | /**
16 | * @Author: Canthny
17 | * @Description: 缴费规则服务
18 | * @Date: Created in 2018/9/30 0:12
19 | */
20 | @Component
21 | public class MobilePaymentRuleService {
22 |
23 | @Autowired
24 | private RedisTemplate redisTemplate;
25 |
26 | @Autowired
27 | private MongoTemplate mongoTemplate;
28 |
29 | private static MobilePaymentRuleService mobilePaymentRuleService;
30 |
31 | @PostConstruct
32 | public void init() {
33 | mobilePaymentRuleService = this;
34 | mobilePaymentRuleService.redisTemplate = this.redisTemplate;
35 | mobilePaymentRuleService.mongoTemplate = this.mongoTemplate;
36 | }
37 |
38 | public static Integer getAvgAmountPerMonthByAccountNo(String accountNo){
39 | Integer amount = (Integer)mobilePaymentRuleService.redisTemplate.opsForHash().get("AvgAmountPerMonthByAccountNo",accountNo);
40 | if(null==amount){
41 | BasicDBObject queryObject=new BasicDBObject();
42 | queryObject.put("_id",accountNo);
43 | BasicDBObject fieldsObject=new BasicDBObject();//指定返回的字段fieldsObject.put("name", true);
44 | fieldsObject.put("_id", true);
45 | fieldsObject.put("value", true);
46 | Query query = new BasicQuery(queryObject,fieldsObject);
47 | List list= mobilePaymentRuleService.mongoTemplate.find(query,DefeatMapReduceObject.class,"ACCOUNT_MOBILEPAYMENT_DAY_AVG");
48 | amount = list.get(0).getValue();
49 | mobilePaymentRuleService.redisTemplate.opsForHash().put("AvgAmountPerMonthByAccountNo",list.get(0).getId(),list.get(0).getValue());
50 | }
51 | //TODO 这里有很多空判断NullPointException,当空的时候应该返回什么呢,成功or失败,还是返回金额在rule文件里再去判断
52 |
53 | return amount;
54 | }
55 |
56 | /**
57 | * 从缓存中获取流计算结果,该用户一小时内充值次数
58 | * @param accountNo
59 | * @return
60 | */
61 | public static Integer getCountPerHourByAccountNo(String accountNo){
62 | Integer amount = (Integer)mobilePaymentRuleService.redisTemplate.opsForHash().get("CountPerHourByAccountNo",accountNo);
63 | return null==amount?0:amount;
64 |
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/service/PhoneNoBlacklistService.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.service;
2 |
3 | import com.mongodb.BasicDBObject;
4 | import com.tanghao.bigdata.drools.domain.PhoneNoBlackObject;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.data.mongodb.core.MongoTemplate;
7 | import org.springframework.data.mongodb.core.query.BasicQuery;
8 | import org.springframework.data.mongodb.core.query.Query;
9 | import org.springframework.data.redis.core.RedisTemplate;
10 | import org.springframework.data.redis.serializer.RedisSerializer;
11 | import org.springframework.data.redis.serializer.StringRedisSerializer;
12 | import org.springframework.stereotype.Component;
13 | import org.springframework.util.CollectionUtils;
14 |
15 | import javax.annotation.PostConstruct;
16 | import java.util.HashSet;
17 | import java.util.List;
18 | import java.util.Set;
19 |
20 | /**
21 | * @Author: Canthny
22 | * @Description: 手机号黑名单
23 | * @Date: Created in 2018/9/29 15:54
24 | */
25 | @Component
26 | public class PhoneNoBlacklistService {
27 |
28 | @Autowired
29 | private RedisTemplate redisTemplate;
30 |
31 | @Autowired
32 | private MongoTemplate mongoTemplate;
33 |
34 | private static PhoneNoBlacklistService phoneNoBlacklistService;
35 |
36 | @PostConstruct
37 | public void init() {
38 | phoneNoBlacklistService = this;
39 | phoneNoBlacklistService.redisTemplate = this.redisTemplate;
40 | phoneNoBlacklistService.mongoTemplate = this.mongoTemplate;
41 | }
42 |
43 | public static boolean isBlack(String phoneNo){
44 | Set resultSet = (HashSet)phoneNoBlacklistService.redisTemplate.opsForSet().members("PHONE_NO_BLACK_LIST");
45 | if(CollectionUtils.isEmpty(resultSet)) {
46 | resultSet = getPhoneNoBlackListFromMongoDb();
47 | phoneNoBlacklistService.redisTemplate.opsForSet().add("PHONE_NO_BLACK_LIST",resultSet.toArray());
48 | }
49 | if(resultSet.contains(phoneNo)){
50 | return true;
51 | }else{
52 | return false;
53 | }
54 | }
55 |
56 | private static Set getPhoneNoBlackListFromMongoDb(){
57 | BasicDBObject fieldsObject=new BasicDBObject();//指定返回的字段fieldsObject.put("name", true);
58 | fieldsObject.put("phone_no", true);
59 | Query query = new BasicQuery(new BasicDBObject(),fieldsObject);
60 | List list= phoneNoBlacklistService.mongoTemplate.find(query,PhoneNoBlackObject.class,"PHONE_NO_BLACK_LIST");
61 | Set phoneNoBlackListSet = new HashSet();
62 | for(PhoneNoBlackObject info:list){
63 | phoneNoBlackListSet.add(info.getPhoneNo());
64 | }
65 |
66 | return phoneNoBlackListSet;
67 | }
68 | }
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/java/com/tanghao/bigdata/drools/util/DateUtil.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.util;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.sql.Timestamp;
7 | import java.text.ParseException;
8 | import java.text.SimpleDateFormat;
9 | import java.util.Calendar;
10 | import java.util.Date;
11 |
12 | /**
13 | * Date Utility Class used to convert Strings to Dates and Timestamps
14 | *
15 | * @author Matt Raible Modified by
16 | * Dan Kibler to correct time
17 | * pattern. Minutes should be mm not MM (MM is month).
18 | */
19 | public class DateUtil {
20 |
21 | private static Logger log = LoggerFactory.getLogger(DateUtil.class);
22 | private static final String TIME_PATTERN = "HH:mm";
23 | private static final String TIME_PATTERN_ALL = "yyyy-MM-dd HH:mm:ss.S";
24 | private static final String TIME_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
25 | private static final String TIME_YYYY_MM_DD = "yyyy-MM-dd";
26 | private static final String TIME_FORM_ALL = "yyyyMMddHHmmss";
27 | private static final String TIME_YYYY_MMDD_HHMMSS_SSS = "yyyyMMddHHmmssSSS";
28 | private static final String TIME_FORM = "HHmmss";
29 | private static final String DATE_FORM = "yyyyMMdd";
30 |
31 | /**
32 | * Checkstyle rule: utility classes should not have public constructor
33 | */
34 | public DateUtil() {
35 | }
36 |
37 | /**
38 | * Timestamp和String之间转换的函数:
39 | */
40 | public static String converTimestampToString(Timestamp obj) {
41 | return converTimestampToString(TIME_YYYY_MM_DD, obj);
42 | }
43 |
44 | /**
45 | * 自定义 转换模式将Timestamp 输出
46 | */
47 | public static String converTimestampToString(String formatPattern, Timestamp obj) {
48 | SimpleDateFormat df = new SimpleDateFormat(formatPattern);
49 | String str = df.format(obj);
50 | return str;
51 | }
52 |
53 | /**
54 | * String转化为Timestamp:
55 | */
56 | public static Timestamp converStringToTimestamp(String str) {
57 | Timestamp ts = Timestamp.valueOf(str);
58 | return ts;
59 | }
60 |
61 | /**
62 | * Return default datePattern (MM/dd/yyyy)
63 | *
64 | * @return a string representing the date pattern on the UI
65 | */
66 | private static String getDatePattern() {
67 | String defaultDatePattern = "MM/dd/yyyy";
68 | // try {
69 | // defaultDatePattern = ResourceBundle.getBundle(Constants.BUNDLE_KEY,
70 | // locale).getString(
71 | // "date.format");
72 | // } catch (MissingResourceException mse) {
73 | // defaultDatePattern = "MM/dd/yyyy";
74 | // }
75 |
76 | return defaultDatePattern;
77 | }
78 |
79 | public static String getDateTimePattern() {
80 | return DateUtil.getDatePattern() + " HH:mm:ss.S";
81 | }
82 |
83 | /**
84 | * This method attempts to convert an Oracle-formatted date in the form
85 | * dd-MMM-yyyy to mm/dd/yyyy.
86 | *
87 | * @param aDate
88 | * date from database as a string
89 | * @return formatted string for the ui
90 | */
91 | public static String getDate(Date aDate) {
92 | SimpleDateFormat df;
93 | String returnValue = "";
94 |
95 | if (aDate != null) {
96 | df = new SimpleDateFormat(getDatePattern());
97 | returnValue = df.format(aDate);
98 | }
99 |
100 | return (returnValue);
101 | }
102 |
103 | /**
104 | * This method generates a string representation of a date/time in the
105 | * format you specify on input
106 | *
107 | * @param aMask
108 | * the date pattern the string is in
109 | * @param strDate
110 | * a string representation of a date
111 | * @return a converted Date object
112 | * @see SimpleDateFormat
113 | * @throws ParseException
114 | * when String doesn't match the expected format
115 | */
116 | public static Date convertStringToDate(String aMask, String strDate) {
117 | SimpleDateFormat df;
118 | Date date = null;
119 | df = new SimpleDateFormat(aMask);
120 |
121 | if (log.isDebugEnabled()) {
122 | log.debug("converting '" + strDate + "' to date with mask '" + aMask + "'");
123 | }
124 | try {
125 | date = df.parse(strDate);
126 | } catch (ParseException pe) {
127 | log.error("Could not convert '" + strDate + "' to a date, throwing exception");
128 | log.error("", pe);
129 | }
130 |
131 | return date;
132 | }
133 |
134 | /**
135 | * This method returns the current date time in the format: MM/dd/yyyy HH:MM
136 | * a
137 | *
138 | * @param theTime
139 | * the current time
140 | * @return the current date/time
141 | */
142 | public static String getTimeNow(Date theTime) {
143 | return getDateTime(TIME_PATTERN, theTime);
144 | }
145 |
146 | /**
147 | * This method returns the current date in the format: MM/dd/yyyy
148 | *
149 | * @return the current date
150 | * @throws ParseException
151 | * when String doesn't match the expected format
152 | */
153 | public static Calendar getCalendarToday() {
154 | Calendar cal = Calendar.getInstance();
155 | return cal;
156 | }
157 |
158 | /**
159 | * This method generates a string representation of a date's date/time in
160 | * the format you specify on input
161 | *
162 | * @param aMask
163 | * the date pattern the string is in
164 | * @param aDate
165 | * a date object
166 | * @return a formatted string representation of the date
167 | *
168 | * @see SimpleDateFormat
169 | */
170 | private static String getDateTime(String aMask, Date aDate) {
171 | SimpleDateFormat df = null;
172 | String returnValue = "";
173 |
174 | if (aDate == null) {
175 | log.info("aDate is null!");
176 | } else {
177 | df = new SimpleDateFormat(aMask);
178 | returnValue = df.format(aDate);
179 | }
180 |
181 | return (returnValue);
182 | }
183 |
184 | /**
185 | * This method generates a string representation of a date based on the
186 | * System Property 'dateFormat' in the format you specify on input
187 | *
188 | * @param aDate
189 | * A date to convert
190 | * @return a string representation of the date
191 | */
192 | public static String convertDateToString(Date aDate) {
193 | return getDateTime(getDatePattern(), aDate);
194 | }
195 |
196 | /**
197 | * This method converts a String to a date using the datePattern
198 | *
199 | * @param strDate
200 | * the date to convert (in format MM/dd/yyyy)
201 | * @return a date object
202 | */
203 | public static Date convertStringToDate(String strDate) {
204 | return convertStringToDate(getDatePattern(), strDate);
205 | }
206 |
207 | /**
208 | *
209 | * @param aDate
210 | * @return string YYYY_MM_DD
211 | */
212 | public static String convertDateToString(String pattern, Date aDate) {
213 | return getDateTime(pattern, aDate);
214 | }
215 |
216 | /**
217 | * 取得从startDate开始的前(正)/后(负)day天
218 | *
219 | * @param startDate
220 | * @param day
221 | * @return date
222 | */
223 | public static Date getRelativeDate(Date startDate, int day) {
224 | long myTime = (startDate.getTime() / 1000) + day * 24 * 60 * 60;
225 | startDate.setTime(myTime * 1000);
226 | return startDate;
227 | }
228 |
229 | /**
230 | * 取得从startDate开始的前(正)/后(负)minute分
231 | *
232 | * @param startDate
233 | * @param minute
234 | * @return date
235 | */
236 | public static Date getRelativeMinute(Date startDate, int minute) {
237 | Calendar calendar = Calendar.getInstance();
238 | try {
239 | calendar.setTime(startDate);
240 | calendar.add(Calendar.MINUTE, minute);
241 | return calendar.getTime();
242 | } catch (Exception e) {
243 | log.error("", e);
244 | return startDate;
245 | }
246 | }
247 |
248 | /**
249 | * 根据日期获取星期几
250 | *
251 | * @param date
252 | * java.util.Date对象,不能为null
253 | * @return int
254 | */
255 | public static int getDay(Date date) {
256 | Calendar cal = Calendar.getInstance();
257 | cal.setTime(date);
258 | return cal.get(Calendar.DAY_OF_WEEK) - 1;
259 | }
260 |
261 | /**
262 | * 统计两个时间差,返回的是天数(即24小时算一天,少于24小时就为0,用这个的时候最好把小时、分钟等去掉)
263 | *
264 | * @param beginStr
265 | * 开始时间
266 | * @param endStr
267 | * @param format
268 | * @return day
269 | */
270 | public static int countDays(String beginStr, String endStr, String format) {
271 | Date end = convertStringToDate(endStr, format);
272 | Date begin = convertStringToDate(beginStr, format);
273 | long times = end.getTime() - begin.getTime();
274 | return (int) (times / 60 / 60 / 1000 / 24);
275 | }
276 |
277 | /**
278 | * 获取8位数字的今天日期格式
279 | * @return
280 | */
281 | public static String getTodayYYYYMMDD() {
282 | return convertDateToString(DATE_FORM, new Date());
283 | }
284 |
285 | /**
286 | * 计算当前日期到结束日期的天小时分钟
287 | *
288 | * @param endDate
289 | * @return string
290 | */
291 | public static String getCountDays(Date endDate) {
292 | Date now = new Date();
293 | String returnString = "";
294 | try {
295 | long l = endDate.getTime() - now.getTime();
296 | if (l < 0) {
297 | return "00天00小时00分";
298 | }
299 | long day = l / (24 * 60 * 60 * 1000);
300 | if (day != 0) {
301 | returnString = day + "天";
302 | }
303 | long hour = (l / (60 * 60 * 1000) - day * 24);
304 | long min = ((l / (60 * 1000)) - day * 24 * 60 - hour * 60);
305 | returnString = returnString + hour + "小时" + min + "分";
306 | } catch (Exception e) {
307 | return returnString;
308 | }
309 | return returnString;
310 | }
311 |
312 | /**
313 | * 判断当前时间是否大于传入时间加传入天数
314 | *
315 | * @param date
316 | * 传入日期
317 | * @param day
318 | * 增加天数
319 | * @return true or false
320 | */
321 | public static boolean compareDate(Date date, int day) {
322 | Date newDate = getRelativeDate(date, day);
323 | return new Date().after(newDate);
324 | }
325 |
326 | public static int countDays(Date begin, Date end) {
327 | if (begin == null || end == null) {
328 | return -9999;
329 | }
330 | long times = end.getTime() - begin.getTime();
331 | return (int) (times / 60 / 60 / 1000 / 24);
332 | }
333 |
334 | /**
335 | *
336 | * 功能:天数向上取整,velocity使用
337 | *
338 | * @param in
339 | * @return int
340 | */
341 | public static int getWholeDay(String in) {
342 | Double double1 = Double.parseDouble(in);
343 | if (double1 < 0) {
344 | return 0;
345 | }
346 | return (int) Math.ceil(double1);
347 | }
348 |
349 | public static Timestamp getCurrentTimestamp() {
350 | Date today = new Date();
351 | return new Timestamp(today.getTime());
352 | }
353 |
354 | /**
355 | * 得到一个时间延后或前移几天的时间,nowdate为时间,delay为前移或后延的天数
356 | * @param nowdate yyyyMMdd
357 | * @param delay
358 | * @return
359 | */
360 | public static String getNextDay(String nowdate, int delay) {
361 | try {
362 | SimpleDateFormat format = new SimpleDateFormat(DATE_FORM);
363 | Date d = format.parse(nowdate);
364 | return getNextDay(d, delay);
365 | } catch (ParseException e) {
366 | log.error("", e);
367 | return null;
368 | }
369 | }
370 |
371 | public static String getNextDay(Date nowdate, int delay) {
372 | SimpleDateFormat format = new SimpleDateFormat(DATE_FORM);
373 | return format.format(getRelativeDate(nowdate, delay));
374 | }
375 |
376 | /**
377 | *
378 | * 当期时间的前后几小时
379 | *
380 | * @param hour
381 | * @return
382 | */
383 | public static String getTimeByHour(int hour) {
384 | Calendar calendar = Calendar.getInstance();
385 | calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + hour);
386 | return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar.getTime());
387 | // return new SimpleDateFormat("HH:mm:ss").format(calendar.getTime());
388 | }
389 |
390 | /**
391 | * 根据字符串日期获取对应的星期
392 | *
393 | * @param time
394 | * @return
395 | * @throws ParseException
396 | */
397 | public static String getWeek(String time) throws ParseException {
398 | final String[] dayNames = { "周日", "周一", "周二", "周三", "周四", "周五", "周六" };
399 | SimpleDateFormat sdfInput = new SimpleDateFormat("yyyy-MM-dd HH:mm");
400 | Calendar calendar = Calendar.getInstance();
401 | Date date = new Date();
402 | date = sdfInput.parse(time);
403 | calendar.setTime(date);
404 | int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
405 | if (dayOfWeek < 0) {
406 | dayOfWeek = 0;
407 | }
408 | return dayNames[dayOfWeek];
409 | }
410 | }
411 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/resources/META-INF/kmodule.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.data.mongodb.uri=mongodb://192.168.177.128:27017/rule
2 |
3 | #spring.kafka.bootstrap-servers=192.168.0.102:9092
4 | #spring.kafka.consumer.group-id=mobile_pay_info_into_db
5 | #spring.kafka.consumer.auto-offset-reset=latest
6 |
7 | # Redis缓存配置
8 | spring.redis.database=0
9 | spring.redis.host=localhost
10 | spring.redis.port=6379
11 | spring.redis.password=
12 | spring.redis.timeout=0
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/resources/com.tanghao.bigdata.drools.rules/pay_rule.drl:
--------------------------------------------------------------------------------
1 | import com.tanghao.bigdata.drools.domain.request.MobilePaymentRequest;
2 | import com.tanghao.bigdata.drools.domain.response.RuleResponse;
3 | import com.tanghao.bigdata.drools.enums.EnumRuleResponseLevel;
4 | import com.tanghao.bigdata.drools.service.PhoneNoBlacklistService;
5 | import com.tanghao.bigdata.drools.service.MobilePaymentRuleService;
6 | import com.tanghao.bigdata.drools.util.DateUtil;
7 |
8 | rule "pay_rule1"
9 | //执行顺序配置,数字越大优先级越高
10 | salience 4
11 | //对于自己规则操作引起的update重新匹配,不会重复执行,对于其他规则操作引起的update重新匹配会执行一次
12 | //当两个规则都满足,并且then中都会update的情况下就会进入死循环这时要使用lock-on-active属性保证规则只会执行一次
13 | //这里通过塞入响应对象以及前置空判断保证规则不会同时满足,只会执行一次
14 | no-loop true
15 | when
16 | $pay : MobilePaymentRequest(RuleResponse.checkIsNull(response) && amount > 300);
17 | then
18 | $pay.setResponse("9999",EnumRuleResponseLevel.LOW.getCode(),"金额单笔金额超300了");
19 | System.out.println("金额单笔金额超300了");
20 | update($pay);
21 | end
22 |
23 | rule "pay_rule2"
24 | salience 3
25 | no-loop true
26 | when
27 | $pay : MobilePaymentRequest(RuleResponse.checkIsNull(response) && PhoneNoBlacklistService.isBlack(mobile));
28 | then
29 | $pay.setResponse("9999",EnumRuleResponseLevel.LOW.getCode(),"手机号在黑名单中");
30 | System.out.println("手机号在黑名单中");
31 | update($pay);
32 | end
33 |
34 | rule "pay_rule3"
35 | salience 2
36 | no-loop true
37 | when
38 | $pay : MobilePaymentRequest(RuleResponse.checkIsNull(response) && amount > 3*MobilePaymentRuleService.getAvgAmountPerMonthByAccountNo(accountNo));
39 | then
40 | $pay.setResponse("9999",EnumRuleResponseLevel.MIDDLE.getCode(),"大于上月平均充值金额的3倍");
41 | System.out.println("大于上月平均充值金额的3倍");
42 | update($pay);
43 | end
44 |
45 | rule "pay_rule4"
46 | salience 1
47 | no-loop true
48 | when
49 | $pay : MobilePaymentRequest(RuleResponse.checkIsNull(response) && 10 < MobilePaymentRuleService.getCountPerHourByAccountNo(accountNo));
50 | then
51 | $pay.setResponse("9999",EnumRuleResponseLevel.HIGH.getCode(),"1小时内最多充值10次!");
52 | update($pay);
53 | end
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/resources/drools/pay_rule.drl:
--------------------------------------------------------------------------------
1 | import com.tanghao.bigdata.drools.domain.request.MobilePaymentRequest;
2 | import com.tanghao.bigdata.drools.domain.response.RuleResponse;
3 | import com.tanghao.bigdata.drools.enums.EnumRuleResponseLevel;
4 | import com.tanghao.bigdata.drools.service.PhoneNoBlacklistService;
5 | import com.tanghao.bigdata.drools.service.MobilePaymentRuleService;
6 | import com.tanghao.bigdata.drools.util.DateUtil;
7 |
8 | rule "pay_rule1"
9 | //执行顺序配置,数字越大优先级越高
10 | salience 4
11 | //对于自己规则操作引起的update重新匹配,不会重复执行,对于其他规则操作引起的update重新匹配会执行一次
12 | //当两个规则都满足,并且then中都会update的情况下就会进入死循环这时要使用lock-on-active属性保证规则只会执行一次
13 | //这里通过塞入响应对象以及前置空判断保证规则不会同时满足,只会执行一次
14 | no-loop true
15 | when
16 | $pay : MobilePaymentRequest(RuleResponse.checkIsNull(response) && amount > 300);
17 | then
18 | $pay.setResponse("9999",EnumRuleResponseLevel.LOW.getCode(),"金额单笔金额超300了");
19 | System.out.println("金额单笔金额超300了");
20 | update($pay);
21 | end
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/resources/drools/pay_rule2.drl:
--------------------------------------------------------------------------------
1 | import com.tanghao.bigdata.drools.domain.request.MobilePaymentRequest;
2 | import com.tanghao.bigdata.drools.domain.response.RuleResponse;
3 | import com.tanghao.bigdata.drools.enums.EnumRuleResponseLevel;
4 | import com.tanghao.bigdata.drools.service.PhoneNoBlacklistService;
5 | import com.tanghao.bigdata.drools.service.MobilePaymentRuleService;
6 | import com.tanghao.bigdata.drools.util.DateUtil;
7 |
8 | rule "pay_rule2"
9 | //执行顺序配置,数字越大优先级越高
10 | salience 3
11 | //对于自己规则操作引起的update重新匹配,不会重复执行,对于其他规则操作引起的update重新匹配会执行一次
12 | //当两个规则都满足,并且then中都会update的情况下就会进入死循环这时要使用lock-on-active属性保证规则只会执行一次
13 | //这里通过塞入响应对象以及前置空判断保证规则不会同时满足,只会执行一次
14 | no-loop true
15 | when
16 | $pay : MobilePaymentRequest(RuleResponse.checkIsNull(response) && amount > 290);
17 | then
18 | $pay.setResponse("9999",EnumRuleResponseLevel.LOW.getCode(),"金额单笔金额超290了");
19 | System.out.println("金额单笔金额超290了");
20 | update($pay);
21 | end
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/resources/mapreduce/mobile_payment_info_map.js:
--------------------------------------------------------------------------------
1 | function() {emit(this.account_no,this.amount);}
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/main/resources/mapreduce/mobile_payment_info_reduce.js:
--------------------------------------------------------------------------------
1 | function(key,values) {return Array.avg(values)}
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/test/java/com/tanghao/bigdata/drools/test/TestDrools.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.test;
2 |
3 | import com.tanghao.bigdata.drools.DroolsStarter;
4 | import com.tanghao.bigdata.drools.domain.request.MobilePaymentRequest;
5 | import com.tanghao.bigdata.drools.util.DateUtil;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.kie.api.KieServices;
9 | import org.kie.api.io.ResourceType;
10 | import org.kie.api.runtime.KieContainer;
11 | import org.kie.api.runtime.KieSession;
12 | import org.kie.internal.KnowledgeBase;
13 | import org.kie.internal.KnowledgeBaseFactory;
14 | import org.kie.internal.builder.KnowledgeBuilder;
15 | import org.kie.internal.builder.KnowledgeBuilderFactory;
16 | import org.kie.internal.io.ResourceFactory;
17 | import org.kie.internal.runtime.StatefulKnowledgeSession;
18 | import org.springframework.boot.test.context.SpringBootTest;
19 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
20 |
21 | import java.util.Date;
22 |
23 | /**
24 | * @Author: Canthny
25 | * @Description: drools单元测试类
26 | * @Date: Created in 2018/9/29 19:51
27 | */
28 | @RunWith(SpringJUnit4ClassRunner.class)
29 | @SpringBootTest(classes = DroolsStarter.class)
30 | public class TestDrools {
31 |
32 | /**
33 | *测试case1:金额超限
34 | */
35 | @Test
36 | public void testCase1(){
37 |
38 | KnowledgeBuilder knowledgeBuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
39 | knowledgeBuilder.add(ResourceFactory.newClassPathResource("drools/pay_rule.drl"), ResourceType.DRL);
40 | knowledgeBuilder.add(ResourceFactory.newClassPathResource("drools/pay_rule2.drl"), ResourceType.DRL);
41 | KnowledgeBase knowledgeBase = KnowledgeBaseFactory.newKnowledgeBase();
42 | knowledgeBase.addKnowledgePackages(knowledgeBuilder.getKnowledgePackages());
43 | StatefulKnowledgeSession knowledgeSession = knowledgeBase.newStatefulKnowledgeSession();
44 | MobilePaymentRequest payRequest = new MobilePaymentRequest();
45 | payRequest.setAccountNo("3691529391467418");
46 | payRequest.setAmount(351);//设置为大于单笔的最大限额,pay_rule.drl中规则pay_rule1配的是300
47 | payRequest.setOutTradeDate(DateUtil.convertDateToString("yyyyMMdd",new Date()));
48 | payRequest.setMobile("18709858763");
49 | payRequest.setBankCardNo("62260113241234");
50 | knowledgeSession.insert(payRequest);//具体的java类对象添加到workingMemory中。
51 | knowledgeSession.fireAllRules();
52 | knowledgeSession.dispose();
53 | System.out.println(payRequest.getResponse());
54 |
55 | // KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
56 | // KieSession ksession = kc.newKieSession("pay_rule");
57 | // MobilePaymentRequest payRequest = new MobilePaymentRequest();
58 | // payRequest.setAccountNo("3691529391467418");
59 | // payRequest.setAmount(351);//设置为大于单笔的最大限额,pay_rule.drl中规则pay_rule1配的是300
60 | // payRequest.setOutTradeDate(DateUtil.convertDateToString("yyyyMMdd",new Date()));
61 | // payRequest.setMobile("18709858763");
62 | // payRequest.setBankCardNo("62260113241234");
63 | // ksession.insert(payRequest);
64 | // ksession.fireAllRules();
65 | // ksession.dispose();
66 | // System.out.println(payRequest.getResponse());
67 | }
68 |
69 | /**
70 | * 该银行卡号在黑名单内(银行卡黑名单表)
71 | * 手机号在黑名单内(手机号黑名单表)
72 | */
73 | @Test
74 | public void testCase2(){
75 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
76 | KieSession ksession = kc.newKieSession("pay_rule");
77 | MobilePaymentRequest payRequest = new MobilePaymentRequest();
78 | payRequest.setAccountNo("3691529391467418");
79 | payRequest.setAmount(49);//金额不要超过单笔限额
80 | payRequest.setOutTradeDate(DateUtil.convertDateToString("yyyyMMdd",new Date()));
81 | payRequest.setMobile("18709858763");//手机号在黑名单中
82 | payRequest.setBankCardNo("62260113241234");
83 | ksession.insert(payRequest);
84 | ksession.fireAllRules();
85 | ksession.dispose();
86 | System.out.println(payRequest.getResponse());
87 | }
88 |
89 | /**
90 | * 当前单笔充值额度大于用户最近一个月充值额度平均值的3倍(定时批处理,月初统计上个月充值平均额度)
91 | */
92 | @Test
93 | public void testCase3(){
94 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
95 | KieSession ksession = kc.newKieSession("pay_rule");
96 | MobilePaymentRequest payRequest = new MobilePaymentRequest();
97 | payRequest.setAccountNo("3691529391467418");
98 | payRequest.setAmount(280);//设置为大于月平均值的3倍,且不超过单笔最大限额
99 | payRequest.setOutTradeDate(DateUtil.convertDateToString("yyyyMMdd",new Date()));
100 | payRequest.setMobile("18709858764");//手机号不在黑名单
101 | payRequest.setBankCardNo("62260113241234");
102 | ksession.insert(payRequest);
103 | ksession.fireAllRules();
104 | ksession.dispose();
105 | System.out.println(payRequest.getResponse());
106 | }
107 |
108 | /**
109 | * 一个小时内充值次数不超过5笔(实时流计算,保留用户一小时充值笔数)
110 | */
111 | @Test
112 | public void testCase4(){
113 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer();
114 | KieSession ksession = kc.newKieSession("pay_rule");
115 | MobilePaymentRequest payRequest = new MobilePaymentRequest();
116 | payRequest.setAccountNo("3691529391467418");
117 | payRequest.setAmount(220);//设置为小于月平均值的3倍,且不超过单笔最大限额
118 | payRequest.setOutTradeDate(DateUtil.convertDateToString("yyyyMMdd",new Date()));
119 | payRequest.setMobile("18709858764");//手机号不在黑名单
120 | payRequest.setBankCardNo("62260113241234");
121 | ksession.insert(payRequest);
122 | ksession.fireAllRules();
123 | ksession.dispose();
124 | System.out.println(payRequest.getResponse());
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/test/java/com/tanghao/bigdata/drools/test/TestKafkaProduct.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.test;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.tanghao.bigdata.drools.DroolsStarter;
5 | import com.tanghao.bigdata.drools.domain.MobilePaymentInfo;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.boot.test.context.SpringBootTest;
10 | import org.springframework.kafka.core.KafkaTemplate;
11 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
12 |
13 | import java.util.Date;
14 |
15 | /**
16 | * @Author: Canthny
17 | * @Description: kafka生产者测试
18 | * @Date: Created in 2018/9/29 15:02
19 | */
20 | @RunWith(SpringJUnit4ClassRunner.class)
21 | @SpringBootTest(classes = DroolsStarter.class)
22 | public class TestKafkaProduct {
23 |
24 | @Autowired
25 | KafkaTemplate kafkaTemplate;
26 |
27 | @Test
28 | public void testSendMobilePaymentInfo() {
29 | MobilePaymentInfo info = new MobilePaymentInfo();
30 | info.setAccountNo("3691529391467418");
31 | info.setAmount((int)(Math.random()*100));
32 | info.setBankCardNo("62260113241234");
33 | info.setMobile("18709858763");
34 | info.setPayOrderNo("2018090100001");
35 | info.setTime(new Date());
36 |
37 | String infoStr = JSONObject.toJSONString(info);
38 | kafkaTemplate.send("mobile_pay_info",infoStr);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/test/java/com/tanghao/bigdata/drools/test/TestMongodb.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.test;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.mongodb.BasicDBObject;
5 | import com.mongodb.QueryBuilder;
6 | import com.tanghao.bigdata.drools.DroolsStarter;
7 | import com.tanghao.bigdata.drools.domain.DefeatMapReduceObject;
8 | import com.tanghao.bigdata.drools.domain.MobilePaymentInfo;
9 | import com.tanghao.bigdata.drools.domain.PhoneNoBlackObject;
10 | import com.tanghao.bigdata.drools.mongodb.service.MobilePaymentInfoService;
11 | import com.tanghao.bigdata.drools.service.PhoneNoBlacklistService;
12 | import com.tanghao.bigdata.drools.util.DateUtil;
13 | import org.junit.Test;
14 | import org.junit.runner.RunWith;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.boot.test.context.SpringBootTest;
17 | import org.springframework.data.mongodb.core.MongoOperations;
18 | import org.springframework.data.mongodb.core.mapreduce.MapReduceOptions;
19 | import org.springframework.data.mongodb.core.query.BasicQuery;
20 | import org.springframework.data.mongodb.core.query.Criteria;
21 | import org.springframework.data.mongodb.core.query.Query;
22 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
23 |
24 | import java.text.ParseException;
25 | import java.text.SimpleDateFormat;
26 | import java.util.*;
27 |
28 | /**
29 | * @Author: Canthny
30 | * @Description: mongodb测试类
31 | * @Date: Created in 2018/9/27 14:54
32 | */
33 | @RunWith(SpringJUnit4ClassRunner.class)
34 | @SpringBootTest(classes = DroolsStarter.class)
35 | public class TestMongodb {
36 |
37 | @Autowired
38 | MobilePaymentInfoService mobilePaymentInfoService;
39 |
40 | @Autowired
41 | MongoOperations mongoTemplate;
42 |
43 | /**
44 | * 缴费数据插入
45 | * @throws ParseException
46 | */
47 | @Test
48 | public void testSave() throws ParseException {
49 | for(int i=0;i<10;i++){
50 | MobilePaymentInfo info = new MobilePaymentInfo();
51 | info.setAccountNo("3691529391467418");
52 | info.setAmount((int)(Math.random()*100));
53 | info.setBankCardNo("62260113241234");
54 | info.setMobile("18709858763");
55 | info.setPayOrderNo("2018090300001");
56 | // SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd" );
57 | // info.setTime(format.parse("2018-09-26"));
58 | if(i%3==0){
59 | info.setTime(DateUtil.getRelativeDate(new Date(),-1));
60 | }else if(i%3==1){
61 | info.setTime(new Date());
62 | }else if(i%3==2){
63 | info.setTime(DateUtil.getRelativeDate(new Date(),1));
64 | }
65 | mobilePaymentInfoService.saveMobilePaymentInfo(info);
66 | }
67 | }
68 |
69 | /**
70 | * 插入黑名单数据
71 | */
72 | @Test
73 | public void insertPhoneNoBlackList(){
74 | String phoneNo = "18709858763";
75 | PhoneNoBlackObject obj = new PhoneNoBlackObject();
76 | obj.setPhoneNo(phoneNo);
77 | mongoTemplate.save(obj);
78 |
79 |
80 |
81 | }
82 |
83 | /**
84 | * mongodb mapreduce批处理任务,可以通过定时器去执行,也可以通过crontab定时任务方式去执行脚本
85 | * 计算三天内用户缴费平均值
86 | * @throws ParseException
87 | */
88 | @Test
89 | public void testMapReduce() throws ParseException {
90 | Query query = new Query();
91 | SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd" );
92 | Criteria criteria = Criteria.where("time").gte(DateUtil.getRelativeDate(new Date(),-1)).lte(DateUtil.getRelativeDate(new Date(),1));
93 | query.addCriteria(criteria);
94 | MapReduceOptions mapReduceOptions = new MapReduceOptions();
95 | mapReduceOptions.outputCollection("ACCOUNT_MOBILEPAYMENT_DAY_AVG");
96 | mongoTemplate.mapReduce(query, "MOBILE_PAYMENT_INFO","classpath:mapreduce/mobile_payment_info_map.js", "classpath:mapreduce/mobile_payment_info_reduce.js",
97 | mapReduceOptions, HashMap.class);
98 | }
99 |
100 | /**
101 | * mongodb查询,指定查询条件和查询结果字段
102 | */
103 | @Test
104 | public void findPhonenNoBlackList(){
105 | BasicDBObject fieldsObject=new BasicDBObject();//指定返回的字段fieldsObject.put("name", true);
106 | fieldsObject.put("phone_no", true);
107 | Query query = new BasicQuery(new BasicDBObject(),fieldsObject);
108 | List list= mongoTemplate.find(query,PhoneNoBlackObject.class,"PHONE_NO_BLACK_LIST");
109 | Set phoneNoBlackListSet = new HashSet();
110 | for(PhoneNoBlackObject info:list){
111 | phoneNoBlackListSet.add(info.getPhoneNo());
112 | }
113 | System.out.println(phoneNoBlackListSet.toArray());
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/test/java/com/tanghao/bigdata/drools/test/TestMongodbJob.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.test;
2 |
3 | /**
4 | * @Author: Canthny
5 | * @Description:
6 | * @Date: Created in 2018/9/29 15:29
7 | */
8 | public class TestMongodbJob {
9 |
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/tanghao-bigdata-drools/src/test/java/com/tanghao/bigdata/drools/test/TestRuleService.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.bigdata.drools.test;
2 |
3 | import com.tanghao.bigdata.drools.DroolsStarter;
4 | import com.tanghao.bigdata.drools.service.MobilePaymentRuleService;
5 | import com.tanghao.bigdata.drools.service.PhoneNoBlacklistService;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.springframework.boot.test.context.SpringBootTest;
9 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
10 |
11 | /**
12 | * @Author: Canthny
13 | * @Description: 规则服务类测试
14 | * @Date: Created in 2018/9/30 0:49
15 | */
16 | @RunWith(SpringJUnit4ClassRunner.class)
17 | @SpringBootTest(classes = DroolsStarter.class)
18 | public class TestRuleService {
19 |
20 | @Test
21 | public void testPhoneNoBlacklistService(){
22 | System.out.println(PhoneNoBlacklistService.isBlack("18709858763"));
23 | }
24 |
25 | @Test
26 | public void testMobilePaymentRuleService(){
27 | System.out.println(MobilePaymentRuleService.getAvgAmountPerMonthByAccountNo("3691529391467418"));
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | tanghao.flink.demo
8 | tanghao-flink-demo
9 | 1.0-SNAPSHOT
10 | jar
11 |
12 | tanghao flink demo
13 |
14 |
15 | UTF-8
16 | 1.10.0
17 |
18 |
19 |
20 |
21 | org.apache.flink
22 | flink-connector-kafka-0.11_2.11
23 | ${flink.version}
24 |
25 |
26 | org.apache.flink
27 | flink-java
28 | ${flink.version}
29 |
30 |
31 | org.apache.flink
32 | flink-streaming-java_2.11
33 | ${flink.version}
34 |
35 |
36 | org.apache.flink
37 | flink-clients_2.11
38 | ${flink.version}
39 |
40 |
41 | log4j
42 | log4j
43 | 1.2.17
44 |
45 |
46 | org.slf4j
47 | slf4j-api
48 | 1.7.25
49 |
50 |
51 | org.slf4j
52 | slf4j-log4j12
53 | 1.7.25
54 |
55 |
56 | org.apache.flink
57 | flink-json
58 | 1.6.0
59 |
60 |
61 | com.alibaba
62 | fastjson
63 | 1.2.62
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | org.apache.maven.plugins
78 | maven-shade-plugin
79 | 3.0.0
80 |
81 |
82 | package
83 |
84 | shade
85 |
86 |
87 |
88 |
89 | com.google.code.findbugs:jsr305
90 |
91 |
92 |
93 |
94 |
95 |
96 |
98 | *:*
99 |
100 | META-INF/*.SF
101 | META-INF/*.DSA
102 | META-INF/*.RSA
103 |
104 |
105 |
106 |
107 |
108 | com.tanghao.flink.demo.GetPayInfoJob
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/README.md:
--------------------------------------------------------------------------------
1 | 执行计划:https://flink.apache.org/visualizer/
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/GetPayInfoJob.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo;
2 |
3 | import org.apache.flink.api.common.functions.MapFunction;
4 | import org.apache.flink.api.common.functions.ReduceFunction;
5 | import org.apache.flink.api.common.serialization.SimpleStringSchema;
6 | import org.apache.flink.api.java.tuple.Tuple;
7 | import org.apache.flink.api.java.tuple.Tuple2;
8 | import org.apache.flink.api.java.tuple.Tuple3;
9 | import org.apache.flink.formats.json.JsonNodeDeserializationSchema;
10 | import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.node.ObjectNode;
11 | import org.apache.flink.streaming.api.datastream.DataStream;
12 | import org.apache.flink.streaming.api.datastream.KeyedStream;
13 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
14 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
15 | import org.apache.flink.streaming.api.functions.timestamps.BoundedOutOfOrdernessTimestampExtractor;
16 | import org.apache.flink.streaming.api.windowing.assigners.SlidingEventTimeWindows;
17 | import org.apache.flink.streaming.api.windowing.assigners.SlidingProcessingTimeWindows;
18 | import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
19 | import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
20 | import org.apache.flink.streaming.api.windowing.time.Time;
21 | import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;
22 |
23 | import java.text.ParseException;
24 | import java.text.SimpleDateFormat;
25 | import java.util.Date;
26 | import java.util.Properties;
27 |
28 | /**
29 | * @Author: Canthny
30 | * @Description: 获取支付信息日志流计算job
31 | * @Date: Created in 2018/9/13 2:06
32 | */
33 | public class GetPayInfoJob {
34 |
35 | public static void main(String[] args) throws Exception {
36 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
37 |
38 | Properties properties = new Properties();
39 | properties.setProperty("bootstrap.servers", "192.168.8.145:9082");
40 |
41 |
42 | // DataStream stream = env.addSource(new FlinkKafkaConsumer011("20180913", new SimpleStringSchema(), properties));
43 | SingleOutputStreamOperator stream= env.addSource(new FlinkKafkaConsumer011("CountPerHourByAccountNo2", new JsonNodeDeserializationSchema(), properties));
44 | // SingleOutputStreamOperator> stream = env.addSource(new FlinkKafkaConsumer011("20180913", new JsonNodeDeserializationSchema(), properties));
45 |
46 | SingleOutputStreamOperator objectNodeOperator = stream.assignTimestampsAndWatermarks(new BoundedOutOfOrdernessTimestampExtractor(Time.seconds(15)) {
47 | @Override
48 | public long extractTimestamp(ObjectNode element) {
49 | SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
50 | Date eventTime = null;
51 | try {
52 | eventTime = format.parse(element.get("eventTime").asText());
53 | } catch (ParseException e) {
54 | e.printStackTrace();
55 | }
56 | return eventTime.getTime();
57 | }
58 | });
59 |
60 | KeyedStream, Tuple> keyBy = objectNodeOperator.map(new MapFunction>() {
61 | public Tuple2 map(ObjectNode jsonNodes) throws Exception {
62 | System.out.println(jsonNodes.get("accountId").asText() + "==map====" + jsonNodes.get("amount").asLong());
63 | return new Tuple2(jsonNodes.get("accountId").asText(), jsonNodes.get("amount").asLong());
64 | }
65 | }).keyBy(0);
66 |
67 | testTumblingEventTimeWindows(keyBy);
68 |
69 | // stream.keyBy(0).timeWindow(Time.minutes(1)).sum(1);
70 | stream.print();
71 | env.execute();
72 | }
73 |
74 | private static void testTumblingEventTimeWindows(KeyedStream, Tuple> keyBy) {
75 | keyBy.window(TumblingEventTimeWindows.of(Time.seconds(5))).reduce(new ReduceFunction>()
76 | {
77 | public Tuple2 reduce(Tuple2 v1, Tuple2 v2) {
78 | Tuple2 test = new Tuple2(v1.f0, v1.f1 + v2.f1);
79 | System.out.println(test);
80 | return test;
81 | }
82 | });
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/TestAction.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo;
2 |
3 | import org.apache.flink.formats.json.JsonNodeDeserializationSchema;
4 | import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.ObjectMapper;
5 | import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.node.ObjectNode;
6 | import org.apache.flink.streaming.util.serialization.JSONKeyValueDeserializationSchema;
7 |
8 | /**
9 | * @Author: Canthny
10 | * @Description: 测试一些api
11 | * @Date: Created in 2018/9/13 15:15
12 | */
13 | public class TestAction {
14 |
15 | public static void main(String[] args) {
16 | try{
17 | // ObjectMapper mapper = new ObjectMapper();
18 | // ObjectNode initialKey = mapper.createObjectNode();
19 | // initialKey.put("index", 4);
20 | // byte[] serializedKey = mapper.writeValueAsBytes(initialKey);
21 | //
22 | // ObjectNode initialValue = mapper.createObjectNode();
23 | // initialValue.put("word", "world");
24 | // byte[] serializedValue = mapper.writeValueAsBytes(initialValue);
25 | //
26 | // JSONKeyValueDeserializationSchema schema = new JSONKeyValueDeserializationSchema(false);
27 | // ObjectNode deserializedValue = schema.deserialize(serializedKey, serializedValue, "", 0,
28 | // 0);
29 | // System.out.println(deserializedValue);
30 | //
31 | // String testjson = "{\"accountId\":\"0716\",\"amount\":\"100\",\"eventTime\":\"2018/09/13 14:56:00\"}";
32 | // JsonNodeDeserializationSchema schema1 = new JsonNodeDeserializationSchema();
33 | // ObjectNode node = schema1.deserialize(testjson.getBytes());
34 | // System.out.println(node);
35 | }catch (Exception e){
36 | System.out.println(e);
37 | }
38 |
39 |
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/api/datastream/FilterApiTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.api.datastream;
2 |
3 | import org.apache.flink.api.common.functions.FilterFunction;
4 | import org.apache.flink.streaming.api.datastream.DataStreamSource;
5 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
6 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
7 |
8 | import java.util.Arrays;
9 |
10 | /**
11 | * Description: FilterApi测试类
12 | * Created By tanghao on 2020/4/1
13 | */
14 | public class FilterApiTest {
15 |
16 | public static void main(String[] args) {
17 | StreamExecutionEnvironment streamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
18 | String[] strArray={"0","1","2","3","4","5","6","7","8","9","10"};
19 | DataStreamSource streamSource = streamExecutionEnvironment.fromCollection(Arrays.asList(strArray));
20 | SingleOutputStreamOperator streamAfterFilter = streamSource.filter(new FilterFunction() {
21 | public boolean filter(String s) throws Exception {
22 | if(Integer.parseInt(s) % 2==0){
23 | return true;
24 | }else{
25 | return false;
26 | }
27 | }
28 | });
29 |
30 | streamAfterFilter.print("双数流");
31 |
32 | SingleOutputStreamOperator streamAfterFilter2 = streamSource.filter(new FilterFunction() {
33 | public boolean filter(String s) throws Exception {
34 | if(Integer.parseInt(s) % 2==0){
35 | return false;
36 | }else{
37 | return true;
38 | }
39 | }
40 | });
41 | streamAfterFilter2.print("单数流");
42 |
43 |
44 | try {
45 | streamExecutionEnvironment.execute();
46 | } catch (Exception e) {
47 | e.printStackTrace();
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/api/datastream/FlatMapApiTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.api.datastream;
2 |
3 | import org.apache.flink.api.common.functions.FlatMapFunction;
4 | import org.apache.flink.streaming.api.datastream.DataStreamSource;
5 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
6 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
7 | import org.apache.flink.util.Collector;
8 |
9 | import java.util.Arrays;
10 |
11 | /**
12 | * Description: FlatMapApi测试类
13 | * Created By tanghao on 2020/4/1
14 | */
15 | public class FlatMapApiTest {
16 |
17 | public static void main(String[] args) {
18 | StreamExecutionEnvironment streamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
19 | String[] strArray={"blue,green,red","green,green,red","blue,blue","red"};
20 | DataStreamSource streamSource = streamExecutionEnvironment.fromCollection(Arrays.asList(strArray));
21 | SingleOutputStreamOperator stream = streamSource.flatMap(new FlatMapFunction() {
22 |
23 | /** flatMap相对于Map和filter更灵活,不仅仅一对一,也可以过滤也可以一对多 */
24 | public void flatMap(String s, Collector collector) throws Exception {
25 | String[] array = s.split(",");
26 | for (int i=0;i list = new ArrayList();
23 | list.add(new Message("1","1001",30L));
24 | list.add(new Message("2","2001",21L));
25 | list.add(new Message("3","2001",65L));
26 | list.add(new Message("4","1001",1L));
27 | list.add(new Message("5","2001",21L));
28 | DataStreamSource streamSource = streamExecutionEnvironment.fromCollection(list);
29 | KeyedStream keyedStream= streamSource.keyBy(new KeySelector() {
30 | public String getKey(Message message) throws Exception {
31 | return message.getTransCode();
32 | }
33 | });
34 |
35 | /** 根据类型统计每种类型的交易金额总和 */
36 | SingleOutputStreamOperator reduceResult = keyedStream.reduce(new ReduceFunction() {
37 | public Message reduce(Message message, Message message2) throws Exception {
38 | Long sum = message.getAmount() + message2.getAmount();
39 | String id = message.getId() + "_" +message2.getId();
40 | return new Message(id,message.getTransCode(),sum);
41 | }
42 | });
43 |
44 | reduceResult.print();
45 |
46 | /** 聚合函数,滚动输出当前key下最新的一条聚合操作后的记录 */
47 | // keyedStream.sum("amount").print();
48 | keyedStream.max("amount").print();
49 | // keyedStream.maxBy("amount").print();
50 | // keyedStream.min("amount").print();
51 | // keyedStream.minBy("amount").print();
52 |
53 | try {
54 | streamExecutionEnvironment.execute();
55 | } catch (Exception e) {
56 | e.printStackTrace();
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/api/datastream/MapApiTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.api.datastream;
2 |
3 | import org.apache.commons.collections.CollectionUtils;
4 | import org.apache.flink.api.common.functions.MapFunction;
5 | import org.apache.flink.streaming.api.datastream.DataStreamSource;
6 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
7 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
8 |
9 | import java.util.Arrays;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | /**
14 | * Description: MapApi测试
15 | * Created By tanghao on 2020/3/31
16 | */
17 | public class MapApiTest {
18 |
19 | public static void main(String[] args) {
20 | StreamExecutionEnvironment streamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
21 | String[] strArray={"deposit,10","withdraw,10","deposit,3","withdraw,10"};
22 | DataStreamSource streamSource = streamExecutionEnvironment.fromCollection(Arrays.asList(strArray));
23 | SingleOutputStreamOperator mapStream = streamSource.map(new MapFunction>() {
24 | public Map map(String s) throws Exception {
25 | String[] array = s.split(",");
26 | Map map = new HashMap();
27 | for (int i=0;i list1 = new ArrayList();
25 | list1.add(new Message("1","1001",30L));
26 | list1.add(new Message("4","1001",1L));
27 |
28 | DataStreamSource streamSource1 = streamExecutionEnvironment.fromCollection(list1);
29 |
30 | List list2 = new ArrayList();
31 | list2.add(new Message("2","2001",21L));
32 | list2.add(new Message("3","2001",65L));
33 | list2.add(new Message("5","2001",21L));
34 | DataStreamSource streamSource2 = streamExecutionEnvironment.fromCollection(list2);
35 |
36 | DataStream streamSource = streamSource1.union(streamSource2);
37 | // streamSource.print();
38 |
39 | /** SplitStream is deprecated,now use Side Outputs instead*/
40 | final OutputTag outputTag1001 = new OutputTag("side-output-1001"){};
41 | final OutputTag outputTag2001 = new OutputTag("side-output-2001"){};
42 |
43 | SingleOutputStreamOperator sideOutStream = streamSource.process(new ProcessFunction() {
44 | @Override
45 | public void processElement(Message value, Context ctx, Collector out) throws Exception {
46 | out.collect(value);
47 | if(value.getTransCode().equals("1001")){
48 | ctx.output(outputTag1001,value);
49 | }else if(value.getTransCode().equals("2001")){
50 | ctx.output(outputTag2001,value);
51 | }
52 | }
53 | });
54 | DataStream sideOutputStream1001 = sideOutStream.getSideOutput(outputTag1001);
55 | DataStream sideOutputStream2001 = sideOutStream.getSideOutput(outputTag2001);
56 |
57 | sideOutStream.print("all");
58 | sideOutputStream1001.print("1001");
59 | sideOutputStream2001.print("2001");
60 |
61 | try {
62 | streamExecutionEnvironment.execute();
63 | } catch (Exception e) {
64 | e.printStackTrace();
65 | }
66 |
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/api/others/BroadcastTableTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.api.others;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.tanghao.flink.demo.common.ConstantKafka;
5 | import com.tanghao.flink.demo.common.Message;
6 | import com.tanghao.flink.demo.common.TransTypeInfo;
7 | import org.apache.flink.api.common.functions.MapFunction;
8 | import org.apache.flink.api.common.serialization.SimpleStringSchema;
9 | import org.apache.flink.api.common.state.BroadcastState;
10 | import org.apache.flink.api.common.state.MapStateDescriptor;
11 | import org.apache.flink.api.common.state.ReadOnlyBroadcastState;
12 | import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
13 | import org.apache.flink.api.java.tuple.Tuple2;
14 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
15 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
16 | import org.apache.flink.streaming.api.functions.co.BroadcastProcessFunction;
17 | import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;
18 | import org.apache.flink.util.Collector;
19 |
20 | import java.util.Properties;
21 |
22 | /**
23 | * Description: 广播维表动态更新测试,对应的数据源为BroadcastMsgProducerTest产生的数据
24 | * 场景:上游的消息中仅包含id和code之类的数据要转化成对应的类目名称,从字典表或者动态广播流中获取映射关系,并且支持类目名称可更新或者开关控制
25 | * Created By tanghao on 2020/4/8
26 | */
27 | public class BroadcastTableTest {
28 |
29 | public static void main(String[] args) {
30 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
31 | Properties properties = new Properties();
32 | properties.setProperty("bootstrap.servers", "192.168.8.145:9082");
33 |
34 | /** 动态配置交易类型信息流,可以修改transCode对应的交易名称,也可以通过isOpen开关来展示是否要转换transName */
35 | SingleOutputStreamOperator stream= env.addSource(new FlinkKafkaConsumer011(ConstantKafka.TRANS_TYPE_TOPIC, new SimpleStringSchema(), properties)).map(new MapFunction() {
36 | public TransTypeInfo map(String s) throws Exception {
37 | return JSONObject.parseObject(s,TransTypeInfo.class);
38 | }
39 | });
40 |
41 | /** 业务消息中仅包含transCode交易编码,因此需要从广播表中获取交易编码对应的transName */
42 | SingleOutputStreamOperator messageStream= env.addSource(new FlinkKafkaConsumer011(ConstantKafka.TRADE_MESSAGE_TOPIC, new SimpleStringSchema(), properties)).map(new MapFunction() {
43 | public Message map(String s) throws Exception {
44 | return JSONObject.parseObject(s,Message.class);
45 | }
46 | });
47 |
48 | /** 存放transCode和transName的映射关系 */
49 | final MapStateDescriptor TRANS_TYPE_MAP = new MapStateDescriptor(
50 | "TRANS_TYPE_MAP",
51 | BasicTypeInfo.STRING_TYPE_INFO,
52 | BasicTypeInfo.STRING_TYPE_INFO);
53 |
54 | /** 将业务消息流和交易类型码流connect,并通过BroadcastProcessFunction设置业务消息处理方法和广播表更新方法 */
55 | SingleOutputStreamOperator> resStream = messageStream.connect(stream.broadcast(TRANS_TYPE_MAP)).process(new BroadcastProcessFunction>() {
56 | @Override
57 | public void processElement(Message value, ReadOnlyContext ctx, Collector> out) throws Exception {
58 | ReadOnlyBroadcastState broadcastState =
59 | ctx.getBroadcastState(TRANS_TYPE_MAP);
60 | String transName = broadcastState.get(value.getTransCode());
61 | out.collect(Tuple2.of(value,transName));
62 | }
63 |
64 | @Override
65 | public void processBroadcastElement(TransTypeInfo value, Context ctx, Collector> out) throws Exception {
66 | BroadcastState broadcastState =
67 | ctx.getBroadcastState(TRANS_TYPE_MAP);
68 | //判断开关,添加或者删除映射关系记录
69 | if(value.isOpen()){
70 | broadcastState.put(value.getTransCode(), value.getTransName());
71 | }else{
72 | broadcastState.remove(value.getTransCode());
73 | }
74 | }
75 | });
76 |
77 | resStream.print();
78 |
79 | /**
80 | * 从MessageKafkaProducerTest中producer交易类型信息的isOpen开关,输出结果如下:
81 | * 5> (Message{id='af02aa86-927d-47d2-af56-a4f06d5151c8', transCode='2001', amount=101, tradeTime=Wed Apr 08 17:14:06 CST 2020, userId=209},提现)
82 | * 5> (Message{id='0eca95a8-5d79-4e99-a992-a33c9ba20937', transCode='2001', amount=101, tradeTime=Wed Apr 08 17:14:21 CST 2020, userId=111},null)
83 | * 5> (Message{id='93731fd3-8ecb-4aaa-8ace-078b451de178', transCode='2001', amount=101, tradeTime=Wed Apr 08 17:15:06 CST 2020, userId=141},提现)
84 | */
85 |
86 | try {
87 | env.execute();
88 | } catch (Exception e) {
89 | e.printStackTrace();
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/api/window/GlobalWindowTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.api.window;
2 |
3 | /**
4 | * Description: TODO
5 | * Created By tanghao on 2020/4/7
6 | */
7 | public class GlobalWindowTest {
8 | }
9 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/api/window/SessionWindowTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.api.window;
2 |
3 | /**
4 | * Description: TODO
5 | * Created By tanghao on 2020/4/7
6 | */
7 | public class SessionWindowTest {
8 | }
9 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/api/window/SlidingWindowTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.api.window;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.tanghao.flink.demo.common.ConstantKafka;
5 | import com.tanghao.flink.demo.common.Message;
6 | import com.tanghao.flink.demo.common.UserConsumerAmountPerMinute;
7 | import org.apache.flink.api.common.functions.AggregateFunction;
8 | import org.apache.flink.api.common.functions.FilterFunction;
9 | import org.apache.flink.api.common.functions.MapFunction;
10 | import org.apache.flink.api.common.functions.ReduceFunction;
11 | import org.apache.flink.api.common.serialization.SimpleStringSchema;
12 | import org.apache.flink.api.java.functions.KeySelector;
13 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
14 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
15 | import org.apache.flink.streaming.api.functions.aggregation.AggregationFunction;
16 | import org.apache.flink.streaming.api.windowing.time.Time;
17 | import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;
18 |
19 | import java.text.DateFormat;
20 | import java.text.SimpleDateFormat;
21 | import java.util.*;
22 |
23 | /**
24 | * Description: 滑动窗口场景——每5s刷新一次最近1分钟消费总金额用户排名top3
25 | * Created By tanghao on 2020/4/7
26 | */
27 | public class SlidingWindowTest {
28 |
29 | public static void main(String[] args) {
30 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
31 | Properties properties = new Properties();
32 | properties.setProperty("bootstrap.servers", "192.168.8.145:9082");
33 |
34 | SingleOutputStreamOperator messageStream= env.addSource(new FlinkKafkaConsumer011(ConstantKafka.TRADE_MESSAGE_TOPIC, new SimpleStringSchema(), properties)).map(new MapFunction() {
35 | public Message map(String s) throws Exception {
36 | return JSONObject.parseObject(s,Message.class);
37 | }
38 | });
39 |
40 | SingleOutputStreamOperator> result = messageStream.filter(new FilterFunction() {
41 | public boolean filter(Message value) throws Exception {
42 | if(value.getTransCode().equals("3001")){
43 | return true;
44 | }else{
45 | return false;
46 | }
47 | }
48 | }).keyBy(new KeySelector() {
49 | public String getKey(Message value) throws Exception {
50 | return value.getTransCode();
51 | }
52 | }).timeWindow(Time.minutes(1),Time.seconds(5)).aggregate(new AggregateFunction, List>() {
53 | public Map createAccumulator() {
54 | return new HashMap();
55 | }
56 |
57 | public Map add(Message value, Map accumulator) {
58 | UserConsumerAmountPerMinute userConsumerAmountPerMinute = accumulator.get(value.getUserId());
59 | if(null == userConsumerAmountPerMinute){
60 | userConsumerAmountPerMinute = new UserConsumerAmountPerMinute();
61 | DateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm");
62 | String currentMinute = format.format(new Date());
63 | userConsumerAmountPerMinute.setAmount(value.getAmount());
64 | userConsumerAmountPerMinute.setUserId(value.getUserId());
65 | userConsumerAmountPerMinute.setCurrentMinute(currentMinute);
66 | accumulator.put(value.getUserId(),userConsumerAmountPerMinute);
67 | }else{
68 | userConsumerAmountPerMinute.setAmount(userConsumerAmountPerMinute.getAmount()+value.getAmount());
69 | }
70 | return accumulator;
71 | }
72 |
73 | public List getResult(Map accumulator) {
74 | List list = new ArrayList(accumulator.values());
75 | list.sort(new UserConsumerAmountPerMinuteComparator());
76 | return list;
77 | }
78 |
79 | public Map merge(Map a, Map b) {
80 | return null;
81 | }
82 | });
83 |
84 | result.print();
85 |
86 | try {
87 | env.execute();
88 | } catch (Exception e) {
89 | e.printStackTrace();
90 | }
91 | }
92 |
93 | private static class UserConsumerAmountPerMinuteComparator implements Comparator{
94 | public int compare(UserConsumerAmountPerMinute o1, UserConsumerAmountPerMinute o2) {
95 | return o1.getAmount().compareTo(o2.getAmount());
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/api/window/TumblingWindowAggregateFunctionTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.api.window;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.tanghao.flink.demo.common.ConstantKafka;
5 | import com.tanghao.flink.demo.common.Message;
6 | import com.tanghao.flink.demo.common.TradeCountMinuteResult;
7 | import com.tanghao.flink.demo.common.UserConsumerAmountPerMinute;
8 | import org.apache.commons.lang3.StringUtils;
9 | import org.apache.flink.api.common.functions.*;
10 | import org.apache.flink.api.common.serialization.SimpleStringSchema;
11 | import org.apache.flink.api.common.state.*;
12 | import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
13 | import org.apache.flink.api.java.functions.KeySelector;
14 | import org.apache.flink.configuration.Configuration;
15 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
16 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
17 | import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
18 | import org.apache.flink.streaming.api.windowing.time.Time;
19 | import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
20 | import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;
21 | import org.apache.flink.util.Collector;
22 | import org.apache.flink.util.OutputTag;
23 |
24 | import java.io.IOException;
25 | import java.text.DateFormat;
26 | import java.text.SimpleDateFormat;
27 | import java.util.*;
28 |
29 | /**
30 | * Description: 滚动窗口测试
31 | * 场景:根据transCode统计每分钟充值、提现、消费等各类型交易总金额;并且根据userId统计用户分钟消费金额。
32 | * Created By tanghao on 2020/4/7
33 | */
34 | public class TumblingWindowAggregateFunctionTest {
35 |
36 | public static void main(String[] args) {
37 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
38 | Properties properties = new Properties();
39 | properties.setProperty("bootstrap.servers", "192.168.8.145:9082");
40 |
41 | SingleOutputStreamOperator messageStream= env.addSource(new FlinkKafkaConsumer011(ConstantKafka.TRADE_MESSAGE_TOPIC, new SimpleStringSchema(), properties)).map(new MapFunction() {
42 | public Message map(String s) throws Exception {
43 | return JSONObject.parseObject(s,Message.class);
44 | }
45 | });
46 |
47 | //用户分钟消费额子流标记
48 | final OutputTag userConsumerAmountPerMin = new OutputTag("side-output-user-consumer-amount-per-min"){};
49 |
50 | //按交易类型分区
51 | SingleOutputStreamOperator res = messageStream.keyBy(new KeySelector() {
52 | public String getKey(Message message) throws Exception {
53 | return message.getTransCode();
54 | }
55 | }).timeWindow(Time.minutes(1)).aggregate(new MySumAggregate());
56 | res.print();
57 | res.getSideOutput(userConsumerAmountPerMin).print();
58 | /**
59 | * 输出结果:各类型分钟交易总额,用户分钟消费总额
60 | * 4> TradeCountMinuteResult{transCode='1001', sumAmount=4998, currentMinute='2020-04-09 15:52'}
61 | * 3> TradeCountMinuteResult{transCode='3001', sumAmount=4023, currentMinute='2020-04-09 15:52'}
62 | * 6> TradeCountMinuteResult{transCode='2001', sumAmount=6190, currentMinute='2020-04-09 15:52'}
63 | * 3> UserConsumerAmountPerMinute{userId=754, amount=599, currentMinute='2020-04-09 15:52'}
64 | * 3> UserConsumerAmountPerMinute{userId=578, amount=725, currentMinute='2020-04-09 15:52'}
65 | * 3> UserConsumerAmountPerMinute{userId=931, amount=622, currentMinute='2020-04-09 15:52'}
66 | */
67 | try {
68 | env.execute();
69 | } catch (Exception e) {
70 | e.printStackTrace();
71 | }
72 | }
73 |
74 | /**
75 | * 这里禁止使用RichFunction,暂时不清楚为何这样设计,说是这样使用状态不正确
76 | */
77 | private static class MySumAggregate extends RichAggregateFunction {
78 |
79 | private transient MapState firstMinUserConsumerAmountMap;
80 | private transient ValueState totalTradeAmountValue;
81 |
82 | @Override
83 | public void open(Configuration parameters) throws Exception {
84 | MapStateDescriptor firstMinUserConsumerAmount = new MapStateDescriptor("firstMinUserConsumerAmount", BasicTypeInfo.LONG_TYPE_INFO,BasicTypeInfo.LONG_TYPE_INFO);
85 | StateTtlConfig ttlConfig = StateTtlConfig
86 | .newBuilder(org.apache.flink.api.common.time.Time.seconds(1))
87 | .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
88 | .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
89 | .build();
90 | firstMinUserConsumerAmount.enableTimeToLive(ttlConfig);
91 | firstMinUserConsumerAmountMap = getRuntimeContext().getMapState(firstMinUserConsumerAmount);
92 |
93 | ValueStateDescriptor totalTradeAmount = new ValueStateDescriptor("totalTradeAmount", BasicTypeInfo.LONG_TYPE_INFO);
94 | StateTtlConfig ttlConfig2 = StateTtlConfig
95 | .newBuilder(org.apache.flink.api.common.time.Time.seconds(1))
96 | .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
97 | .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
98 | .build();
99 | totalTradeAmount.enableTimeToLive(ttlConfig2);
100 | totalTradeAmountValue = getRuntimeContext().getState(totalTradeAmount);
101 | }
102 |
103 | public TradeCountMinuteResult createAccumulator() {
104 | return new TradeCountMinuteResult();
105 | }
106 |
107 | public TradeCountMinuteResult add(Message value, TradeCountMinuteResult accumulator) {
108 | DateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm");
109 | String currentMinute = format.format(new Date());
110 | if(currentMinute.equals("2020-04-10 17:42")){
111 | Long userId = value.getUserId();
112 | Long userSum = null;
113 | try {
114 | userSum = firstMinUserConsumerAmountMap.get(userId);
115 | } catch (Exception e) {
116 | e.printStackTrace();
117 | }
118 | if(null==userSum){
119 | userSum = value.getAmount();
120 | }else{
121 | userSum += value.getAmount();
122 | }
123 | try {
124 | firstMinUserConsumerAmountMap.put(userId,userSum);
125 | } catch (Exception e) {
126 | e.printStackTrace();
127 | }
128 | }
129 | try {
130 | Long totalTradeAmount = totalTradeAmountValue.value();
131 | if(null==totalTradeAmount){
132 | totalTradeAmount = value.getAmount();
133 | }else{
134 | totalTradeAmount += value.getAmount();
135 | }
136 | totalTradeAmountValue.update(totalTradeAmount);
137 | } catch (IOException e) {
138 | e.printStackTrace();
139 | }
140 |
141 | if(StringUtils.isEmpty(accumulator.getTransCode())){
142 | accumulator.setTransCode(value.getTransCode());
143 | }
144 | if(StringUtils.isEmpty(accumulator.getCurrentMinute())){
145 | accumulator.setCurrentMinute(currentMinute);
146 | }
147 | Long sum = null==accumulator.getSumAmount()?0L:accumulator.getSumAmount();
148 | sum += value.getAmount();
149 | accumulator.setSumAmount(sum);
150 | return accumulator;
151 | }
152 |
153 | public TradeCountMinuteResult getResult(TradeCountMinuteResult accumulator) {
154 | return accumulator;
155 | }
156 |
157 | public TradeCountMinuteResult merge(TradeCountMinuteResult a, TradeCountMinuteResult b) {
158 | return null;
159 | }
160 | }
161 |
162 | }
163 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/api/window/TumblingWindowProcessWindowFunctionTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.api.window;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.tanghao.flink.demo.common.ConstantKafka;
5 | import com.tanghao.flink.demo.common.Message;
6 | import com.tanghao.flink.demo.common.TradeCountMinuteResult;
7 | import com.tanghao.flink.demo.common.UserConsumerAmountPerMinute;
8 | import org.apache.flink.api.common.functions.MapFunction;
9 | import org.apache.flink.api.common.serialization.SimpleStringSchema;
10 | import org.apache.flink.api.java.functions.KeySelector;
11 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
12 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
13 | import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
14 | import org.apache.flink.streaming.api.windowing.time.Time;
15 | import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
16 | import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;
17 | import org.apache.flink.util.Collector;
18 | import org.apache.flink.util.OutputTag;
19 |
20 | import java.text.DateFormat;
21 | import java.text.SimpleDateFormat;
22 | import java.util.*;
23 |
24 | /**
25 | * Description: 滚动窗口测试
26 | * 场景:根据transCode统计每分钟充值、提现、消费等各类型交易总金额;并且根据userId统计用户分钟消费金额。
27 | * Created By tanghao on 2020/4/7
28 | */
29 | public class TumblingWindowProcessWindowFunctionTest {
30 |
31 | public static void main(String[] args) {
32 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
33 | Properties properties = new Properties();
34 | properties.setProperty("bootstrap.servers", "192.168.8.145:9082");
35 |
36 | SingleOutputStreamOperator messageStream= env.addSource(new FlinkKafkaConsumer011(ConstantKafka.TRADE_MESSAGE_TOPIC, new SimpleStringSchema(), properties)).map(new MapFunction() {
37 | public Message map(String s) throws Exception {
38 | return JSONObject.parseObject(s,Message.class);
39 | }
40 | });
41 |
42 | //用户分钟消费额子流标记
43 | final OutputTag userConsumerAmountPerMin = new OutputTag("side-output-user-consumer-amount-per-min"){};
44 |
45 | //按交易类型分区
46 | SingleOutputStreamOperator res = messageStream.keyBy(new KeySelector() {
47 | public String getKey(Message message) throws Exception {
48 | return message.getTransCode();
49 | }
50 | }).timeWindow(Time.minutes(1)).process(new ProcessWindowFunction() {
51 | public void process(String s, Context context, Iterable elements, Collector out) throws Exception {
52 | DateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm");
53 | String currentMinute = format.format(new Date());
54 | Long sum = 0L;
55 | Map userConsumerAmountPerMinMap = new HashMap();
56 | for(Message message:elements){
57 | /** 之前已经keyBy根据交易类型分区过,每个分区都是统一类型的交易数据,直接累加即可 */
58 | sum += message.getAmount();
59 | /** 若交易类型是消费,则要统计用户该分钟内的交易总额,输出到用户维度的子流中 */
60 | if(message.getTransCode().equals("3001")){
61 | if(null==userConsumerAmountPerMinMap.get(message.getUserId())){
62 | userConsumerAmountPerMinMap.put(message.getUserId(),message.getAmount());
63 | }else{
64 | long temp = userConsumerAmountPerMinMap.get(message.getUserId());
65 | temp += message.getAmount();
66 | userConsumerAmountPerMinMap.put(message.getUserId(),temp);
67 | }
68 | }
69 | }
70 | /** 主数据流输出各类型交易额汇总信息*/
71 | TradeCountMinuteResult tradeCountMinuteResult = new TradeCountMinuteResult();
72 | tradeCountMinuteResult.setTransCode(s);
73 | tradeCountMinuteResult.setSumAmount(sum);
74 | tradeCountMinuteResult.setCurrentMinute(currentMinute);
75 | out.collect(tradeCountMinuteResult);
76 | /** 用户分钟消费额统计,输出到子数据流中。可以用于第1分钟消费金额top3用户统计,交给redis排序即可 */
77 | for (Map.Entry m : userConsumerAmountPerMinMap.entrySet()) {
78 | Long userId = m.getKey();
79 | Long amount = m.getValue();
80 | UserConsumerAmountPerMinute userConsumerAmountPerMinute = new UserConsumerAmountPerMinute();
81 | userConsumerAmountPerMinute.setAmount(amount);
82 | userConsumerAmountPerMinute.setUserId(userId);
83 | userConsumerAmountPerMinute.setCurrentMinute(currentMinute);
84 | context.output(userConsumerAmountPerMin,userConsumerAmountPerMinute);
85 | }
86 | }
87 | });
88 | res.print();
89 | System.out.println("执行计划:"+env.getExecutionPlan());
90 | res.getSideOutput(userConsumerAmountPerMin).print();
91 | /**
92 | * 输出结果:各类型分钟交易总额,用户分钟消费总额
93 | * 4> TradeCountMinuteResult{transCode='1001', sumAmount=4998, currentMinute='2020-04-09 15:52'}
94 | * 3> TradeCountMinuteResult{transCode='3001', sumAmount=4023, currentMinute='2020-04-09 15:52'}
95 | * 6> TradeCountMinuteResult{transCode='2001', sumAmount=6190, currentMinute='2020-04-09 15:52'}
96 | * 3> UserConsumerAmountPerMinute{userId=754, amount=599, currentMinute='2020-04-09 15:52'}
97 | * 3> UserConsumerAmountPerMinute{userId=578, amount=725, currentMinute='2020-04-09 15:52'}
98 | * 3> UserConsumerAmountPerMinute{userId=931, amount=622, currentMinute='2020-04-09 15:52'}
99 | */
100 | try {
101 | env.execute();
102 | } catch (Exception e) {
103 | e.printStackTrace();
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/api/window/TumblingWindowUseEventTimeTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.api.window;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.tanghao.flink.demo.common.ConstantKafka;
5 | import com.tanghao.flink.demo.common.Message;
6 | import org.apache.flink.api.common.functions.MapFunction;
7 | import org.apache.flink.api.common.serialization.SimpleStringSchema;
8 | import org.apache.flink.api.java.functions.KeySelector;
9 | import org.apache.flink.streaming.api.TimeCharacteristic;
10 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
11 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
12 | import org.apache.flink.streaming.api.functions.timestamps.AscendingTimestampExtractor;
13 | import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
14 | import org.apache.flink.streaming.api.windowing.time.Time;
15 | import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;
16 |
17 | import java.util.Properties;
18 |
19 | /**
20 | * Description: 使用事件时间
21 | * Created By tanghao on 2020/4/9
22 | */
23 | public class TumblingWindowUseEventTimeTest {
24 | public static void main(String[] args) {
25 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
26 | env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
27 |
28 | Properties properties = new Properties();
29 | properties.setProperty("bootstrap.servers", "192.168.8.145:9082");
30 | SingleOutputStreamOperator messageStream= env.addSource(new FlinkKafkaConsumer011(ConstantKafka.TRADE_MESSAGE_TOPIC, new SimpleStringSchema(), properties)).map(new MapFunction() {
31 | public Message map(String s) throws Exception {
32 | return JSONObject.parseObject(s,Message.class);
33 | }
34 | }).assignTimestampsAndWatermarks(new AscendingTimestampExtractor() {
35 | @Override
36 | public long extractAscendingTimestamp(Message element) {
37 | return element.getTradeTime().getTime();
38 | }
39 | });
40 |
41 | SingleOutputStreamOperator res = messageStream.keyBy(new KeySelector() {
42 | public String getKey(Message message) throws Exception {
43 | return message.getTransCode();
44 | }
45 | }).window(TumblingEventTimeWindows.of(Time.minutes(1))).sum("amount");
46 | res.print();
47 | try {
48 | env.execute();
49 | } catch (Exception e) {
50 | e.printStackTrace();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/common/ConstantKafka.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.common;
2 |
3 | /**
4 | * Description: kafka常量
5 | * Created By tanghao on 2020/4/7
6 | */
7 | public class ConstantKafka {
8 |
9 | public static String KAFKA_SINGLE = "192.168.8.145:9082";
10 |
11 | public static String TRADE_MESSAGE_TOPIC = "trade_message";
12 |
13 | public static String TRANS_TYPE_TOPIC = "trans_type";
14 | }
15 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/common/Message.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.common;
2 |
3 | import java.io.Serializable;
4 | import java.util.Date;
5 | import java.util.Random;
6 | import java.util.UUID;
7 |
8 | /**
9 | * Description: 消息POJO类
10 | * Created By tanghao on 2020/4/1
11 | */
12 | public class Message implements Serializable {
13 | private String id;
14 |
15 | private String transCode;//1001-充值,2001-提现,3001-消费
16 |
17 | private Long amount;
18 |
19 | private Date tradeTime;
20 |
21 | private Long userId;
22 |
23 | /** 符合POJO类的规则:
24 | * The class is public and standalone (no non-static inner class)
25 | * The class has a public no-argument constructor
26 | * All non-static, non-transient fields in the class (and all superclasses) are either public (and non-final) or have a public getter- and a setter- method that follows the Java beans naming conventions for getters and setters.
27 | * 这里关注第二条,必须有无参构造器
28 | * */
29 | public Message(){
30 |
31 | }
32 |
33 | public Message(String transCode, Long amount) {
34 | this.id = generatorId();
35 | this.transCode = transCode;
36 | this.amount = amount;
37 | this.tradeTime = new Date();
38 | this.userId = generatorUserId();
39 | }
40 |
41 |
42 | public Message(String id, String transCode, Long amount) {
43 | this.id = id;
44 | this.transCode = transCode;
45 | this.amount = amount;
46 | this.tradeTime = new Date();
47 | this.userId = generatorUserId();
48 | }
49 |
50 | public Message(String id, String transCode, Long amount, Date tradeTime) {
51 | this.id = id;
52 | this.transCode = transCode;
53 | this.amount = amount;
54 | this.tradeTime = tradeTime;
55 | this.userId = generatorUserId();
56 | }
57 |
58 | public String getId() {
59 | return id;
60 | }
61 |
62 | public void setId(String id) {
63 | this.id = id;
64 | }
65 |
66 | public String getTransCode() {
67 | return transCode;
68 | }
69 |
70 | public void setTransCode(String transCode) {
71 | this.transCode = transCode;
72 | }
73 |
74 | public Long getAmount() {
75 | return amount;
76 | }
77 |
78 | public void setAmount(Long amount) {
79 | this.amount = amount;
80 | }
81 |
82 | public Date getTradeTime() {
83 | return tradeTime;
84 | }
85 |
86 | public void setTradeTime(Date tradeTime) {
87 | this.tradeTime = tradeTime;
88 | }
89 |
90 | private String generatorId(){
91 | return UUID.randomUUID().toString();
92 | }
93 |
94 | private long generatorUserId(){
95 | Random random = new Random();
96 | return random.nextInt(1000);
97 | }
98 |
99 | public Long getUserId() {
100 | return userId;
101 | }
102 |
103 | public void setUserId(Long userId) {
104 | this.userId = userId;
105 | }
106 |
107 | @Override
108 | public String toString() {
109 | return "Message{" +
110 | "id='" + id + '\'' +
111 | ", transCode='" + transCode + '\'' +
112 | ", amount=" + amount +
113 | ", tradeTime=" + tradeTime +
114 | ", userId=" + userId +
115 | '}';
116 | }
117 | }
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/common/MessageDeserializationSchema.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.common;
2 |
3 | import org.apache.flink.api.common.serialization.DeserializationSchema;
4 | import org.apache.flink.api.common.typeinfo.TypeInformation;
5 |
6 | import java.io.IOException;
7 |
8 | /**
9 | * Description: TODO
10 | * Created By tanghao on 2020/4/8
11 | */
12 | public class MessageDeserializationSchema implements DeserializationSchema {
13 | public Message deserialize(byte[] bytes) throws IOException {
14 | return null;
15 | }
16 |
17 | public boolean isEndOfStream(Message message) {
18 | return false;
19 | }
20 |
21 | public TypeInformation getProducedType() {
22 | return null;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/common/TradeCountMinuteResult.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.common;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Description: 交易统计小时结果
7 | * Created By tanghao on 2020/4/9
8 | */
9 | public class TradeCountMinuteResult implements Serializable {
10 |
11 | private String transCode;
12 |
13 | private Long sumAmount;
14 |
15 | private String currentMinute;
16 |
17 | public String getTransCode() {
18 | return transCode;
19 | }
20 |
21 | public void setTransCode(String transCode) {
22 | this.transCode = transCode;
23 | }
24 |
25 | public Long getSumAmount() {
26 | return sumAmount;
27 | }
28 |
29 | public void setSumAmount(Long sumAmount) {
30 | this.sumAmount = sumAmount;
31 | }
32 |
33 | public String getCurrentMinute() {
34 | return currentMinute;
35 | }
36 |
37 | public void setCurrentMinute(String currentMinute) {
38 | this.currentMinute = currentMinute;
39 | }
40 |
41 | @Override
42 | public String toString() {
43 | return "TradeCountMinuteResult{" +
44 | "transCode='" + transCode + '\'' +
45 | ", sumAmount=" + sumAmount +
46 | ", currentMinute='" + currentMinute + '\'' +
47 | '}';
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/common/TransTypeInfo.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.common;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Description: 交易类型信息
7 | * Created By tanghao on 2020/4/8
8 | */
9 | public class TransTypeInfo implements Serializable {
10 |
11 | private String transCode;
12 |
13 | private String transName;
14 |
15 | private boolean isOpen;
16 |
17 | public String getTransCode() {
18 | return transCode;
19 | }
20 |
21 | public void setTransCode(String transCode) {
22 | this.transCode = transCode;
23 | }
24 |
25 | public String getTransName() {
26 | return transName;
27 | }
28 |
29 | public void setTransName(String transName) {
30 | this.transName = transName;
31 | }
32 |
33 | public boolean isOpen() {
34 | return isOpen;
35 | }
36 |
37 | public void setOpen(boolean open) {
38 | isOpen = open;
39 | }
40 |
41 | @Override
42 | public String toString() {
43 | return "TransTypeInfo{" +
44 | "transCode='" + transCode + '\'' +
45 | ", transName='" + transName + '\'' +
46 | ", isOpen=" + isOpen +
47 | '}';
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/common/UserConsumerAmountPerMinute.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.common;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Description: 用户每分钟消费金额统计对象
7 | * Created By tanghao on 2020/4/9
8 | */
9 | public class UserConsumerAmountPerMinute implements Serializable {
10 |
11 | private Long userId;
12 |
13 | private Long amount;
14 |
15 | private String currentMinute;
16 |
17 | public Long getUserId() {
18 | return userId;
19 | }
20 |
21 | public void setUserId(Long userId) {
22 | this.userId = userId;
23 | }
24 |
25 | public Long getAmount() {
26 | return amount;
27 | }
28 |
29 | public void setAmount(Long amount) {
30 | this.amount = amount;
31 | }
32 |
33 | public String getCurrentMinute() {
34 | return currentMinute;
35 | }
36 |
37 | public void setCurrentMinute(String currentMinute) {
38 | this.currentMinute = currentMinute;
39 | }
40 |
41 | @Override
42 | public String toString() {
43 | return "UserConsumerAmountPerMinute{" +
44 | "userId=" + userId +
45 | ", amount=" + amount +
46 | ", currentMinute='" + currentMinute + '\'' +
47 | '}';
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/source/InnerSource.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.source;
2 |
3 | import org.apache.flink.api.common.functions.MapFunction;
4 | import org.apache.flink.streaming.api.datastream.DataStreamSource;
5 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
6 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
7 |
8 | import java.util.Arrays;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | /**
13 | * Description: 内置数据源
14 | * Created By tanghao on 2020/3/31
15 | */
16 | public class InnerSource {
17 |
18 | public static void main(String[] args) {
19 | StreamExecutionEnvironment streamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment();
20 |
21 | //从文件读流
22 | fromFile(streamExecutionEnvironment);
23 | //从本地集合中读流
24 | // fromCollection(streamExecutionEnvironment);
25 | }
26 |
27 | private static void fromFile(StreamExecutionEnvironment streamExecutionEnvironment){
28 | DataStreamSource streamSource = streamExecutionEnvironment.readTextFile("D://test.txt","UTF-8");
29 | streamSource.print();
30 | try {
31 | streamExecutionEnvironment.execute();
32 | } catch (Exception e) {
33 | e.printStackTrace();
34 | }
35 | }
36 |
37 | private static void fromCollection(StreamExecutionEnvironment streamExecutionEnvironment){
38 | String[] strArray={"deposit,10","withdraw,10","deposit,3","withdraw,10"};
39 | DataStreamSource streamSource = streamExecutionEnvironment.fromCollection(Arrays.asList(strArray));
40 | streamSource.print();
41 | try {
42 | streamExecutionEnvironment.execute();
43 | } catch (Exception e) {
44 | e.printStackTrace();
45 | }
46 | }
47 |
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/source/KafkaSource.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.source;
2 |
3 | import com.tanghao.flink.demo.common.ConstantKafka;
4 | import com.tanghao.flink.demo.common.Message;
5 | import org.apache.flink.api.common.serialization.SimpleStringSchema;
6 | import org.apache.flink.formats.json.JsonNodeDeserializationSchema;
7 | import org.apache.flink.shaded.jackson2.com.fasterxml.jackson.databind.node.ObjectNode;
8 | import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
9 | import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
10 | import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer011;
11 | import org.apache.flink.streaming.connectors.kafka.KafkaDeserializationSchema;
12 | import org.apache.flink.streaming.connectors.kafka.internals.KafkaDeserializationSchemaWrapper;
13 |
14 | import java.util.Properties;
15 |
16 | /**
17 | * Description: TODO
18 | * Created By tanghao on 2020/4/8
19 | */
20 | public class KafkaSource {
21 |
22 | public static void main(String[] args) {
23 | StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
24 |
25 | Properties properties = new Properties();
26 | properties.setProperty("bootstrap.servers", "192.168.8.145:9082");
27 | SingleOutputStreamOperator stream= env.addSource(new FlinkKafkaConsumer011(ConstantKafka.TRADE_MESSAGE_TOPIC, new SimpleStringSchema(), properties));
28 | stream.print();
29 |
30 | try {
31 | env.execute();
32 | } catch (Exception e) {
33 | e.printStackTrace();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/test/BroadcastMsgProducerTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.test;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.tanghao.flink.demo.common.ConstantKafka;
5 | import com.tanghao.flink.demo.common.Message;
6 | import com.tanghao.flink.demo.common.TransTypeInfo;
7 | import org.apache.kafka.clients.producer.KafkaProducer;
8 | import org.apache.kafka.clients.producer.ProducerRecord;
9 |
10 | import java.util.Properties;
11 |
12 | /**
13 | * Description: kafka生成交易消息
14 | * Created By tanghao on 2020/4/7
15 | */
16 | public class BroadcastMsgProducerTest {
17 |
18 | public static void main(String[] args) throws InterruptedException {
19 | Properties pro = new Properties();
20 | pro.setProperty("bootstrap.servers", "192.168.8.145:9082");
21 | pro.setProperty("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
22 | pro.setProperty("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
23 | KafkaProducer producer = new KafkaProducer(pro);
24 | sendTransTypeInfo(producer);
25 | Thread.sleep(300);//更新广播表有个时间间隔
26 | sendMessage(producer);
27 | producer.close();
28 | }
29 |
30 | /**
31 | * 发送维表配置的交易类型信息
32 | * isOpen字段标识开关,如果打开可以在接收的消息中根据transCode去TRANS_TYPE_MAP得到transName
33 | * @param producer
34 | */
35 | private static void sendTransTypeInfo(KafkaProducer producer){
36 | TransTypeInfo transTypeInfo = new TransTypeInfo();
37 | transTypeInfo.setOpen(true);
38 | transTypeInfo.setTransCode("2001");
39 | transTypeInfo.setTransName("提现");
40 | producer.send(new ProducerRecord(ConstantKafka.TRANS_TYPE_TOPIC, JSONObject.toJSONString(transTypeInfo)));
41 | }
42 |
43 | private static void sendMessage(KafkaProducer producer){
44 | Message msg = new Message("2001",101L);
45 | producer.send(new ProducerRecord(ConstantKafka.TRADE_MESSAGE_TOPIC, JSONObject.toJSONString(msg)));
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/java/com/tanghao/flink/demo/test/MsgProducerTest.java:
--------------------------------------------------------------------------------
1 | package com.tanghao.flink.demo.test;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.tanghao.flink.demo.common.ConstantKafka;
5 | import com.tanghao.flink.demo.common.Message;
6 | import org.apache.kafka.clients.producer.KafkaProducer;
7 | import org.apache.kafka.clients.producer.ProducerRecord;
8 |
9 | import java.util.Arrays;
10 | import java.util.List;
11 | import java.util.Properties;
12 | import java.util.Random;
13 |
14 | /**
15 | * Description: 消息生成器
16 | * Created By tanghao on 2020/4/8
17 | */
18 | public class MsgProducerTest {
19 | private static final String[] transCodes = {"1001","2001","3001"};
20 |
21 | public static void main(String[] args) throws InterruptedException {
22 | Properties pro = new Properties();
23 | pro.setProperty("bootstrap.servers", "192.168.8.145:9082");
24 | pro.setProperty("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
25 | pro.setProperty("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
26 | KafkaProducer producer = new KafkaProducer(pro);
27 | for(int i=0;i<30;i++){
28 | Message msg = new Message(transCodes[i%3],(long)new Random().nextInt(1000));
29 | System.out.println(msg);
30 | producer.send(new ProducerRecord(ConstantKafka.TRADE_MESSAGE_TOPIC, JSONObject.toJSONString(msg)));
31 | Thread.sleep(500);
32 | }
33 | producer.close();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tanghao-flink-demo/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, console
2 |
3 | log4j.appender.console=org.apache.log4j.ConsoleAppender
4 | log4j.appender.console.layout=org.apache.log4j.PatternLayout
5 | log4j.appender.console.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %-60c %x - %m%n
6 |
--------------------------------------------------------------------------------