Storm1.1.0<温故而知新-网站用户使用的浏览器统计>

软件环境:

storm1.1.0

使用一个600多兆的网站日志来模拟网站每天产生的日志信息

120.197.87.216 - - [04/Jan/2012:00:00:02 +0800] "GET /home.php?mod=space&uid=563413&mobile=yes HTTP/1.1" 200 3388 "-" "-"
123.126.50.73 - - [04/Jan/2012:00:00:02 +0800] "GET /thread-679411-1-1.html HTTP/1.1" 200 5251 "-" "Sogou web spider/4.0(+http://www.sogou.com/docs/help/webmasters.htm#07)"
203.208.60.187 - - [04/Jan/2012:00:00:02 +0800] "GET /archiver/tid-3003.html HTTP/1.1" 200 2056 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
114.112.141.6 - - [04/Jan/2012:00:00:02 +0800] "GET /ctp080113.php?action=getgold HTTP/1.1" 200 13886 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; InfoPath.3; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
114.112.141.6 - - [04/Jan/2012:00:00:02 +0800] "GET /ctp080113.php?action=getmedal HTTP/1.1" 200 13882 "-" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; InfoPath.3; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
110.6.179.88 - - [04/Jan/2012:00:00:02 +0800] "GET /forum.php?mod=attachment&aid=NTczNzU3fDFjNDdjZTgzfDEzMjI4NzgwMDV8MTMzOTc4MDB8MTEwMTcxMA%3D%3D&mobile=no HTTP/1.1" 200 172 "http://www.itpub.net/forum.php?mod=attachment&aid=NTczNzU3fDFjNDdjZTgzfDEzMjI4NzgwMDV8MTMzOTc4MDB8MTEwMTcxMA%3D%3D&mobile=yes" "Mozilla/5.0 (Linux; U; Android 2.2; zh-cn; ZTE-U V880 Build/FRF91) UC AppleWebKit/530+ (KHTML, like Gecko) Mobile Safari/530"
116.205.130.2 - - [04/Jan/2012:00:00:02 +0800] "GET /popwin_js.php?fid=6 HTTP/1.1" 200 32 "http://www.itpub.net/forum-6-1.html?ts=28" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; QQDownload 702; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; AskTbPTV/5.11.3.15590; .NET4.0E)"
114.112.141.6 - - [04/Jan/2012:00:00:02 +0800] "GET /popwin_js.php?fid=133 HTTP/1.1" 200 11 "http://www.itpub.net/thread-1558574-3-9.html" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; InfoPath.3; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
114.112.141.6 - - [04/Jan/2012:00:00:02 +0800] "GET /ctp080113.php?tid=1558574 HTTP/1.1" 200 5 "http://www.itpub.net/thread-1558574-3-9.html" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; InfoPath.3; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
110.75.173.35 - - [04/Jan/2012:00:00:02 +0800] "GET /forum.php?goto=lastpost&mod=redirect&tid=1380214 HTTP/1.1" 302 5 "-" "Yahoo! Slurp China"

以上日志文件的样本,将文件上传到HDFS上的log目录下

使用开源库https://github.com/Gpwner/user-agent-utils解析出浏览器的名称
这里写图片描述

使用的时候,简单地调用一下API就能解析出浏览器的名称了

这里写图片描述

1.思路

首先通过HdfsSpout从hdfs上读取日志文件

 HdfsSpout hdfsSpout = new HdfsSpout()
                .setReaderType("text")
                .withOutputFields(TextFileReader.defaultFields)
                .setHdfsUri(args[0])
                .setSourceDir(args[1])
                .setArchiveDir(args[2])
                .setBadFilesDir(args[3]);

然后数据流入BrowserExtractBolt

    public void execute(Tuple input) {
        String log = input.getStringByField(field);
        UserAgent agent = UserAgent.parseUserAgentString(log);
        if (log != null) {
            collector.emit(new Values(agent.getBrowser().getName()));
        } else {
            System.err.println("解析出现异常:" + log);
        }
        collector.ack(input);
    }

