ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

服务器渲染+自定义模块+mysql操作

服务器渲染+自定义模块+mysql操作

1.服务器渲染

A.第一步,导入模块库和第三方库

npm init

npm --registry https://registry.npmmirror.com install art-template moment

B.第二步,调整html文件

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>仿服务器资源</title></head><body><div class="container" style="width: 600px; margin: 0 auto"><h1>Index Of-2</h1><tableborder="1"width="600px"style="border-spacing: 0; text-align: center"><thead><th>图片</th><th>文件名称</th><th>最后更改时间</th><th>大小(字节)</th><th>文件类型</th></thead><tbody id="tShow">{{each data}}<tr>{{if $value.type == 'F'}}<td><img src="./imgs/file.png" width="50" alt="" /></td>{{else }}<td><img src="./imgs/folder.png" width="50" alt="" /></td>{{/if}}<td>{{$value.uname}}</td><td>{{$value.mtime}}</td><td>{{$value.size}}</td><td>{{$value.type=='F'?'文件':'文件夹'}}</td></tr>{{/each}}</tbody></table></div></body><script></script>
</html>

调整js文件

var http = require("http");
var fs = require("fs");
var moment = require("moment");
var template = require("art-template"); // 第三方模块,读取数据的
template.defaults.root = "./"; // 设置文件读取路径为相对路径!!!!var server = http.createServer();server.on("request", function (req, res) {// 防止乱码res.setHeader("Content-Type", "text/html;charset=utf-8");var ulrs = req.url;// 普通html文档if (req.url == "/") {fs.readdir("./", "utf8", function (err, data) {console.log(data, "datadir");var data_arr = []; // 返回的结果var count = 0; // 计数for (var i = 0; i < data.length; i++) {data_arr[i] = {};// 异步,闭包(function (i) {fs.stat(data[i], function (err1, data1) {// 数量叠加count++;// 判断是否为文件if (data1.isFile()) {data_arr[i].type = "F";} else {data_arr[i].type = "NF";}data_arr[i].uname = data[i];// 为了读取时间更友好,采用第三方模块data_arr[i].mtime = moment(data1.mtime).format("YYYY-MM-DD HH:mm:ss");data_arr[i].size = data1.size;// 跳出闭包,并返回值if (count == data.length) {res.end(template("./01index.html", { data: data_arr }));}});})(i);}});} else {// 其他资源fs.readFile("." + ulrs, function (err, data) {res.end(data);});}
});// 端口
server.listen(5657, function () {console.log("端口5657已启动,正在加载......");
});

效果图:
在这里插入图片描述

2.node模块化及commonJS规范

2.1 node模块化

通过前面几个章节的学习,我们基本掌握了NodeJS编程的基础知识,但是我们也直观的发现了一个问题,和我们之前学习浏览器编程时JS,差异还是很大的;都是JS编程,为何有这种差异?前面写过的仿Apache服务器的案例中,使用过内置fs模块,使用过moment模块,而这些模块都不是我们写的,都是直接拿过来使用,那么我们能不能自己写一个模块,应该怎么写,有那些规矩,如果我们自己写了一个模块,能不能提供给其他编程人员直接使用,应该如何使用?
在这里插入图片描述

2.2 commonJS规范的由来

JS的表现能力取决于宿主环境提供的API,在web1.0时代。W3C组织提供了浏览器的规范支持,在Web2.0时代。随着HTML5的发展,更多的标准API出现在了浏览器中,但是,在后端JS中标准的指定纹丝不动;

由火狐工程司Kevin Dangoor于2009年1月提出名为ServerJS的规范;2009年8月,更名为CommonJS,以显示API的更广泛实用性。

引用:

我在这里描述的不是技术问题。这是一个人闷聚在一起并决定前进并开始建立更大和更冷的东西的问题。——Kevin Dangoor
在这里插入图片描述

2.3 CommonJS的模块规范

CommonJS对模块的定义十分简单,主要分为:

A. 模块引用

使用require()方法引用一个模块API

B. 模块定义

在模块中使用exports对象导出当前模块数据或方法;

在模块中还存在一个module对象,它代表模块自身,module对象由一个exports属性,用于数据导出;

其实exports对象就是modele.exports的引用:exports===module.exports

C. 模块标识

其实就是模块的文件名,必须符合小驼峰法命名规则,使用require()引入时使用**.或…开头的相对路径或绝对路径**,引入时可以不写文件后缀名;

