在管理系统中需要退出系统返回登陆页面
在login页面加入js代码
if (window != top)
top.location.href = location.href;
在管理系统中需要退出系统返回登陆页面
在login页面加入js代码
if (window != top)
top.location.href = location.href;
今天早上醒来想写一篇博客,忽然发现博客坏掉了,我很忧伤>.<
经过不断地重装之后发现错误解决办法,虽然还没发现原因
主要是以前支持的依赖包好像现在不支持了
进入到hexo的目录下面,然后
npm install
ok问题解决
TIP:出现主题错误的情况,可以试着用一下
hexo clean
大功告成
##连接数据库参数设置db.js
设置数据库参数
var Db = require('mongodb').Db;
var Connection = require('mongodb').Connection;
var Server = require('mongodb').Server;
//module.exports = new Db(settings.db, new Server(settings.host, Connection.DEFAULT_PORT, {safe:false}));
module.exports = new Db('nodetest1', new Server('localhost', Connection.DEFAULT_PORT, {safe:false}));
##增加数据库操作user.js
在model中新建user.js
在这个程序中md5操作没有使用,因为好像会出问题
var mongodb = require('./db')
// 加密 md5
var crypto = require('crypto');
//初始化创建
function User(user) {
this.username = user.username;
this.password = user.password;
// this.password = crypto.createHash('md5').update(user.password).digest('hex');
};
module.exports = User;
//存入数据库操作
User.prototype.save = function save(callback) {
// 存入 Mongodb 的文檔
var user = {
username: this.username,
password: this.password,
};
mongodb.open(function(err, db) {
if (err) {
return callback(err);
}
// 讀取 users 集合
db.collection('users', function(err, collection) {
if (err) {
mongodb.close();
return callback(err);
}
// 爲 name 屬性添加索引
// collection.ensureIndex('username', {unique: true});
// 寫入 user 文檔
collection.save({"username": user.username, "password" : user.password}, function(err, user) {
mongodb.close();
callback(err, user);
});
});
});
};
//根据username获取user,其中callback为user
User.get = function get(username, callback) {
mongodb.open(function(err, db) {
if (err) {
return callback(err);
}
// 讀取 users 集合
db.collection('users', function(err, collection) {
if (err) {
mongodb.close();
return callback(err);
}
// 查找 name 屬性爲 username 的文檔
collection.findOne({username: username}, function(err, doc) {
mongodb.close();
if (doc) {
// 封裝文檔爲 User 對象
var user = new User(doc);
callback(err, user);
} else {
callback(err, null);
}
});
});
});
};
##修改routes/index.js
var express = require('express');
var User = require('../model/user.js');
var router = express.Router();
// 加密
// var crypto = require('crypto');
/* GET home page. */
router.get('/', function(req, res) {
if (req.session.user) {
res.render('index', { title: 'Home', user: req.session.user})
} else {
res.redirect('/login');
}
});
router.get('/register',function(req,res) {
res.render('register', { title: 'register' });
});
router.post('/register',function(req,res) {
var newUser = new User({
username: req.body.username,
password: req.body.password,
});
newUser.save(function(err) {
console.log("save");
req.session.user = newUser;
res.redirect('/');
});
});
router.get('/login',function(req,res) {
res.render('login', { title: 'login' });
});
router.post('/login',function(req,res) {
User.get(req.body.username, function(err, user) {
var password = req.body.password;
if (!user) {
//req.flash('error', '用戶不存在');
console.log("用户不存在");
return res.redirect('/register');
}
if (user.password != password) {
//req.flash('error', '用戶口令錯誤');
console.log("用户密码错误"+ user.password + "but nide:"+ password);
return res.redirect('/login');
}
req.session.user = user;
console.log(req.session);
console.log("登陆成功");
res.redirect('/');
});
});
router.get('/logout',function(req,res) {
req.session.user = null;
// req.flash('success', '登出成功');
res.render('logout', { title: 'login' });
});
module.exports = router;
##创建rejister.ejs
完成上述步骤,应该就可以正常的进行mongoDB,以及session的判断,当然mongodb的module这个都是要提前装好的
npm install mongodb
好了,写完收工
TIP
在本博客中一篇文章已经介绍了,mongoDB的安装,以及数据库路径的设置mongod --dbpath ./db
使用上面命令的时候好像需要删除lock.ns
##express中安装connect-mongo
在nodetest1文件夹中执行以下命令
sudo npm install express-session
sudo npm install connect-mongo
##修改app.js
然后在app.js中添加
var app = express();
//在上一句之后添加这句,顺序是有影响的
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
在app.js中添加
app.use(session({
secret: 'zhanfang',
store: new MongoStore({
db: 'nodetest1'
})
}));
执行./bin/www即可,在数据库中可以看到对应的session
TIPS:
路由
、向ejs
模板传参##app.js中添加中间层
var routes = require(‘./routes/index’);
app.use(‘/‘, routes);
app.use(‘/login’, routes);
app.use(‘/logout’, routes);
##express 4路由
在index.js中添加
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
var user={
username:'admin',
password:'admin'
}
//渲染模板,访问127.0.0.1:3000/时对应index.ejs模板
//title和user分别表示传入index.ejs模板的key,后面为对应的value
res.render('index', { title: 'Express' ,user : user});
});
router.get('/login',function(req,res) {
res.render('login', { title: 'login' });
});
//登陆验证操作
router.post('/doLogin',function(req,res) {
var user={
username:'admin',
password:'admin'
}
if(req.body.username===user.username && req.body.password===user.password){
res.redirect('/');
}
res.redirect('/login');
});
router.get('/logout',function(req,res) {
res.render('logout', { title: 'logout' });
});
module.exports = router;
##view/index.ejs
<% include header.html %>
完成以上步骤启动./bin/www即可完成登陆传参功能
##问题描述
Determine whether an integer is a palindrome. Do this without extra space.
click to show spoilers.
Some hints:
Could negative integers be palindromes? (ie, -1)If you are thinking of converting the integer to string, note the restriction of using extra space.
You could also try reversing an integer. However, if you have solved the problem “Reverse Integer”, you know that the reversed integer might overflow. How would you handle such case?
There is a more generic way of solving this problem.
该问题即对回文数字进行判断,上面提示中要求不能开辟新的空间,所以不能将其转换为字符串
进行字符串的回文判断,并且负数
也不是回文数字
##JAVA代码
/
代码很巧妙,主要是判断前一半和后一半是否相同
/
public class Solution {
public boolean isPalindrome(int x) {
//假设输入为1231则,rev为13
int rev = 0;
if(x == 0) return true;
if(x < 0 || x % 10 == 0) return false;
while ( x > rev ){
rev = rev * 10 + x % 10;
x = x / 10;
}
return (x == rev || x == rev / 10);
}
}
#问题描述
Implement atoi to convert a string to an integer.
Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.
Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.
spoilers alert… click to show requirements for atoi.
Requirements for atoi:
The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.
If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.
If no valid conversion could be performed, a zero value is returned. If the correct value is out of the range of representable values, INT_MAX (2147483647) or INT_MIN (-2147483648) is returned.
##问题分析
该问题意思很明白就是要将字符串转换为数字
其中关键点是对特殊的情况进行讨论
##JAVA代码
//3 key things you need to know:
//1. first non-whitespace character must be sign or digit
//2. two consecutive signs is invalid format (“++82” invalid)
//3. only whitespaces and digits are allowed after the sign ( “- 082jk s” valid)
public class Solution {
public static int atoi(String str) {
if(str.length() == 0) {
return 0;
}
int num = 0;
int index = 0;
int sign = 1;
int signCount = 0;
//skip all leading whitespaces
while(str.charAt(index) == ‘ ‘ && index < str.length()) {
index++;
}
if(str.charAt(index) == ‘+’) {
signCount++;
index++;
}
if(str.charAt(index) == ‘-‘) {
signCount++;
sign = -1;
index++;
}
//two consecutive signs is invalid
if(signCount >= 2) {
return 0;
}
while(index < str.length()) {
char ch = str.charAt(index);
if(ch < ‘0’ || ch > ‘9’) break;
//输入字符串太大情况
if(Integer.MAX_VALUE/10 < num || Integer.MAX_VALUE/10 == num && Integer.MAX_VALUE%10 < (ch - ‘0’)) {
return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
num = num 10 + (ch - ‘0’);
index++;
}
return sign num;
}
}
##问题描述
Write a program to find the node at which the intersection of two singly linked lists begins.
For example, the following two linked lists:
A: a1 → a2
↘
c1 → c2 → c3
↗
B: b1 → b2 → b3
begin to intersect at node c1.
即要寻找相交节点,并且要求时间复杂度为n,空间复杂度为1
##问题分析
该问题解决方法非常巧妙
利用list中的val值,计算listB中的所有节点val的和countB
然后计算listA中val++和的值,最后再次计算listB中val的值得和newCountB
比较一下countB和newCountB,如果两者相同,说明listB没有受到listA的影响,则listA和listB无交点
否则则说明有交点,并且交点位置为lengthB - newCountB-countB
Tip:这个方法太牛逼了(不是我想到的)
##C++代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *tmp = headB;
int countB = 0,lengthB = 0;
while(tmp != NULL){
countB += tmp->val;
tmp = tmp->next;
lengthB++;
}
tmp = headA;
while(tmp != NULL){
tmp->val++;
tmp = tmp->next;
}
tmp = headB;
int newCountB = 0;
while(tmp != NULL){
newCountB += tmp->val;
tmp = tmp->next;
}
//默认不允许修改list的结构,所以要将其还原
tmp = headA;
while (tmp!=NULL)
{
tmp->val--;
tmp = tmp->next;
}
if(newCountB == countB) return NULL;
//应该写成if else结构的,但是实际这两种写法的效果是一样的
tmp = headB;
for(int i = 0;i < lengthB-(newCountB-countB);i++){
tmp = tmp->next;
}
return tmp;
}
};
# -*- coding: utf-8 -*-
__author__ = 'zhan'
#该程序为测试豆瓣FM的程序
import json
import urllib
import urllib2
import requests
import requests.exceptions
import traceback
DOUBAN_CHANNEL_UUID_FORMAT = 'douban-%d' # % (channel_id)
DOUBAN_MUSIC_UUID_FORMAT = 'douban-%d-%d' # % (aid, sid)
_user_id = None
_token = None
_expire = None
#登陆获取Token 和 Expire
def login():
payload = {'app_name': 'radio_desktop_win',
'version' : '100',
'email': '***',
'password' : "***"}
try:
r = requests.post("http://www.douban.com/j/app/login", data=payload)
except requests.exceptions.ConnectionError:
return False
except requests.exceptions.Timeout:
return False
r = json.loads(r.text)
if r['r'] != 0:
print 'spider.douban.login: failed. r=', r
return False
global _user_id, _token, _expire
_user_id = r['user_id']
_token = r['token']
_expire = r['expire']
return True
#获取频道列表
def update_channel_list():
r = requests.get("http://www.douban.com/j/app/radio/channels")
r = json.loads(r.text)
channel_list = []
assert 'channels' in r
for channel in r['channels']:
cid = int(channel['channel_id'])
uuid = DOUBAN_CHANNEL_UUID_FORMAT % (cid)
if cid != 0:
# not private list and not in db
new_channel = channel['name']
channel_list.append(new_channel)
return channel_list
def update_channel_once(channel, max_num=10):
'''update music in channel. max is the max number it will update
return updated music
please login before this function'''
global _user_id, _token, _expire
# TODO
# maybe need a better method to assert and get cid
payload = {'app_name': 'radio_desktop_win',
'version': '100',
'user_id': _user_id,
'expire': _expire,
'token': _token,
'channel': channel,
'type': 'n'}
try:
print 'getting list'
r = requests.get("http://www.douban.com/j/app/radio/people", params=payload, timeout=5)
except requests.exceptions.ConnectionError:
traceback.print_exc()
return []
except requests.exceptions.Timeout:
traceback.print_exc()
return []
r = json.loads(r.text)
assert r['r'] == 0
update_music = []
#channel_music_list = channel.music_list
for song in r['song']:
try:
uuid = DOUBAN_MUSIC_UUID_FORMAT % (int(song['aid']), int(song['sid']))
except:
# ads
continue
print uuid
music = None
try:
print 'getting song'
cover_fd = requests.get(song['picture'], stream=True, timeout=5).raw
audio_fd = requests.get(song['url'], stream=True, timeout=5).raw
except requests.exceptions.ConnectionError:
traceback.print_exc()
continue
except requests.exceptions.Timeout:
traceback.print_exc()
continue
print(song['title'], song['artist'], song['albumtitle'],
song['company'], song['public_time'], song['kbps'],
cover_fd, audio_fd, uuid)
return update_music
login()
channels = update_channel_list();
for channel in channels:
print channel
print '--------------------------'
musics = update_channel_once(1,10)
##问题描述
Compare two version numbers version1 and version1.
If version1 > version2 return 1, if version1 < version2 return -1, otherwise return 0.
You may assume that the version strings are non-empty and contain only digits and the . character.
The . character does not represent a decimal point and is used to separate number sequences.
For instance, 2.5 is not “two and a half” or “half way to version three”, it is the fifth second-level revision of the second first-level revision.
Here is an example of version numbers ordering:
0.1 < 1.1 < 1.2 < 13.37
##问题分析
该问题很简单,即比较版本号的大小,主要复杂的是多种情况的比较
例如 1<1.1 01<1.1 这些特殊情况的处理是重点
##JAVA代码
public class Solution {
public int compareVersion(String version1, String version2) {
String[] num1 = version1.split(“\.”);
String[] num2 = version2.split(“\.”);
int i = 0,j = 0;
for(;i <= num1.length - 1 && j <= num2.length - 1;i++,j++){
if (Integer.parseInt(num1[i]) > Integer.parseInt(num2[j])) return 1;
else if (Integer.parseInt(num1[i]) < Integer.parseInt(num2[j])) return -1;
}
//当version1=1;version2=1.1时,return-1
//而此时num1.length=1,num2.length=2
for(;i<num1.length;i++){
if(Integer.parseInt(num1[i]) != 0) return 1;
}
for(;j<num2.length;j++){
if(Integer.parseInt(num2[j]) != 0) return -1;
}
return 0;
}
}
##代码分析
假设输入是1和1.1
分析上述代码
运行到第二个for循环时 i=1
j=1
,此时num1.length=1,num2.length=2
第二个for循环不会执行
第三个fo循环执行
TIPS:这个问题与 http://zhanfang.github.io/2015/01/29/leetcode13/ 这个问题相对应
##问题描述
Given a positive integer, return its corresponding column title as appear in an Excel sheet.
For example:
1 -> A
2 -> B
3 -> C
...
26 -> Z
27 -> AA
28 -> AB
该问题意思很清楚,就是要将数字转化问大写英文字符串
下面直接贴出代码,代码很容易懂,不做过多描述
##JAVA代码
public class Solution {
public String convertToTitle(int n) {
int x = n/26;
int y = n%26;
if(n<=0){
return “”;
}
if(x == 0){
return ((char)(y+64)) + “”;
}
if(y == 0){
return convertToTitle(x-1) + “Z”;
}
return convertToTitle(x) + convertToTitle(y);
}
}
##问题描述
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.
即寻找出现次数最多的数值
##C++代码
class Solution {
public:
int majorityElement(vector
int vote = num[0];
int count = 1;
int size = num.size();
//vote from the second number
for( int i = 1; i < size; i++ )
{
if( count == 0 ) { vote = num[i]; count++; }
else if( vote == num[i] ) count++;
else count–;
}
return vote;
}
};
##算法分析
转载http://javascript.ruanyifeng.com/nodejs/express.html
Express是目前最流行的基于Node.js的Web开发框架,提供各种模块,可以快速地搭建一个具有完整功能的网站。
Express的上手非常简单,首先新建一个项目目录,假定叫做hello-world。
$ mkdir hello-world
进入该目录,新建一个package.json文件,内容如下。
{
"name": "hello-world",
"description": "hello world test app",
"version": "0.0.1",
"private": true,
"dependencies": {
"express": "4.x"
}
}
上面代码定义了项目的名称、描述、版本等,并且指定需要4.0版本以上的Express。
然后,就可以安装了。
$ npm install
安装了Express及其依赖的模块以后,在项目根目录下,新建一个启动文件,假定叫做index.js。
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.listen(8080);
你也可以在index.js之中,生成动态网页。
// index.js
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello world!');
});
app.listen(3000);
然后,在命令行下运行下面的命令,就可以在浏览器中访问项目网站了。
node index
默认情况下,网站运行在本机的3000端口,网页显示Hello World。
index.js中的app.get用于指定不同的访问路径所对应的回调函数,这叫做 “路由”(routing)。上面代码只指定了根目录的回调函数,因此只有一个路由记录,实际应用中,可能有多个路由记录。这时,最好就把路由放到一个单独的文件中,比如新建一个routes子目录。
// routes/index.js
module.exports = function (app) {
app.get('/', function (req, res) {
res.send('Hello world');
});
};
然后,原来的index.js就变成下面这样。
// index.js
var express = require('express');
var app = express();
var routes = require('./routes')(app);
app.listen(3000);
###底层:http模块
Express框架建立在node.js内置的http模块上。 http模块生成服务器的原始代码如下。
var http = require("http");
var app = http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.end("Hello world!");
});
app.listen(3000, "localhost");
上面代码的关键是http模块的createServer方法,表示生成一个HTTP服务器实例。该方法接受一个回调函数,该回调函数的参数,分别为代表HTTP请求和HTTP回应的request对象和response对象。
###对http模块的再包装
Express框架的核心是对http模块的再包装。上面的代码用Express改写如下。
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello world!');
});
app.listen(3000);
var express = require("express");
var http = require("http");
var app = express();
app.use(function(request, response) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Hello world!\n");
});
http.createServer(app).listen(1337);
比较两段代码,可以看到它们非常接近,唯一的差别是createServer方法的参数,从一个回调函数变成了一个Express对象的实例。而这个实例使用了use方法,加载了与上一段代码相同的回调函数。
Express框架等于在http模块之上,加了一个中间层,而use方法则相当于调用中间件。
###什么是中间件
简单说,中间件(middleware)就是处理HTTP请求的函数,用来完成各种特定的任务,比如检查用户是否登录、分析数据、以及其他在需要最终将数据发送给用户之前完成的任务。它最大的特点就是,一个中间件处理完,再传递给下一个中间件。
node.js的内置模块http的createServer方法,可以生成一个服务器实例,该实例允许在运行过程中,调用一系列函数(也就是中间件)。当一个HTTP请求进入服务器,服务器实例会调用第一个中间件,完成后根据设置,决定是否再调用下一个中间件。中间件内部可以使用服务器实例的response对象(ServerResponse,即回调函数的第二个参数),以及一个next回调函数(即第三个参数)。每个中间件都可以对HTTP请求(request对象)做出回应,并且决定是否调用next方法,将request对象再传给下一个中间件。
一个不进行任何操作、只传递request对象的中间件,大概是下面这样:
function uselessMiddleware(req, res, next) {
next();
}
上面代码的next为中间件的回调函数。如果它带有参数,则代表抛出一个错误,参数为错误文本。
function uselessMiddleware(req, res, next) {
next('出错了!');
}
抛出错误以后,后面的中间件将不再执行,直到发现一个错误处理函数为止。
###use方法
use是express调用中间件的方法,它返回一个函数。下面是一个连续调用两个中间件的例子。
var express = require("express");
var http = require("http");
var app = express();
app.use(function(request, response, next) {
console.log("In comes a " + request.method + " to " + request.url);
next();
});
app.use(function(request, response) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Hello world!\n");
});
http.createServer(app).listen(1337);
上面代码先调用第一个中间件,在控制台输出一行信息,然后通过next方法,调用第二个中间件,输出HTTP回应。由于第二个中间件没有调用next方法,所以不再request对象就不再向后传递了。
使用use方法,可以根据请求的网址,返回不同的网页内容。
var express = require("express");
var http = require("http");
var app = express();
app.use(function(request, response, next) {
if (request.url == "/") {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Welcome to the homepage!\n");
} else {
next();
}
});
app.use(function(request, response, next) {
if (request.url == "/about") {
response.writeHead(200, { "Content-Type": "text/plain" });
} else {
next();
}
});
app.use(function(request, response) {
response.writeHead(404, { "Content-Type": "text/plain" });
response.end("404 error!\n");
});
http.createServer(app).listen(1337);
上面代码通过request.url属性,判断请求的网址,从而返回不同的内容。
除了在回调函数内部,判断请求的网址,Express也允许将请求的网址写在use方法的第一个参数。
app.use(‘/‘, someMiddleware);
上面代码表示,只对根目录的请求,调用某个中间件。
因此,上面的代码可以写成下面的样子。
var express = require("express");
var http = require("http");
var app = express();
app.use("/", function(request, response, next) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Welcome to the homepage!\n");
});
app.use("/about", function(request, response, next) {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Welcome to the about page!\n");
});
app.use(function(request, response) {
response.writeHead(404, { "Content-Type": "text/plain" });
response.end("404 error!\n");
});
http.createServer(app).listen(1337);
###all方法和HTTP动词方法
针对不同的请求,Express提供了use方法的一些别名。比如,上面代码也可以用别名的形式来写。
var express = require("express");
var http = require("http");
var app = express();
app.all("*", function(request, response, next) {
response.writeHead(200, { "Content-Type": "text/plain" });
next();
});
app.get("/", function(request, response) {
response.end("Welcome to the homepage!");
});
app.get("/about", function(request, response) {
response.end("Welcome to the about page!");
});
app.get("*", function(request, response) {
response.end("404!");
});
http.createServer(app).listen(1337);
上面代码的all方法表示,所有请求都必须通过该中间件,参数中的“*”表示对所有路径有效。get方法则是只有GET动词的HTTP请求通过该中间件,它的第一个参数是请求的路径。由于get方法的回调函数没有调用next方法,所以只要有一个中间件被调用了,后面的中间件就不会再被调用了。
除了get方法以外,Express还提供post、put、delete方法,即HTTP动词都是Express的方法。
这些方法的第一个参数,都是请求的路径。除了绝对匹配以外,Express允许模式匹配。
app.get("/hello/:who", function(req, res) {
res.end("Hello, " + req.params.who + ".");
});
上面代码将匹配“/hello/alice”网址,网址中的alice将被捕获,作为req.params.who属性的值。需要注意的是,捕获后需要对网址进行检查,过滤不安全字符,上面的写法只是为了演示,生产中不应这样直接使用用户提供的值。
如果在模式参数后面加上问号,表示该参数可选。
app.get('/hello/:who?',function(req,res) {
if(req.params.id) {
res.end("Hello, " + req.params.who + ".");
}
else {
res.send("Hello, Guest.");
}
});
下面是一些更复杂的模式匹配的例子。
app.get('/forum/:fid/thread/:tid', middleware)
// 匹配/commits/71dbb9c
// 或/commits/71dbb9c..4c084f9这样的git格式的网址
app.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function(req, res){
var from = req.params[0];
var to = req.params[1] || 'HEAD';
res.send('commit range ' + from + '..' + to);
});
###set方法
set方法用于指定变量的值。
app.set("views", __dirname + "/views");
app.set("view engine", "jade");
上面代码使用set方法,为系统变量“views”和“view engine”指定值。
###response对象
####(1)response.redirect方法
response.redirect方法允许网址的重定向。
response.redirect("/hello/anime");
response.redirect("http://www.example.com");
response.redirect(301, "http://www.example.com");
####(2)response.sendFile方法
response.sendFile方法用于发送文件。
response.sendFile("/path/to/anime.mp4");
####(3)response.render方法
response.render方法用于渲染网页模板。
app.get("/", function(request, response) {
response.render("index", { message: "Hello World" });
});
上面代码使用render方法,将message变量传入index模板,渲染成HTML网页。
###requst对象
####(1)request.ip
request.ip属性用于获得HTTP请求的IP地址。
####(2)request.files
request.files用于获取上传的文件。
##项目开发实例
###编写启动脚本
上一节使用express命令自动建立项目,也可以不使用这个命令,手动新建所有文件。
先建立一个项目目录(假定这个目录叫做demo)。进入该目录,新建一个package.json文件,写入项目的配置信息。
{
"name": "demo",
"description": "My First Express App",
"version": "0.0.1",
"dependencies": {
"express": "3.x"
}
}
在项目目录中,新建文件app.js。项目的代码就放在这个文件里面。
var express = require('express');
var app = express();
上面代码首先加载express模块,赋给变量express。然后,生成express实例,赋给变量app。
接着,设定express实例的参数。
// 设定port变量,意为访问端口
app.set('port', process.env.PORT || 3000);
// 设定views变量,意为视图存放的目录
app.set('views', path.join(__dirname, 'views'));
// 设定view engine变量,意为网页模板引擎
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
// 设定静态文件目录,比如本地文件
// 目录为demo/public/images,访问
// 网址则显示为http://localhost:3000/images
app.use(express.static(path.join(__dirname, 'public')));
上面代码中的set方法用于设定内部变量,use方法用于调用express的中间件。
最后,调用实例方法listen,让其监听事先设定的端口(3000)。
app.listen(app.get('port'));
这时,运行下面的命令,就可以在浏览器访问http://127.0.0.1:3000。
node app.js
网页提示“Cannot GET /”,表示没有为网站的根路径指定可以显示的内容。所以,下一步就是配置路由。
###配置路由
所谓“路由”,就是指为不同的访问路径,指定不同的处理方法。
####(1)指定根路径
在app.js之中,先指定根路径的处理方法。
app.get('/', function(req, res) {
res.send('Hello World');
});
上面代码的get方法,表示处理客户端发出的GET请求。相应的,还有app.post、app.put、app.del(delete是JavaScript保留字,所以改叫del)方法。
get方法的第一个参数是访问路径,正斜杠(/)就代表根路径;第二个参数是回调函数,它的req参数表示客户端发来的HTTP请求,res参数代表发向客户端的HTTP回应,这两个参数都是对象。在回调函数内部,使用HTTP回应的send方法,表示向浏览器发送一个字符串。然后,运行下面的命令。
node app.js
此时,在浏览器中访问http://127.0.0.1:3000,网页就会显示“Hello World”。
如果需要指定HTTP头信息,回调函数就必须换一种写法,要使用setHeader方法与end方法。
app.get('/', function(req, res){
var body = 'Hello World';
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Content-Length', body.length);
res.end(body);
});
####(2)指定特定路径
上面是处理根目录的情况,下面再举一个例子。假定用户访问/api路径,希望返回一个JSON字符串。这时,get可以这样写。
app.get('/api', function(request, response) {
response.send({name:"张三",age:40});
});
上面代码表示,除了发送字符串,send方法还可以直接发送对象。重新启动node以后,再访问路径/api,浏览器就会显示一个JSON对象。
{
"name": "张三",
"age": 40
}
我们也可以把app.get的回调函数,封装成模块。先在routes目录下面建立一个api.js文件。
// routes/api.js
exports.index = function (req, res){
res.json(200, {name:"张三",age:40});
}
然后,在app.js中加载这个模块。
// app.js
var api = require('./routes/api');
app.get('/api', api.index);
现在访问时,就会显示与上一次同样的结果。
如果只向浏览器发送简单的文本信息,上面的方法已经够用;但是如果要向浏览器发送复杂的内容,还是应该使用网页模板。
###静态网页模板
在项目目录之中,建立一个子目录views,用于存放网页模板。
假定这个项目有三个路径:根路径(/)、自我介绍(/about)和文章(/article)。那么,app.js可以这样写:
var express = require('express');
var app = express();
app.get('/', function(req, res) {
res.sendfile('./views/index.html');
});
app.get('/about', function(req, res) {
res.sendfile('./views/about.html');
});
app.get('/article', function(req, res) {
res.sendfile('./views/article.html');
});
app.listen(3000);
上面代码表示,三个路径分别对应views目录中的三个模板:index.html、about.html和article.html。另外,向服务器发送信息的方法,从send变成了sendfile,后者专门用于发送文件。
假定index.html的内容如下:
<html>
<head>
<title>首页</title>
</head>
<body>
<h1>Express Demo</h1>
<footer>
<p>
<a href="/">首页</a> - <a href="/about">自我介绍</a> - <a href="/article">文章</a>
</p>
</footer>
</body>
</html>
上面代码是一个静态网页。如果想要展示动态内容,就必须使用动态网页模板。
##动态网页模板
网站真正的魅力在于动态网页,下面我们来看看,如何制作一个动态网页的网站。
###安装模板引擎
Express支持多种模板引擎,这里采用Handlebars模板引擎的服务器端版本hbs模板引擎。
先安装hbs。
npm install hbs --save-dev
上面代码将hbs模块,安装在项目目录的子目录node_modules之中。save-dev参数表示,将依赖关系写入package.json文件。安装以后的package.json文件变成下面这样:
// package.json文件
{
"name": "demo",
"description": "My First Express App",
"version": "0.0.1",
"dependencies": {
"express": "3.x"
},
"devDependencies": {
"hbs": "~2.3.1"
}
}
安装模板引擎之后,就要改写app.js。
// app.js文件
var express = require('express');
var app = express();
// 加载hbs模块
var hbs = require('hbs');
// 指定模板文件的后缀名为html
app.set('view engine', 'html');
// 运行hbs模块
app.engine('html', hbs.__express);
app.get('/', function (req, res){
res.render('index');
});
app.get('/about', function(req, res) {
res.render('about');
});
app.get('/article', function(req, res) {
res.render('article');
});
上面代码改用render方法,对网页模板进行渲染。render方法的参数就是模板的文件名,默认放在子目录views之中,后缀名已经在前面指定为html,这里可以省略。所以,res.render(‘index’) 就是指,把子目录views下面的index.html文件,交给模板引擎hbs渲染。
###新建数据脚本
渲染是指将数据代入模板的过程。实际运用中,数据都是保存在数据库之中的,这里为了简化问题,假定数据保存在一个脚本文件中。
在项目目录中,新建一个文件blog.js,用于存放数据。blog.js的写法符合CommonJS规范,使得它可以被require语句加载。
// blog.js文件
var entries = [
{"id":1, "title":"第一篇", "body":"正文", "published":"6/2/2013"},
{"id":2, "title":"第二篇", "body":"正文", "published":"6/3/2013"},
{"id":3, "title":"第三篇", "body":"正文", "published":"6/4/2013"},
{"id":4, "title":"第四篇", "body":"正文", "published":"6/5/2013"},
{"id":5, "title":"第五篇", "body":"正文", "published":"6/10/2013"},
{"id":6, "title":"第六篇", "body":"正文", "published":"6/12/2013"}
];
exports.getBlogEntries = function (){
return entries;
}
exports.getBlogEntry = function (id){
for(var i=0; i < entries.length; i++){
if(entries[i].id == id) return entries[i];
}
}
##新建网页模板
接着,新建模板文件index.html。
###渲染模板
最后,改写app.js文件。
// app.js文件
var express = require('express');
var app = express();
var hbs = require('hbs');
// 加载数据模块
var blogEngine = require('./blog');
app.set('view engine', 'html');
app.engine('html', hbs.__express);
app.use(express.bodyParser());
app.get('/', function(req, res) {
res.render('index',{title:"最近文章", entries:blogEngine.getBlogEntries()});
});
app.get('/about', function(req, res) {
res.render('about', {title:"自我介绍"});
});
app.get('/article/:id', function(req, res) {
var entry = blogEngine.getBlogEntry(req.params.id);
res.render('article',{title:entry.title, blog:entry});
});
app.listen(3000);
上面代码中的render
方法,现在加入了第二个参数,表示模板变量绑定的数据。
现在重启node服务器,然后访问http://127.0.0.1:3000。
node app.js
可以看得,模板已经使用加载的数据渲染成功了。
###指定静态文件目录
模板文件默认存放在views子目录。这时,如果要在网页中加载静态文件(比如样式表、图片等),就需要另外指定一个存放静态文件的目录。
app.use(express.static('public'));
上面代码在文件app.js之中,指定静态文件存放的目录是public。于是,当浏览器发出非HTML文件请求时,服务器端就到public目录寻找这个文件。比如,浏览器发出如下的样式表请求:
<link href="/bootstrap/css/bootstrap.css" rel="stylesheet">
服务器端就到public/bootstrap/css/目录中寻找bootstrap.css文件。
##ExpressJS 4.0的Router用法
Express 4.0的Router用法,做了大幅改变,增加了很多新的功能。Router成了一个单独的组件,好像小型的express应用程序一样,有自己的use、get、param和route方法。
###基本用法
Express 4.0的router对象,需要单独新建。然后,使用该对象的HTTP动词方法,为不同的访问路径,指定回调函数;最后,挂载到某个路径
var router = express.Router();
router.get('/', function(req, res) {
res.send('首页');
});
router.get('/about', function(req, res) {
res.send('关于');
});
app.use('/', router);
上面代码先定义了两个访问路径,然后将它们挂载到根目录。如果最后一行改为app.use(‘/app’, router),则相当于/app和/app/about这两个路径,指定了回调函数。
这种挂载路径和router对象分离的做法,为程序带来了更大的灵活性,既可以定义多个router对象,也可以为将同一个router对象挂载到多个路径。
###router.route方法
router实例对象的route方法,可以接受访问路径作为参数。
var router = express.Router();
router.route('/api')
.post(function(req, res) {
// ...
})
.get(function(req, res) {
Bear.find(function(err, bears) {
if (err) res.send(err);
res.json(bears);
});
});
app.use('/', router);
###router中间件
use方法为router对象指定中间件,即在数据正式发给用户之前,对数据进行处理。下面就是一个中间件的例子。
router.use(function(req, res, next) {
console.log(req.method, req.url);
next();
});
上面代码中,回调函数的next参数,表示接受其他中间件的调用。函数体中的next(),表示将数据传递给下一个中间件。
注意,中间件的放置顺序很重要,等同于执行顺序。而且,中间件必须放在HTTP动词方法之前,否则不会执行。
###对路径参数的处理
router对象的param方法用于路径参数的处理,可以
router.param('name', function(req, res, next, name) {
// 对name进行验证或其他处理……
console.log(name);
req.name = name;
next();
});
router.get('/hello/:name', function(req, res) {
res.send('hello ' + req.name + '!');
});
上面代码中,get方法为访问路径指定了name参数,param方法则是对name参数进行处理。注意,param方法必须放在HTTP动词方法之前。
###app.route
假定app是Express的实例对象,Express 4.0为该对象提供了一个route属性。app.route实际上是express.Router()的缩写形式,除了直接挂载到根路径。因此,对同一个路径指定get和post方法的回调函数,可以写成链式形式。
app.route('/login')
.get(function(req, res) {
res.send('this is the login form');
})
.post(function(req, res) {
console.log('processing');
res.send('processing the login form!');
});
上面代码的这种写法,显然非常简洁清晰。
##参考链接
##问题描述
Given a list of non negative integers, arrange them such that they form the largest number.
For example, given [3, 30, 34, 5, 9]
, the largest formed number is 9534330.
Note: The result may be very large, so you need to return a string instead of an integer.
##问题分析
利用JAVA的一些小技巧,重新构造一个操作符,来比较字符串的大小
String的 compareTo 其实就是依次比较两个字符串ASC码。如果两个字符的ASC码相等则继续后续比较,否则直接返回两个ASC的差值。如果两个字符串完全一样,则返回0。来看一下代码
compareTo进行简单 字符串的排序
“abcd”.compareTo(“adef”)== -2
“abc”.compareTo(“abcdef”)== -3
“abc”.compareTo(“abc”) == 0
以下为例子
“930”.compareTo(“309”) = 6 > 0
Arrays.sort():将数组从小到大排列
重新构造操作符,使得从大到小排列数组
##JAVA代码
public class Solution{
class StringComparator implements Comparator
public int compare(String s1,String s2){
String s1s2 = s1 + s2;
String s2s1 = s2 + s1;
//“930”>”309” 返回-1
if(s1s2.compareTo(s2s1) > 0) return -1;
else if (s2s1.compareTo(s1s2) >0) return 1;
else if (s1.length() <= s2.length() ) return -1;
else return 1;
}
}
public String largestNumber(int[] num){
String[] nums = new String[num.length];
for(int i = 0; i < num.length; i++){
nums[i] = String.valueOf(num[i]);
}
Comparator<String> comparator = new StringComparator();
Arrays.sort(nums,comparator);
StringBuilder str = new StringBuilder();
for(String n:nums){
str.append(n);
}
return str.charAt(0)=='0'?"0":str.toString();
}
}
为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。
模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。
##创建模块
在 Node.js 中,创建一个模块非常简单,如下我们创建一个 ‘main.js’ 文件,代码如下:
var hello = require('./hello');
hello.world();
以上实例中,代码 require(‘./hello’) 引入了当前目录下的hello.js文件(./ 为当前目录,node.js默认后缀为js)。
Node.js 提供了exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。
接下来我们就来创建hello.js文件,代码如下:
exports.world = function() {
console.log('Hello World');
}
在以上示例中,hello.js 通过 exports 对象把 world 作为模块的访 问接口,在 main.js 中通过 require(‘./hello’) 加载这个模块,然后就可以直接访 问main.js 中 exports 对象的成员函数了。
有时候我们只是想把一个对象封装到模块中,格式如下:
module.exports = function() {
// ...
}
例如:
//hello.js
function Hello() {
varname;
this.setName = function(thyName) {
name = thyName;
};
this.sayHello = function() {
console.log('Hello ' + name);
};
};
module.exports = Hello;
这样就可以直接获得这个对象了:
//main.js
var Hello = require('./hello');
hello = new Hello();
hello.setName('BYVoid');
hello.sayHello();
模块接口的唯一变化是使用 module.exports = Hello 代替了exports.world = function(){}。 在外部引用该模块时,其接口对象就是要输出的 Hello 对象本身,而不是原先的 exports