接着与做词频统计类似:

  public void execute(Tuple input, BasicOutputCollector collector) {
        String browser = input.getStringByField("browser");
        Integer count = counts.get(browser);
        if (count == null)
            count = 0;
        count++;
        counts.put(browser, count);
        System.out.println(browser + " :  " + count);
        collector.emit(new Values(browser, count));
    }

不清楚如何将hdfs与storm整合的看我之前的博客:
http://blog.youkuaiyun.com/gpwner/article/details/74157575

整个拓扑的构建:

这里写图片描述

2.实现

使用到的依赖

  <dependencies>
        <dependency>
            <groupId>org.apache.storm</groupId>
            <artifactId>storm-core</artifactId>
            <!--<scope>provided</scope>-->
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.storm</groupId>
            <artifactId>storm-hdfs</artifactId>
            <version>1.1.0</version>
        </dependency>
        <dependency>
            <groupId>eu.bitwalker</groupId>
            <artifactId>UserAgentUtils</artifactId>
            <version>1.20</version>
        </dependency>
    </dependencies>

BrowserCountTopology


import neu.bolt.BrowserExtractBolt;
import neu.bolt.CountBolt;
import neu.bolt.ExtractBolt;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.generated.AlreadyAliveException;
import org.apache.storm.generated.AuthorizationException;
import org.apache.storm.generated.InvalidTopologyException;
import org.apache.storm.hdfs.spout.HdfsSpout;
import org.apache.storm.hdfs.spout.TextFileReader;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.tuple.Fields;

import java.util.HashMap;


public class BrowserCountTopology {


    public static void main(String[] args) throws InvalidTopologyException, AuthorizationException, AlreadyAliveException, InterruptedException {
        System.setProperty("HADOOP_USER_NAME", "root");
        if (args.length != 4) {
            System.out.println("Usage <HdfsUri SourceDir ArchiveDir BadFilesDir>");
            System.exit(1);
        }
        TopologyBuilder builder = new TopologyBuilder();
        HdfsSpout hdfsSpout = new HdfsSpout()
                .setReaderType("text")
                .withOutputFields(TextFileReader.defaultFields)
                .setHdfsUri(args[0])
                .setSourceDir(args[1])
                .setArchiveDir(args[2])
                .setBadFilesDir(args[3]);


        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put(ExtractBolt.FIELD, "line");

        builder.setSpout("hdfsSpout", hdfsSpout, 1);
        builder.setBolt("browserextractbolt", new BrowserExtractBolt(), 8)
                .addConfigurations(hashMap).shuffleGrouping("hdfsSpout");
        builder.setBolt("countBolt", new CountBolt(), 1)
                .fieldsGrouping("browserextractbolt", new Fields("browser"));
        Config conf = new Config();
        conf.setDebug(true);
        conf.setMaxTaskParallelism(1);
        LocalCluster cluster = new LocalCluster();
        cluster.submitTopology("CountTopology", conf, builder.createTopology());
        Thread.sleep(90000);
        cluster.shutdown();
    }
}

BrowserExtractBolt


import eu.bitwalker.useragentutils.UserAgent;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.IRichBolt;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;

import java.util.Map;

public class BrowserExtractBolt implements IRichBolt {
    public static final String FIELD = "field";
    String field;
    OutputCollector collector;

    public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
        this.collector = collector;
        this.field = (String) stormConf.get(FIELD);
    }

    public void execute(Tuple input) {
        String log = input.getStringByField(field);
        UserAgent agent = UserAgent.parseUserAgentString(log);
        if (log != null) {
            collector.emit(new Values(agent.getBrowser().getName()));
        } else {
            System.err.println("解析出现异常:" + log);
        }
        collector.ack(input);
    }

    public void cleanup() {
    }

    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        declarer.declare(new Fields("browser"));
    }

    public Map<String, Object> getComponentConfiguration() {
        return null;
    }
}

CountBolt


public class CountBolt extends BaseBasicBolt {
    private Map<String, Integer> counts = new HashMap<>();

