需要实现的目标是:
订单数统计,下单用户统计
1、创建maven工程(具体您可以百度)
2、pom.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wsz.stormd</groupId>
<artifactId>StormD11</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<version>1.0.3</version>
<!--设置该属性编译时依赖该jar,打包后相关配置不依赖-->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.wsz.stormd.topology.PaymentTopologyMain</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
3、PaymentInfo
package com.wsz.stormd.entity;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
/**
* Created by wsz on 2017/3/31.
*/
public class PaymentInfo {
private String orderId; // 订单编号
private Date createOrderTime; // 订单创建时间
private String paymentId; // 支付编号
private Date paymentTime; // 支付时间
private String productId; // 商品编号
private String productName; // 商品名称
private long productPrice; // 商品价格
private long promotionPrice; // 商品促销价
private String shopId; // 商铺编号
private String shopName; // 商铺名称
private String shopMobile; // 商铺手机
private long payPrice; // 订单价格
private int num; // 商品数量
private Random random;
public PaymentInfo() {
random();
}
public PaymentInfo(String orderId, Date createOrderTime, String paymentId, Date paymentTime, String productId, String productName, long productPrice, long promotionPrice, String shopId, String shopName, String shopMobile, long payPrice, int num) {
this.orderId = orderId;
this.createOrderTime = createOrderTime;
this.paymentId = paymentId;
this.paymentTime = paymentTime;
this.productId = productId;
this.productName = productName;
this.productPrice = productPrice;
this.promotionPrice = promotionPrice;
this.shopId = shopId;
this.shopName = shopName;
this.shopMobile = shopMobile;
this.payPrice = payPrice;
this.num = num;
random();
}
// 赋值
public void random() {
random = new Random();
this.orderId = UUID.randomUUID().toString().replace("-" , "");
this.createOrderTime = new Date();
this.paymentId = UUID.randomUUID().toString().replace("-" , "");
this.paymentTime = new Date();
this.productId = UUID.randomUUID().toString().replace("-" , "");
this.productName = String.valueOf(random.nextInt(899)+100);
this.num = random.nextInt(9)+1;
this.productPrice = 300;
this.promotionPrice = 208;
this.payPrice = this.promotionPrice;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Date getCreateOrderTime() {
return createOrderTime;
}
public void setCreateOrderTime(Date createOrderTime) {
this.createOrderTime = createOrderTime;
}
public String getPaymentId() {
return paymentId;
}
public void setPaymentId(String paymentId) {
this.paymentId = paymentId;
}
public Date getPaymentTime() {
return paymentTime;
}
public void setPaymentTime(Date paymentTime) {
this.paymentTime = paymentTime;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public long getProductPrice() {
return productPrice;
}
public void setProductPrice(long productPrice) {
this.productPrice = productPrice;
}
public long getPromotionPrice() {
return promotionPrice;
}
public void setPromotionPrice(long promotionPrice) {
this.promotionPrice = promotionPrice;
}
public String getShopId() {
return shopId;
}
public void setShopId(String shopId) {
this.shopId = shopId;
}
public String getShopName() {
return shopName;
}
public void setShopName(String shopName) {
this.shopName = shopName;
}
public String getShopMobile() {
return shopMobile;
}
public void setShopMobile(String shopMobile) {
this.shopMobile = shopMobile;
}
public long getPayPrice() {
return payPrice;
}
public void setPayPrice(long payPrice) {
this.payPrice = payPrice;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "PaymentInfo{" +
"orderId='" + orderId + '\'' +
", createOrderTime=" + createOrderTime +
", paymentId='" + paymentId + '\'' +
", paymentTime=" + paymentTime +
", productId='" + productId + '\'' +
", productName='" + productName + '\'' +
", productPrice=" + productPrice +
", promotionPrice=" + promotionPrice +
", shopId='" + shopId + '\'' +
", shopName='" + shopName + '\'' +
", shopMobile='" + shopMobile + '\'' +
", payPrice=" + payPrice +
", num=" + num +
", random=" + random +
'}';
}
}
4、topology
package com.wsz.stormd.topology;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.topology.TopologyBuilder;
/**
* Created by wsz on 2017/3/31.
*/
public class PaymentTopologyMain {
public static void main(String []args ) throws Exception{
TopologyBuilder topologyBuilder = new TopologyBuilder();
topologyBuilder.setSpout("paymentInfo" , new PaymentInfoSpout());
// 设置用于过滤订单的bolt,它订阅了PaymentInfoSpout
topologyBuilder.setBolt("filter" , new FilterMessageBolt()).shuffleGrouping("paymentInfo");
// 设置用于保存数据的bolt,它订阅了FilterMessageBolt
topologyBuilder.setBolt("save" , new Save2RedisBolt()).shuffleGrouping("filter");
Config config = new Config();
config.setDebug(true);
// 集群下的运行方式
if(null != args && args.length > 0) {
config.setNumWorkers(1);
StormSubmitter.submitTopologyWithProgressBar(args[0] , config , topologyBuilder.createTopology());
} else {
// 本地运行方式
config.setMaxTaskParallelism(1);
new LocalCluster();
StormSubmitter.submitTopology("test" , config , topologyBuilder.createTopology());
}
}
}
5、bolt
该bolt主要是用于过滤掉,不是今天的订单,不记录统计。
package com.wsz.stormd.topology;
import com.google.gson.Gson;
import com.wsz.stormd.entity.PaymentInfo;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;
import java.util.Calendar;
import java.util.Map;
/**
* 用于过滤掉不是今天下的单,值统计今天的订单数
*
* Created by wsz on 2017/3/31.
*/
public class FilterMessageBolt extends BaseBasicBolt {
private Gson gson;
private Calendar calendar;
@Override
public void prepare(Map stormConf, TopologyContext context) {
this.gson = new Gson();
calendar = Calendar.getInstance();
super.prepare(stormConf, context);
}
public void execute(Tuple tuple, BasicOutputCollector basicOutputCollector) {
// 获取由spout吐过来的数据
String value = tuple.getStringByField("payment");
if(null == value || "".equals(value)) {
return ;
}
PaymentInfo paymentInfo = gson.fromJson(value, PaymentInfo.class);
calendar.setTime(paymentInfo.getPaymentTime());
// 判断是不是今天下的单(今天是2017.3.31)
if(calendar.get(Calendar.DATE ) == 31) {
basicOutputCollector.emit(new Values(value));
}
}
// 设置用于传输的字段
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declare(new Fields("payment"));
}
}
6、统计订单数的bolt
package com.wsz.stormd.topology;
import com.google.gson.Gson;
import com.wsz.stormd.entity.PaymentInfo;
import org.apache.storm.state.KeyValueState;
import org.apache.storm.state.State;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.base.BaseStatefulBolt;
import org.apache.storm.tuple.Tuple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
*
* 把数据保存到KeyValueState中
* Created by wsz on 2017/3/31.
*/
public class Save2RedisBolt extends BaseStatefulBolt<KeyValueState>{
private static final Logger LOG = LoggerFactory.getLogger(Save2RedisBolt.class);
private KeyValueState<String , Long> state;
private OutputCollector collector;
private Gson gson;
@Override
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
this.collector = collector;
this.gson = new Gson();
super.prepare(stormConf, context, collector);
}
public void execute(Tuple tuple) {
String value = tuple.getStringByField("payment");
PaymentInfo paymentInfo = gson.fromJson(value, PaymentInfo.class);
// 订单总数
if(null == state.get("orderTotalNum")) {
state.put("orderTotalNum" , (long)1);
} else {
state.put("orderTotalNum" , state.get("orderTotalNum")+1);
}
// 销售额
if(null == state.get("totalSaleroom")) {
state.put("totalSaleroom" , paymentInfo.getProductPrice());
} else {
state.put("totalSaleroom" , state.get("totalSaleroom")+paymentInfo.getProductPrice());
}
// 交易额
if(null == state.get("orderTotalRealPay")) {
state.put("orderTotalRealPay" , paymentInfo.getPayPrice());
} else {
state.put("orderTotalRealPay" , state.get("orderTotalRealPay")+paymentInfo.getPayPrice());
}
// 下单用户(不考虑去重)
if(null == state.get("userNum")) {
state.put("userNum" , Long.valueOf(1));
} else {
state.put("userNum", state.get("userNum") + 1);
}
LOG.info("orderTotalNum:"+state.get("orderTotalNum"));
LOG.info("totalSaleroom:"+state.get("totalSaleroom"));
LOG.info("orderTotalRealPay:"+state.get("orderTotalRealPay"));
LOG.info("userNum:"+state.get("userNum"));
// 表示数据处理完成,可靠性
collector.ack(tuple);
}
public void initState(KeyValueState keyValueState) {
this.state = keyValueState;
}
}
7、进入到pom.xml文件同级目录(Windows用命令提示符进入)
执行命令:mvn package -Dmaven.test.skip=true
8、在target目录下该StormD11-1.0-SNAPSHOT-jar-with-dependencies.jar包上传到nimbus机器上
9、运行jar
需配置好STORM_HOME
执行命令:
storm jar StormD11-1.0-SNAPSHOT-jar-with-dependencies.jar com.wsz.stormd.topology.PaymentTopologyMain wordcountpn
10、查看运行结果
进入到运行worker的机器上
进入到${STORM_HOME}/logs/workers-artifacts/wordcountpn-4-1490965507/6705目录下(这个路径不一定和其一致,从logs目录一直对应进入即可,每一个任务workers-artifacts都有自己的日志文件夹,wordcountpn-4-1490965507以拓扑名称开头)
执行命令:tail -100 worker.log
2017-03-31 21:07:48.978 c.w.s.t.Save2RedisBolt Thread-12-save-executor[5 5] [INFO] orderTotalNum:310
2017-03-31 21:07:48.979 c.w.s.t.Save2RedisBolt Thread-12-save-executor[5 5] [INFO] totalSaleroom:93000
2017-03-31 21:07:48.979 c.w.s.t.Save2RedisBolt Thread-12-save-executor[5 5] [INFO] rderTotalRealPay:64480
2017-03-31 21:07:48.979 c.w.s.t.Save2RedisBolt Thread-12-save-executor[5 5] [INFO] userNum:310