【Node.js基础篇】(六)实现如同jsp标签的HTML模板

一、概述

在上一篇中,我们已经可以使用mime类型模块以及文件传输模块为客户端返回任何类型的文件,但目前能返回的只有静态的HTML,css等文件,而jsp等服务器端语言却可以通过<% %>标签来实现java的扩张,根据请求来指定返回给客户端的html,从而只需要有一个html模板,就可以返回无数个html页面,而不用一个一个页面的编写,然后根据请求路由各个HTML。

今天,我们要实现的就是类似jsp这样的html模板文件(当然,远没有jsp那般强大)。首先,得先介绍一下JSON(JavaScript Object Notation)

二、JSON

JSON是一种轻量级的数据交换格式,可用来替代xml成为服务端和客户端之间数据交换格式。程序解析起JSON数据来也非常快。下面是JSON的语法和一段示例:

  • 数据在名称/值对中
  • 数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组
示例:
{
    "menu": {
        "id": "file",
        "value": "File",
        "popup": {
            "menuitem": [
                { "value": "New", "onclick": "CreateNewDoc()" },
                { "value": "Open", "onclick": "OpenDoc()" },
                { "value": "Close", "onclick": "CloseDoc()" }
            ]
        }
    }
}

从语法和示例我们可以看出:JSON具有两种结构,对象(使用{})和数组(使用[])

JSON基于JavaScript标准的一个子集,所以基于JavaScript的Node.js使用起JSON来是得天独厚。

三、开发步骤

项目依旧是延续着上一篇的TestFrame,但不会很涉及,主要是讲讲实现方法

1、创建data文件夹和data.json

首先,我们先来确定一下等会要显示的数据。和以前一样,今天的也是显示唐诗,JSON数据如下:

{
    "jingyesi":{
        "title":"静夜思",
        "1":"床前明月光",
        "2":"疑是地上光",
        "3":"举头望明月",
        "4":"低头思故乡"
    },

    "chunxiao":{
        "title":"春晓"
        "1":"春眠不觉晓",
        "2":"处处闻啼鸟",
        "3":"夜来风雨声",
        "4":"花落知多少"
    }
}

只为示例,所以只有两首。

2、创建tangshi.html模板

下面就是创建一个html的唐诗模板:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>唐诗</title>
    <link  href="./stylesheets/index.css" rel="stylesheet" type="text/css">
</head>
<body>
<nav>%title%</nav>
<div id="value">
    <p>%1%</p>
    <p>%2%</p>
    <p>%3%</p>
    <p>%4%</p>
</div>
</body>
</html>

现有文件目录结构如下:

红色方框里就是新添加的文件和文件夹。

3、创建render.js模板渲染函数

在有了模板以后,我们就要根据数据和模板来创建新的html,然后将此html文件返回给客户端,下面是render这个渲染函数(我们将其做成一个模块):
render.js

/**
 * Created by Administrator on 2015/4/1.
 */

//文件模块
var fs = require('fs');

//获取mime模块
var mime = require("mime");

//获取response模块
var response = require("./response");

var render = function(res,filePath,dataSource,target){
    //读取文件进行渲染
    fs.readFile(filePath,function(err,data){
        if(err){
            console.log(err);
        }else{
            var targetData = dataSource[target];
            //转换HTML模板,生成新的HTML
            var dataString = data.toString();
            dataString = dataString.replace("%title%",targetData["title"]);
            dataString = dataString.replace("%1%",targetData["1"]);
            dataString = dataString.replace("%2%",targetData["2"]);
            dataString = dataString.replace("%3%",targetData["3"]);
            dataString = dataString.replace("%4%",targetData["4"]);
            response.response(res,filePath,dataString);
        }
    });
};

exports.render = render;

render函数参数说明:
res : response,用于响应客户端,此参数将传给response模块
filePath : html模板的路径
dataSource : JSON文件的数据源
target : 唐诗的名字(如chunxiao)

在这里,还用到了一个response模块,这是为了尽量不去改以前的代码,所以为render模块单独写了一个响应模块,代码如下:
response.js

/**
 * Created by Administrator on 2015/4/1.
 */

//获取mime模块
var mime = require("mime");
var response = function(res,filePath,data){
    res.writeHead(200,{                            //响应客户端,将文件内容发回去
        'Content-type':mime.lookup(filePath)});    //通过后缀名指定mime类型
    res.end(data);
};
exports.response = response;

4、使用render

在这里要修改一下Luyou.js
首先是在文件开头加上:

//获取render模块
var render = require("./file/render");
//模板路径
var ts = "./file/tangshi.html";
//数据源路径
var data = "./data/data.json";

然后是Http服务器文件路由函数的修改,

//创建HTTP服务器
var server = http.createServer(function(req,res){
   console.log(req.url);               //在控制台打印请求
    //判断URL,提供不同的路由
    if(req.url == '/index' || req.url == '/') {    //主页
        index.index(res);
    }
    else if(req.url.substr(0,8) == '/tangshi'&& req.url.indexOf(".")<=0) {
        //获取诗名
        var name = req.url.substr(9);  //获取/tangshi/以后的字符串,即诗名
        //读取JSON文件内容
        fs.readFile(data,function(err,data){
            if(err){
                console.log(err);
            }else{
                console.log(name);
                var dataString = data.toString();
                var dataJson = JSON.parse(dataString);
                console.log(dataJson);
                if(!dataJson[name]){    //如果没有诗存在,则跳到404 error
                    error404(res);
                    return;
                }
                render.render(res,ts,dataJson,name);
            }
        });
    }
    else {                              //访问其它静态文件,如/stylesheets/index.css
        req.url = req.url.replace("/tangshi","");
        Response(res,"./file"+req.url);
    }
});

客户端查询唐诗的路径有两条:
http://localhost:3000/tangshi/jingyesi
http://localhost:3000/tangshi/chunxiao

然后在/tangshi路径里会对url进行处理,提取出诗名后进行render处理,至于req.url.indexOf(".")<=0是为了防止静态css文件也在这条路由路径处理。