重点注意:模块中的方法和变量的作用于尽在模块内部,每个模块具有独立的空间,互不干扰。

CommonJS构建的模块机制中的引入与导出是我们完全不用考虑变量污染或者替换的问题,相比与命名空间的机制,简直就是天才和菜鸟的区别;

2.3.1 自定义模块

1.自定义模块(1.a.js)

var a=1;
var b=2;
var c=a+b;
exports.data=c;

2.加载(2.b.js)

var a=require("./1.a");//自定义模块不需要写后缀名,第二,要用相对路径写法
console.log(a);
2.3.1.1 默认导出与默认导入

A. 默认导出语法export.default默认导出的成员

B. 默认导入语法import接收名称 from ‘模块标识符’

定义2.m1.js

//定义私有成员a和c
let a=10;
let c=20;//外界访问不到d,因为它没有暴露出去
let d=30;function show(){}//将本模块中的私有成员暴露出去,供其他模块使用
export default{a,c,show
}

导入模块成员2.index.js

//导入模块成员
import m1 from './2.m1.js'  //加后缀名
console.log(m1)//在这里使用会报错,要配置package.json的文件,"type":"module"

输出结果在这里插入图片描述
注意:每个模块中,只能使用唯一的一次export default,否则会报错

2.3.1.2 按需导出与按需导入

A. 按需导出语法 export let s1=10;

B. 按需导入语法 import{s1} from ‘模块标识符’

注意:每个模块中,可以使用多次按需导出

m1.js

//定义私有成员a和c
let a=10;
let c=20;//外界访问不到d,因为它没有暴露出去
let d=30;function show(){}//将本模块中的私有成员暴露出去,供其他模块使用
export default{a,c,show
}//按需导出
export let s1='aaa';
export let s2='ccc';
export function say(){console.log('hello world')
}

index.js

//导入模块成员
import m1 from './2.m1.js'  //加后缀名
console.log(m1)//在这里使用会报错,要配置package.json的文件,"type":"module"//按需导入,其中名字必须和按需导出的名字一致
import { s1, s2, say as saySay } from './2.m1.js'
console.log(s1, s2);
//如果一旦更改的名字,就只能用新名字,不可以使用原来的名字了
console.log(saySay)
//console.log(say)  //say is not defined 
2.3.1.3 直接导入并执行模块代码

有时候,我们只想单纯执行某个模块中的代码,并不需要得到模块中向外暴露的成员,此时,可以直接导入并执行模块代码

//当前模块

//在当前模块循环输出一些东西
for(var  i=0;i<3;i++){console.log('你真棒');
}

//导入模块

import './2.m1.js'

2.4 模块加载的顺序和规则

在CommonJS规范中,使用require()加载(引入)模块时,模块标识必须使用相对路径或绝对路径指明模块位置,但是在node的实现中,我们可以不知名模块路径;如:require(‘fs’)、require(‘moment’);

如果没有指明路径,那就是加载核心模块或第三方模块,指明加载路径一般就是加载自定义模块;

不管加载什么模块,都是优先从缓存中加载:

说明:

​ Node加载模块时,如果这个模块已经被加载过了,则会直接缓存起来,将来再次引用 是不会再次加载这个模块(即:如果一个模块被加载两次,则模块中的代码只会被执行 一次)。

而核心模块和第三方模块的加载顺序就是:

说明:

​ 先加载核心模块,核心模块的内容都是在安装node时已经编译好的可执行的二进制代码,加载执行的速度,仅次于缓存加载,如果核心模块中没有,则加载第三方模块。

第三方模块加载的规则:

说明:

​ A. 先在当前文件的模块所属目录去找node_modeules目录

​ B. 如果找到,则去该目录中找模块名的目录,如:moment

​ C. 如果找到moment目录,则找该目录中的package.json文件

​ D. 如果找到package.json文件,则找该文件中的main属性

​ E. 如果找到main属性,则拿到该属性对应的文件

​ F. 如果找到moment目录之后

​ \1. 没有package.json

​ \2. 或者由package.json没有main属性

​ \3. 或者由main属性,但是指向的路径不存在

​ \4. 则node会默认去看一下moment目录中有没有index.js–>index.json–>index.node文件

​ G. 如果找不到index或者找不到moment或者找不到node_modules

​ H. 则进入上一级目录找node_moudles查找(规则同上)

​ I. 如果上一级还找不到,继续向上,一致到当前文件所属磁盘的根目录

