用Node.js搭建一个简易的Web端文件词频统计动态网页

大数据学习路线图

本教程将教导大家如何用Node.js语言搭建一个Web端文件词频统计动态网页。

教程需求

在网页中指定词频文件路径,利用网页点击提交,提交后程序自动运行WordCount的MapReduce程序的JAR包,对HDFS中的文件进行词频统计,并把统计结果显示在网页上。

开发环境

NVM Node版本管理工具
Node.js --LTS
Hadoop 2.7.4
Visual Studio Code 文本编辑工具

安装nvm

打开终端,输入如下命令

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash

然后用vim打开 ~/.bashrc

vim ~/.bashrc

进入编辑模式,添加NVM_DIR环境变量

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This

:wq退出vim的编辑模式,在终端中输入如下命令

source ~/.bashrc

更多有关NVM的教程,请点击访问GitHub NVM官方地址

利用nvm安装Node长期支持版本

nvm install --lts

安装完成后,在终端输入如下命令,即可看到node安装的版本

node -v

运行Hadoop伪分布式

如果已经安装好Hadoop的伪分布式,请跳过本步骤
如果还未安装好Hadoop的伪分布式,请点击Hadoop安装教程_单机/伪分布式配置_Hadoop2.6.0/Ubuntu14.04,按照此教程进行安装。
运行Hadoop伪分布式命令后,我们还需要使用之前教程中使用的WordCount.jar包。
如果没有这个Jar包,请参考教程使用命令行编译打包运行自己的MapReduce程序 Hadoop2.6.0,自行导出Jar包。
本教程中,我导出的Jar包位于路径是'~/WordCount.jar'
终端中执行如下命令:

cd /usr/local/hadoop
sbin/start-dfs.sh

项目开发

终端输入如下命令

# 创建项目文件夹
mkdir myapp
# 初始化项目
cd myapp
npm init

初始化项目后,终端会让你输入项目的相关信息,并自动把这些信息记录在package.json中。
如果想快捷进行开发,不想手动输入项目信息,只需要一路按“Enter”键即可,接受默认自动配置。

安装Express开发框架

npm install express --save

通过npm --save安装的模块都会放在当前项目文件夹下的node_modules文件夹下,并更新到package.json文件中。node中引用该模块的时候,会自动从node_modules文件夹下寻找模块。

Hello world实例

在myapp项目目录中,创建一个名为index.js的文件,这个文件将是整个应用的入口。将如下代码复制进去

const express = require('express');
const app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

const server = app.listen(3000, function () {
  const host = server.address().address;
  const port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

上面的代码启动一个服务并监听从 3000 端口进入的所有连接请求。他将对所有 (/) URL 或 路由 返回 “Hello World!” 字符串。对于其他所有路径全部返回 404 Not Found。
然后在终端中输入如下命令,启动该应用

node index.js

OK,一个最原始的网站就实现了,在浏览器中输入http://locahost:3000 就可以查看结果.

添加模板引擎

上面的Hello world实例只是教大家实现一个简单Web服务网站,没有添加任何模板引擎。这里将完善整个项目需求功能。
Jade是超高性能的node JavaScript模板引擎,有着非常强大的API和大量杰出的特性。
项目文件夹中继续添加jade模板引擎软件包,在终端中执行如下命令

npm install jade --save

安装好后,还需要在应用中设置模板文件目录、识别模板引擎。
在项目文件夹下的应用入口index.js文件下,添加如下内容:

app.set('views', './views')
app.set('view engine', 'jade')

设置好后,在项目文件夹下添加views文件夹,并在views目录下添加一个index.jade的Jade模板文件。

html
  head
    title!= title
  body
    h1!= message

如果想了解更多jade模板的语法,请参考Jade官方文档.
返回应用入口index.js文件下,修改index.js代码,如下

app.get('/', function (req, res) {
  res.render('index', { title: 'WordCount测试', message: '厦门大学数据库实验室'})
})

此时在终端中重新执行如下命令:

node index.js

浏览器再次访问localhost:3000,模板文件“index.jade”就会被渲染成html.

完善模板引擎index.jade文件

修改index.jade模板文件,增加模板的form等标签。

html
  head
    title!= title
  body
    h1!= message  
    form(action='/', method='post')
      p 请在下面输入所需要进行词频统计文件的路径
      p HDFS文件路径示例:
      p 本地文件路径示例:
      br
      input(name='path')
      input(type='submit')
      br
      textarea(rows='40', cols='40')!=result 

这里只是使用简单的页面效果,如果想增加更多的页面效果,请自行添加css、js文件。

index.js应用入口增加路由等功能

node.js要获取从前端post过去的,还需要安装body-parser,才能识别post过来的数据.
在终端中输入执行如下命令

npm install body-parser --save

然后利用node.js中child_process模块执行外部命令,并获取外部命令的输出结果.
完整的index.js代码如下:

const express = require('express')
const bodyParser = require('body-parser')
const exec = require('child_process').exec

const app = express();

// 设置模板引擎
app.set('views','./views')
app.set('view engine', 'jade')
// 添加body-parser解析post过来的数据
app.use(bodyParser.urlencoded({extended: false}))
app.use(bodyParser.json())

app.get('/', function (req, res) {
  res.render('index', {title: 'WordCount测试', message: '厦门大学数据库实验室!'})
})

app.post('/',function(req, res){
  const path = req.body.path.trim()
  const jarStr = '/usr/local/hadoop/bin/hadoop jar ~/WordCount.jar ' + path +' /output'
  const rmrStr = '/usr/local/hadoop/bin/hadoop fs -rmr /output'
  const catStr = '/usr/local/hadoop/bin/hadoop fs -cat /output/part-r-00000'
  exec(rmrStr,function(err, stdout, stderr){
    exec(jarStr, function(err, stdout, stderr){
      // 判断路径是否存在,如果路径不存在,则显示错误信息
      if(stderr){
        res.render('index', {title: 'WordCount测试', message: '厦门大学数据库实验室!', result: stderr})
      }
      //执行成功后,显示统计结果。
      exec(catStr,function(err, stdout, stderr){
        res.render('index', {title: 'WordCount测试', message: '厦门大学数据库实验室!', result: stdout})
      })
    })
  })
})

const server = app.listen(3000, function () {
  const host = server.address().address;
  const port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});

到目前为止,一个简易的Web端文件词频统计动态网页已经搭建完成。