网站搭建通常由多人相互配合完成;在整个开发过程中,需要涉及/数据库/后台管理/前端开发等等;基于简单的语言完成整个网站的构建,可以有助于了解网络的构成.在没有足够精力前提下,对其他领域知识’一知半解’也是很有用的,至少可以保证在接口对接等等情况时,可以有目的性的查找问题.
数据库—-sqlite
sqlite数据库算是所有数据库中,最小最轻量的了,基本字段只有五种:
- integer——整型
- real——浮点型
- text——字符串类型
- blob——字节流,将输入内容不改变进行存储
- null——空字段
在数据处理时,使用简单的字段类型,可以很方便的进行一些数据转换,从整体来看,sqlite有JS的某些特质;同时sqlite也是安卓端默认的数据库,因此对于移动开发人员会比较熟悉一些;
sqlite支持性比较好,在linux和window端均可以进行安装,具体内容可以参照 菜鸟教程-SQLITE,sqlite语法非常简单,使用起来很方便,对于小型系统而言,非常的适合。
后台—-Nodejs
nodejs自其2009出生以来,受到的广泛的关注,对于前端人员来说,javaScript已经炉火纯青,nodejs与原有的js相比,增量比较的小;由于V8引擎的存在,js运行速度足以达到大部分业务的需要;
重要的是,ES6 标准的出台,在使得开发规范的同时,引入了很多面向对象的特性,原有的js由于功能和语法的需要,不得不使用大量的闭包;面对大量的var,简直头晕脑胀;ES6则新引入局部变量let,类class等,使得js开发门槛大大降低;
当前nodejs社区也是异常的火热,大量的模块module被上传到npm中,真正实现了“插件式”开发;在需要某项功能时,一个require就可以解决所有。
网上有现成的界面渲染框架,只要稍微懂得jsp原理,就可以使用,这里选择使用较为简单的express-ejs框架模版。
express-ejs使用
nodejs集成sqlite数据库
前端框架
前端页面对于一个非专业人员来说,想看懂不难,但想实现绚丽的效果,就不是简单能够做到的,因此对于前端界面,这里选择克隆基于 bootstrap 前端框架。
框架模版下载地址。
组合开发
在选定语言模版后,就可以着手进行小型服务器搭建了;
1、环境
首先需要选择某个操作平台,window/linux等,这里环境限制,我使用了window开发环境;安装nodejs开发环境,安装express插件。安装node环境。使用npm安装sqlite模块:
2、工具
下载一款良好的开发工具,我一般习惯使用webstorm,因为与AndroidStudio风格很相似。
3、创建项目
1、打开webstorm
2、使用express插件新建项目,在红线处设置项目名
3、项目创建后,会自动生成多个文件和文件夹
- /bin 一般存放可执行的js文件
- /node_modules 存放node项目开发过程中需要require的模块
- /public 存放一些静态的文件,如css,html,字体,图片等等
- /routes 路由文件,在网络请求时,express拦截器可以将相应请求拦截给指定的文件去处理
- /views 模版文件,用于生成html文件或文本内容,ejs文件,可以通过 <%= %> 等方式进行渲染。
- .gitignore 在项目上传至github 等git仓库时,配置不予上传的内容。
- .app.js 主要的文件,在这里可以配置express的拦截方法,配置静态文件的寻找路径,错误异常处理等等。
- package.json 包配置文件,其中记录了项目名,版本,依赖等等内容,在项目根目录下运行npm install 命令,会将配置的依赖模块进行安装。
- package-lock.json 其他的一些依赖配置,一般不主动配置
- README.md makedown文件,用于进行项目说明
4、导入前端模版
将下载好的html,js,css,img等图片导入项目中,放入public 目录。将首界面文件更改为ejs文件放入到views目录,用于填充数据后返回给客户端进行显示。
5、初始化数据库,配置app.js,生成路由类
1、先新建config.js文件,用于配置项目的host,port,数据库名称
代码块:
exports.dbName='company.db';
exports.host='localhost';
exports.port=80;
2、新建database.js文件,用于加载数据库:这里配置了模版界面中需要显示的信息、数据库表等
代码块:
//file:test.js
var sqlite3 = require('sqlite3');
var debug = require('debug');
var globalConfig=require('../config');
//新建并创建表
var db;
//操纵实例
var singleInstance = {};
singleInstance.pageConfig = {
company: '**科技',
about: '关于',
services: '服务',
products: '产品',
joinUs: '人才招聘',
blog: '博客',
contact: '联系我们',
page: '界面元素',
regulations: '制度',
motto: '想法与实现之间,尚有很大的差距',
mottoAuthor: 'Mark Simmons,Nett Media',
introduce: '这是我们',
introduceTitle: '激情,昂扬,拼搏,进取',
introduceContent: '这是一个集体,这是我的家,这里有技术大牛,有商务精英,有销售专家,更有尊敬的领导...',
productsBelief: '我们是一个信誉良好的网络公司',
moreBlog: '查看更多博客',
address: '**街道,**区<br>郑州,河南',
email: '***@***.com',
phone: '180 **** ****',
getContact: '如果对本公司有****,......,请与我们取得联系',
submitUrl: '/postSubject'
};
singleInstance.getDB = function () {
if (db) return db; else throw "数据库未创建,请先调用 initDB 方法";
};
/**
* 验证用户账户
*
* @param account 帐号
* @param password 密码
* @param callback 回调函数,包含两个参数:err,data,若成功则err为null,若查询不到数据,则data为undefined,否则data为有效数据
*/
singleInstance.checkRootAccount = function (account, password, callback) {
db.get("select * from " + TABLE_MEMBER + " where account=$account and password=$password", account, password, callback)
};
/**
* 查询博客信息
*
* @param limit 限制获取多少条数据,小于0表示不处理
* @param orderBy 以哪个字段排序
* @param orderType 排序方式,默认>0为升序,<0为降序,0表示不处理
* @param callback 回调,err,rows[多个数据为数组形式]
*/
singleInstance.queryTableBlog = function (limit, orderBy, orderType, callback) {
var order = '';
if (orderType) {
order = " order by " + orderBy + " " + (orderType > 0 ? "ASC" : "DESC") + " ";
}
limit = limit < 0 ? "" : " limit " + limit + " ";
db.all("select * from " + TABLE_BLOG + order + limit, callback);
};
/**
* 向数据库中写入建议信息
*
* @param callback 回调,err,rows[多个数据为数组形式]
* @param obj js对象,键和值对应数据库中字段
*/
singleInstance.insertTableSuggestions = function (obj, callback) {
var keys = '';
var values = '';
for (var key in obj) {
keys += "," + key;
values += ",'" + obj[key] + "'";
}
if (Object.keys(obj)) {
keys = keys.substring(1);
values = values.substring(1);
}
var sql = "insert into " + TABLE_SUGGESTIONS + "(" + keys + ") values(" + values + ");";
db.run(sql, callback);
};
/**
* 获取职位对应的字符串形式
*/
singleInstance.getJOINType = function (id) {
switch (id) {
case 0:
return '总经理';
case 1:
return '软件开发人员';
case 2:
return '硬件开发';
case 3:
return '前端开发';
case 4:
return '安卓开发';
}
return '普工';
};
/**
* 获取职工类型
*/
singleInstance.getStaffDuty = function (duty) {
switch (duty) {
case 0:
return '职员';
case 100:
return '项目组长';
case 200:
return '总监';
case 300:
return '经理';
case 400:
return '总经理';
case 500:
return '董事长';
}
return '临时工';
};
//数据库表
var TABLE_INFO = 'table_info';
var TABLE_STAFF = 'table_staff';
var TABLE_SERVICE = 'table_service';
var TABLE_PRODUCT = 'table_product';
var TABLE_BLOG = 'table_blog';
var TABLE_MEMBER = 'table_member';
var TABLE_JOIN = 'table_join';
var TABLE_REGULATIONS = 'table_regulations';
var TABLE_SUGGESTIONS = 'table_suggestions';
var defaultConfig = {
dbName: '../database/'+globalConfig.dbName,
tables: [
//省略创建其他表
//公司内部人员博客:博客编号,图片,员工id,笔名,标题,简介,博客地址
{
name: TABLE_BLOG,
columns: ['id', 'icon', 'staff_id', 'pen_name', 'title', 'brief', 'address', 'weight', 'time'],
types: ['integer primary key autoincrement', 'text', 'integer', 'text', 'text', 'text', 'text', 'integer', 'integer, FOREIGN KEY (staff_id) REFERENCES '+TABLE_STAFF+'(id)']
}
]
};
exports.initDB = function (config) {
if (!db) {
if (!config) config = defaultConfig;
db = new sqlite3.Database(config.dbName, function (err) {
if (err) throw "数据库创建失败:\n" + err;
//页面配置表
var create_table = '';
var item;
for (var k = 0; k < config.tables.length; k++) {
item = '(';
for (var i = 0; i < config.tables[k].columns.length; i++) {
item += config.tables[k].columns[i] + " " + config.tables[k].types[i];
if (i == config.tables[k].columns.length - 1) {
item += ')';
} else {
item += ','
}
}
create_table += "create table if not exists " + config.tables[k].name + item + ";";
}
debug.log(create_table);
db.exec(create_table, function (err) {
if (err) throw "无法创建TABLE" + err;
});
});
}
return singleInstance;
};
3、配置app.js文件,设定路由拦截,静态文件选择路径,同时将ejs模版渲染需要的数据绑定到app.locals 上,声明周期为全局。
代码块:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var debug = require('debug');
var dbInstance = require('./src/database').initDB();
var ejs = require('ejs');
var fs=require('fs');
var welcome = require('./routes/welcome');
var users = require('./routes/users');
var reboot = require('./routes/reboot');
var app = express();
//定义log
var log = debug.log;
debug.log = function (msg) {
log("=====BEGIN");
log(msg);
log('=====END\n');
};
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
/**
* 更新app.locals数据
*/
function initAppLocals() {
///////////////////////////////////////////////////// 从数据库中获取最新记录
/**
* 设定界面元素显示信息
*/
app.locals.pageConfig = dbInstance.pageConfig;
/**
* 博客消息
*/
dbInstance.queryTableBlog(5, 'weight', -1, function (err, data) {
app.locals.tableBlog = data;
debug.log(data);
});
//省略其他表初始化过程
/**
* 内部方法,提供数据格式转换
*/
app.locals.getStaffDuty=dbInstance.getStaffDuty;
app.locals.getJOINType=dbInstance.getJOINType;
/////////////////////////////////////////////////////
}
initAppLocals();
exports.initAppLocals=initAppLocals;
//拦截器,再次拦截
app.use('/users', users);
//重新从数据库中加载数据
app.use('/reboot', reboot);
//提出建议内容
app.use(dbInstance.pageConfig.submitUrl,function (req,res,next) {
var name=req.body['name'];
var email=req.body['email'];
var subject=req.body['subject'];
var content=req.body['content'];
var time=new Date().getTime();
dbInstance.insertTableSuggestions({
name:name,
email:email,
subject:subject,
content:content,
time:time
},function (err) {
if(!err){
res.end('success');
}else{
res.end('error');
}
});
});
//如果是html中访问css,js等文件,则修改路径的规则
app.use('/public',function (req, res, next) {
console.log(req.url);
fs.readFile(path.join(__dirname,req.baseUrl,req.url), function (err, data) {
if (err) {
res.end();
}
res.end(data);
});
});
//加载首页信息
app.use('/index',welcome);
app.use('/*', function (req, res, next) {
res.redirect('/index');
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
4、模版渲染,将app.locals 对象上的数据渲染到ejs模版中,生成html内容,在客户端访问时返回给客户端。
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title><%= pageConfig.company %></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<!-- css -->
<link href="../public/css/bootstrap-responsive.css" rel="stylesheet">
<link href="../public/css/style.css" rel="stylesheet">
<!-- skin color -->
<link href="../public/color/default.css" rel="stylesheet">
<!--[if lt IE 7]>
<link href="../public/css/font-awesome-ie7.css" type="text/css" rel="stylesheet">
<![endif]-->
<link rel="shortcut icon" href="../public/img/favicon.ico">
</head>
<body>
<!-- navbar头部 -->
<div class="navbar-wrapper">
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<!-- Responsive navbar -->
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"><span
class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span>
</a>
<%# 加载导航栏数据%>
<h1 class="brand"><a tppabs="#" disabled="true"><%= pageConfig.company %></a></h1>
<!-- navigation -->
<nav class="pull-right nav-collapse collapse">
<ul id="menu-main" class="nav">
<li><a title="team" href="#about"><%= pageConfig.about %></a></li>
<li><a title="services" href="#services"><%= pageConfig.services %></a></li>
<!--<li class="hidden"><a title="products" href="#products"><%= pageConfig.products %></a></li>-->
<li><a title="joinUs" href="#joinUs"><%= pageConfig.joinUs %></a></li>
<li><a title="blog" href="#blog"><%= pageConfig.blog %></a></li>
<li><a title="regulations" href="#regulations"><%= pageConfig.regulations %></a></li>
<li><a title="contact" href="#contact"><%= pageConfig.contact %></a></li>
<li class="hidden"><a href="../public/page.html"><%= pageConfig.page %></a></li>
</ul>
</nav>
</div>
</div>
</div>
</div>
<!-- Header area -->
<div id="header-wrapper" class="header-slider">
<header class="clearfix">
<div class="logo">
<img src="../public/img/logo-image.png" alt=""/>
</div>
<div class="container">
<div class="row">
<div class="span12">
<div id="main-flexslider" class="flexslider">
<ul class="slides">
<%# 首页欢迎内容,海报%>
<% for(var position in tableInfo) { %>
<li>
<p class="home-slide-content">
<%= tableInfo[position].title %>
</p>
</li>
<% } %>
</ul>
</div>
<!-- end slider -->
</div>
</div>
</div>
</header>
</div>
<%# 座右铭%>
<!-- spacer section -->
<section class="spacer green">
<div class="container">
<div class="row">
<div class="span6 alignright flyLeft">
<blockquote class="large">
<%= pageConfig.motto %> <cite><%= pageConfig.mottoAuthor %></cite>
</blockquote>
</div>
<div class="span6 aligncenter flyRight">
<i class="icon-coffee icon-10x"></i>
</div>
</div>
</div>
</section>
<!-- end spacer section -->
<!-- section: team -->
<%# 员工信息 %>
<section id="about" class="section">
<div class="container">
<h4><%= pageConfig.introduce %></h4>
<div class="row">
<div class="span4 offset1">
<div>
<h2><%= pageConfig.introduceTitle %></h2>
<p><%= pageConfig.introduceContent %></p>
</div>
</div>
<div class="span6">
<div class="aligncenter">
<img src="../public/img/icons/creativity.png" alt=""/>
</div>
</div>
</div>
<div class="row">
<% for(var item in tableStaff) { %>
<div class="span2 <%= item == 0 ? 'offset1' : '' %> flyIn">
<div class="people">
<img class="team-thumb img-circle" src="<%= tableStaff[item]['icon'] %>" alt=""/>
<h3><%= tableStaff[item]['name'] %></h3>
<p>
<%= getStaffDuty(tableStaff[item]['duty']) %>
</p>
</div>
</div>
<% } %>
</div>
</div>
<!-- /.container -->
</section>
<!-- end section: team -->
<!--省略其他数据加载部分-->
6、数据填充
在数据库中插入虚假的信息,填充网页内容。
这样服务端以及数据库就已经完成了,然后针对前端显示的效果进行微调,然后进入bin 目录执行命令:node www 启动服务,此时可以使用浏览器访问本地地址:http:/localhost/
=============================
整理整个项目放入github上,其中前端框架放在public 目录中。
GITHUB地址:https://github.com/lovingning/CompanyGateway
=============================