​ J. 如果到磁盘根目录还没有找到,直接报错

3.mysql的增删改查

3.1 表结构

在这里插入图片描述

3.2 新建项目搭建环境

npm init
npm install mysql moment art-template jquery bootstrap formidable --registry https://registry.npmmirror.com install express

html界面(03studentManage.html)

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>学生信息</title><link rel="stylesheet" href="./node_modules/bootstrap/dist/css/bootstrap.min.css" />
</head>
<body><div class="container"><h1>学生信息管理界面</h1><table class="table"><tr><th>学号</th><th>姓名</th><th>年龄</th><th>性别</th><th>登录名</th><th>登录密码</th></tr>{{each datas}}<tr><td>{{$value.Sno}}</td><td>{{$value.Sname}}</td><td>{{$value.Sage}}</td><td>{{$value.Ssex}}</td><td>{{$value.loginName}}</td><td>{{$value.loginPwd}}</td></tr>{{/each}}</table></div>
</body>
</html>

响应js(03studentManage.js)

//导入模块
var http = require('http');//核心模块,
var fs = require('fs');//核心模块
var moment = require('moment');//第三方模块
var template = require('art-template');
template.defaults.root = './';
var db = require('./3.studentDB');
var server = http.createServer();//响应
server.on('request', function (request, response) {var urls = request.url;//防止乱码response.setHeader('Content-type', "charset=utf-8");//资源绑定if (urls == "/") {//html资源response.end(template('3.studentManage.html', { datas: db.datas }));} else {response.setHeader('Content-type', "text/css;charset=utf-8");//读取其他资源fs.readFile('.' + urls, function (err, data) {response.end(data);})}
});//端口号
server.listen(2323, function () {console.log('服务2323正在启动.....');
});

注意:资源绑定时,bootstrap样式文件要作为其他资源进行绑定,否则样式会不生效

连接数据库(03studentDB.js)

//数据库操作
var mysql = require('mysql');
//连接数据库
var connection = mysql.createConnection({host: "localhost",user: "root",password: '123456',database: "school2"
});//打开桥梁
connection.connect();
var sql = "select * from student";
connection.query(sql, function (err, data) {module.exports.datas = data;
});//关闭桥梁
connection.end();

4.连接mysql的增删查改

4.1 表结构

在这里插入图片描述

4.2 端口

//端口页面
const http=require('http');
const yewu=require('./2.yewu');const server=http.createServer();
//事件
yewu.bind(server);//端口
server.listen(9000,function (){console.log('正在启动服务9000.....')
})

4.3 业务界面

//业务界面
var fs = require('fs');
var url = require('url');//地址对象
var template = require('art-template');
var moment = require('moment');
template.defaults.root = './';//相对路径
var db = require('./3.db');//连接数据库的,自定义模块
var formidable = require('formidable');//读取表单//方法
module.exports.bind = function (server) {//读取数据server.on('request', function (request, response) {//获取对象var urlS = url.parse(request.url, true);//1.查询if (urlS.pathname == '/') {let tSname = urlS.query.tSname == undefined ? "" : urlS.query.tSname;db.student_selectBySname(tSname, function (data) {response.end(template("./4.index.html", { datas: data }));});}//2.删除else if (urlS.pathname == '/delete') {let sno = urlS.query.sno == undefined ? "" : urlS.query.sno;db.student_deleteBySno(sno, function (data) {response.setHeader('Content-type', 'text/html;charset=utf-8');var result = "<script>alert('删除失败');window.location.href='http://localhost:9000';</script>";if (data.affectedRows > 0) {result = "<script>alert('删除成功');window.location.href='http://localhost:9000';</script>"}response.end(result);});}//3.查看else if (urlS.pathname == '/see') {if (request.method.toString() == "GET") {//提交方式let sno = urlS.query.sno == undefined ? "" : urlS.query.sno;db.student_selectBySno(sno, function (data) {if (sno == "") {var obj = new Object();obj.Sno = "";obj.Sname = "";obj.Sage = "";obj.Ssex = "";obj.loginName = "";obj.loginPwd = "";response.end(template('5.see.html', { datas: obj }));} else {response.end(template('5.see.html', { datas: data[0] }));}});}else if (request.method.toString() == "POST") {let sno = urlS.query.sno == undefined ? "" : urlS.query.sno;var formData=new formidable.IncomingForm();//可以获取表单提交的所有数据formData.parse(request,function (err,data){//调用数据库db.student_addAndUpdate(sno,data,function (data1){response.setHeader('Content-type', 'text/html;charset=utf-8');var result = "<script>alert('修改失败');window.location.href='http://localhost:9000';</script>";if (data1.affectedRows > 0) {result = "<script>alert('修改成功');window.location.href='http://localhost:9000';</script>"}response.end(result);})});}}else {//其他资源fs.readFile("." + request.url, function (err, data) {response.end(data);})}});
}