    public void execute(Tuple input, BasicOutputCollector collector) {
        String browser = input.getStringByField("browser");
        Integer count = counts.get(browser);
        if (count == null)
            count = 0;
        count++;
        counts.put(browser, count);
        System.out.println(browser + " :  " + count);
        collector.emit(new Values(browser, count));
    }

    public void declareOutputFields(OutputFieldsDeclarer declarer) {
        declarer.declare(new Fields("browser", "count"));
    }
}

参数配置:
这里写图片描述
运行结果:
这里写图片描述

<think>好的,用户问的是为什么在Vue.js的Element Plus组件中,使用`<el-dialog>`时设置`destroy-on-close`属性后没有生效。我需要先回忆一下Element Plus的文档,确认这个属性的正确用法。 首先,用户提供的代码中属性是`destory-on-close`,这里可能存在拼写错误,正确的属性名应该是`destroy-on-close`。拼写错误会导致属性无法被正确识别,从而功能失效。这是最常见的问题之一,应该先检查这一点。 接下来,如果确认属性名正确,但依然不生效,可能需要考虑其他原因。比如,Element Plus的版本问题。旧的版本可能不支持这个属性,或者该属性的行为在某个版本后有所改变。用户需要确认他们使用的Element Plus版本是否支持`destroy-on-close`,并查看对应版本的文档。 另外,`destroy-on-close`的作用是在对话框关闭时销毁子组件。如果对话框内部的内容没有被正确销毁,可能是因为子组件没有被正确包裹在插槽内,或者存在某些阻止销毁的因素,比如状态管理中的引用。需要检查对话框内部的结构,确保子组件确实会被销毁。 还有一种可能是,用户可能误解了`destroy-on-close`的功能。该属性销毁的是对话框内的内容,而不是对话框组件本身。如果用户期望整个对话框组件被销毁并重新创建,可能需要通过`v-if`来控制对话框的显示隐藏,这样在关闭时完全销毁组件,并在打开时重新创建。 此外,还要查看是否有其他代码干扰,比如自定义的关闭事件处理函数没有正确触发销毁逻辑,或者父组件中的某些状态影响了子组件的销毁。需要确保对话框的关闭是通过Element Plus自身的事件处理的,而不是自定义的方法绕过了销毁过程。 最后,建议用户检查浏览器控制台是否有错误或警告信息,这可能会提供线索。如果以上步骤都确认无误,可能需要提供一个可复现的示例,以便进一步排查问题。</think>这个`destroy-on-close`属性不生效可能有以下几个原因: ### 一、属性名称拼写错误 🔍 你代码中写的是`destory-on-close`(注意拼写错误),正确拼写应该是: ```html <el-dialog destroy-on-close> ``` (注意是`destroy`而不是`destory`) ### 二、Element Plus版本问题 📦 该属性在以下版本有效: 1. Element Plus 1.1.0-beta.17+ 开始支持 2. Element UI 2.15.0+ 开始支持 可通过命令检查版本: ```bash npm list element-plus ``` ### 三、组件使用注意事项 ⚠️ 1. **需要配合`v-model`使用**: ```html <el-dialog v-model="visible" destroy-on-close> ``` 2. **动态内容处理**: - 当对话框关闭时,只会销毁通过`default`插槽传入的内容 - 其他插槽内容(如header/footer)不会被销毁 3. **状态保持问题**: ```html <!-- 如果使用keep-alive包裹内容,会阻止销毁 --> <keep-alive> <div>不会被销毁的内容</div> </keep-alive> ``` ### 四、推荐解决方案 ✅ ```html <el-dialog v-model="data.formVisible" :destroy-on-close="true" @closed="handleDialogClosed"> ``` 可配合关闭事件重置表单: ```javascript const handleDialogClosed = () => { formRef.value.resetFields() } ``` ### 五、验证是否生效的方法 🔨 1. 在子组件中添加生命周期钩子: ```javascript onBeforeUnmount(() => { console.log('组件已被销毁') }) ``` 2. 使用Vue Devtools观察DOM节点变化 如果仍不生效,建议提供完整的组件代码和版本信息以便进一步分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值