4.4 db界面

//连接数据库的
const mysql = require('mysql');//创建对象
var connection = mysql.createConnection({host: 'localhost',user: 'root',password: '123456',database: 'school27'
});//打开
connection.connect();//查询,根据用户名进行模糊查询
module.exports.student_selectBySname = function (sname, callback) {let sql = `select * from student where sname like '%${sname}%'`;connection.query(sql, function (err, data) {if (!err) {callback(data);}});
}//删除,根据学号删除
module.exports.student_deleteBySno = function (sno, callback) {let sql = `delete from student where sno=${sno}`;connection.query(sql, function (err, data) {if (!err) {callback(data);}});
}//根据学号查看学生信息
module.exports.student_selectBySno = function (sno, callback) {let sql = `select * from student where Sno='${sno}'`;connection.query(sql, function (err, data) {if (!err) {callback(data);}});
}//新增或者修改
module.exports.student_addAndUpdate = function (sno, student, callback) {let sql = `insert into student values('${student.tSno}','${student.tSname}',${student.tSage},'${student.tSsex}','${student.tLoginName}','${student.tLoginPwd}')`;if (sno !== "") {sql = `update student set Sno='${student.tSno}',Sname='${student.tSname}',Sage=${student.tSage},Ssex='${student.tSsex}',loginName='${student.tLoginName}',loginPwd='${student.tLoginPwd}' where Sno='${sno}'`;}connection.query(sql, function (err, data) {if (!err) {callback(data);}});
}

4.5 html页面

4.index.html查看界面

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>学生信息管理</title><link rel="stylesheet" href="./node_modules/bootstrap/dist/css/bootstrap.min.css" />
</head><body><div class="container"><form action="./"><h1>学生信息管理-完整</h1>用户名:<input type="text" name="tSname" class="form-control" style="width: 200px;display: inline-block;"><input type="submit" value="搜 索" class="btn btn-info"><a href="./see" class="btn btn-danger">新增</a><table class="table"><tr><th>学号</th><th>姓名</th><th>年龄</th><th>性别</th><th>登录名</th><th>登录密码</th><th>操作</th></tr>{{each datas}}<tr><td>{{$value.Sno}}</td><td>{{$value.Sname}}</td><td>{{$value.Sage}}</td><td>{{$value.Ssex}}</td><td>{{$value.loginName}}</td><td>{{$value.loginPwd}}</td><td><a href="./see?sno={{$value.Sno}}" class="btn btn-info">查看</a><a href="javascript:if(confirm('确定要删除吗?')){window.location.href='./delete?sno={{$value.Sno}}'}"class="btn btn-danger">删除</a></td></tr>{{/each}}</table></form></div>
</body></html>

5.see.html(新增界面)

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>查看详情</title><link rel="stylesheet" href="./node_modules/bootstrap/dist/css/bootstrap.min.css" />
</head><body><div class="container"><form action="./see?sno={{datas.Sno}}" method="post"><table><tr><td>学号:</td><td><input type="text" name="tSno" class="form-control" value="{{datas.Sno}}"></td></tr><tr><td>姓名:</td><td><input type="text" name="tSname" class="form-control" value="{{datas.Sname}}"></td></tr><tr><td>年龄:</td><td><input type="text" name="tSage" class="form-control" value="{{datas.Sage}}"></td></tr><tr><td>性别:</td><td><input type="text" name="tSsex" class="form-control" value="{{datas.Ssex}}"></td></tr><tr><td>登录名:</td><td><input type="text" name="tLoginName" class="form-control" value="{{datas.loginName}}"></td></tr><tr><td>登录密码:</td><td><input type="text" name="tLoginPwd" class="form-control" value="{{datas.loginPwd}}"></td></tr><tr><td colspan="2"><input type="submit" value="确 定" class="btn btn-info"></td></tr></table></form></div>
</body></html>

如果上述跳转路由报错或者一直在加载,可检查sql语句是否正确
在这里插入图片描述
在这里插入图片描述

返回列表