如何学习nodejs express+express

Nodejs学习笔记(五)--- Express安装入门与模版引擎ejs_JavaScript_第七城市
Nodejs学习笔记(五)--- Express安装入门与模版引擎ejs
目录前言Express简介和安装运行第一个基于express框架的Web模版引擎 ejsexpress项目结构express项目分析app.set(name,value)app.use([path], function)app.get(name)路由文件index.js前言  前面也学习了一些Node.js的基本入门知道,现在开始进入Web开发的部分;  Node.js提供了http模块,这个模块中提供了一些底层接口,可以直接使用,但是直接开发网站那还是太累了,所以http模块也不单讲了,可以去看官方API:http://nodejs.org/api/http.html  下面我们直接从Express框架着手去进行Web开发,它实现好了更高层的接口,让Web开发更简单快捷...简介和安装  Express是一个轻量级、简洁、易用的Node.js Web MVC开发框架,它基于Node.js原有进行了很多Web开发所需的功能封装...  /  https://www.npmjs.org/package/express    安装npm install -g express-generator  /visionmedia/express#quick-start  -g:表示全局安装    &  到此express就在全局环境中安装成功!   PS:用npm安装有时可能进度不动,多试几次!运行第一个基于express框架的Web&&  1.创建一个testWebAppexpress testWebApp  &  2.安装依赖项  注意上一步安装成功后的提示,需要cd到网站目录,并执行npm install命令安装项目依赖项(可以在项目的package.json文件的dependencies节点下看到需要哪些依赖)  3.修改app.js文件并运行  在testWebApp根目录下找到app.js并增加端口监听,在sublime中Ctrl+B运行app.listen(8100,function(){
console.log("Server Start!");});    4.通过浏览器访问,看看效果  &  到此成功的运行起来基本express框架的Web!&  相关提示:  1.在sublime中运行过后,如果想要关闭,去任务管理器中结束node.exe进程  2.不在sublime中运行,可以在cmd中执行node app,关闭使用快捷键Ctrl+C模版引擎 ejs  在上面创建的testWebApp中express默认使用的模版擎为jade,个人觉得jade虽然简洁但不直观,所以选择了更易上手的ejs。  ejs:Embedded JavaScript  /visionmedia/ejs  1.创建一个express + ejs的项目express -e testEjsWebAppcd&testEjsWebAppnpm install  express参数
Usage: express [options] [dir]
-h, --help
output usage information
-V, --version
output the version number
add ejs engine support (defaults to jade)
-H, --hogan
add hogan.js engine support
-c, --css &engine&
add stylesheet &engine& support (less|stylus|compass) (defaults to plain css)
-f, --force
force on non-empty directory    2.创建成功后,打开app.js,添加8100端口监听  3.打开routes文件夹下index.js,并修改代码如下    var express = require('express');var router = express.Router();/* GET home page. */router.get('/', function(req, res) {
res.render('index', { title: '&h1&Express&/h1&'
,users:[{username: 'Wilson'},
{username: 'Wilson Zhong'},
{username: 'Zhong Wei'}]
});});module.exports =修改后的index.js 源码  4.打开views文件夹下index.ejs,并修改代码如下  &!DOCTYPE html&&html&
&link rel='stylesheet' href='/stylesheets/style.css' /&
&%= title %&
&%- title %&
&% users.forEach(function(user){ %&
&h6&&%= user.username %&&/h6&
&/body&&/html&修改后的index.ejs 源码  5.运行页面,查看结果  &  在这里,我们还没有讲express的一些东西,所以大家先不要管太多细节部分,只要知道上面示例中当通过http://localhost:8100访问时,  会转到index.js,而index.js而index.ejs传递了title和users对象作为参数。&  这里重点看看index.ejs  ejs结尾的文件就是模版文件,可以看到在文件中我们用了三种标签方式(这种标签方式有过其它web开发经验的应该很好看懂)  1.&%= %&  这个标签在接到收到title: '&h1&Express&/h1&'时,从显示效果来看,他直接输出HTML标签到页面上,输出的是转义后的变量值  2.&%- %&&    而这个标签,从显示效果上看,他没有直接输出HTML代码到页面上,输出的是没有转义后的变量值  3.&% %&  而这个标签,从显示上看,他循环了出来参数中的值,标签中是javascript逻辑代码,注意括号的开闭合&  在这里,简单认识一下ejs,下面开始看看express的结构!&express项目结构  上面新建了一个叫testEjsWebApp的项目,模版引擎使用的ejs,先看看项目的结构    1.node_modules文件夹&  这文件夹就是在创建完项目后,cd到项目目录执行npm install后生成的文件夹,下载了项目需要的依赖项  2.package.json文件  此文件是项目的配置文件(可定义应用程序名,版本,依赖项等等)  node_modules文件夹下的依赖项是从哪里知道的呢?原因就是项目根目录下的这个package.json文件,执行npm install时会去找此文件中的dependencies,并安装指定的依赖项  3.public文件夹(包含images、javascripts、stylesheets)  这个文件夹做过Web开发的应该一看就知道,为了存放图片、脚本、样式等文件的  4.routes文件夹  用于存放路由文件,  5.views文件夹  用于存放模版文件express项目分析  先从app.js看起  1.app.set(name,value)  把名字为name的项的值设为value,用于设置参数  app.set('views', path.join(__dirname, 'views')); & 设置了模版文件夹的路径;主要清楚__dirname的意思就可以了,它是node.js中的全局变量,表示取当前执行文件的路径  app.set('view engine', 'ejs'); &设置使用的模版引擎,我们使用的ejs  2.app.use([path], function)&  & 用这个方法来使用中间件,因为express依赖于connect,有大量的中间件,可以通过app.use来使用;path参数可以不填,默认为'/' &(项目中用到的就不分别解释了,用到的时候自已查一API的中间件部分)  app.use(express.static(path.join(__dirname, 'public'))); 这一句中可能要注意一下,express.static( )是处理静态请求的,设置了public文件,public下所有文件都会以静态资料文件形式返回(如样式、脚本、图片素材等文件)var routes = require('./routes/index');var users = require('./routes/users');app.use('/', routes);app.use('/users', users);  上面代码表示当用户使用/访问时,调用routes,即routes目录下的index.js文件,其中.js后缀省略,用/users访问时,调用routes目录下users.js文件  这就是为什么,我们示例中用http://localhost:8100/访问是,修改的index.js里的文件代码可以执行(当然index.js文件中也要写对应的代码,才能是我们最终看到的效果)  3.app.get(name)  获取名为name的项的值if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});}  表示如果是开发环境,处理error时会输出堆栈信息  4.路由文件index.js  主要看下面这段代码router.get('/', function(req, res) {
res.render('index', { title: '&h1&Express&/h1&'
,users:[{username: 'Wilson'},
{username: 'Wilson Zhong'},
{username: 'Zhong Wei'}]
});});  这段表示,router.get表示通过get请求/时,响应后面的function处理,两个参数分别是request、response;  res.render表示调用模版引擎解析名字index的模板,传并传入了title和users两个对象做为参数;  为什么它会知道解板views目录下的index.ejs?而不是其它目录下的文件,或者后其它后缀名的文件?  原因就是app.js中的设置:app.set('views', path.join(__dirname, 'views'));app.set('view engine', 'ejs');  而这两个参数在index.ejs中可以使用,那么加上ejs的部分,就会返回最终生成的页面展现!&  到此应该差不多能动手用express+ejs做了一点东西了,入门就先到这里吧!&  提示:关于express,还是有必要去看看API,application、request、response、router、middleware还提供了很多方法!&
最新教程周点击榜
微信扫一扫NodeJS学习笔记 – 入门简介 - 为程序员服务
NodeJS学习笔记 – 入门简介
1、Node.js是什么
1.1、Node.js是让Javascript运行在服务器端的开发平台
NodeJS并不是独立的语言,也不是Javascript框架,也不是浏览器端库。
NodeJS是一个让Javascript运行在务器端的开发平台,让Javascript运行在浏览器之外的平台,实现了很多的模块:文件系统,模块,包,操作系统API,网络通信等CoreJavascript中没有或者不完善的功能。
1.2、异步式I/O与事件驱动
这也是NodeJS最大的特点
传统的架构:多线程,为每个业务逻辑提供一个系统线程,通过系统线程切换来弥补同步时I/O调用时的时间开销。
NodeJS使用的是单线程模型,对于所有I/O都采用异步式请求的方式,避免了上下文切换。在执行过程中维护着一个事件队列,程序在执行时进入事件循环等待下一个事件到来,每个异步式I/O请求完成后会被推送到事件队列,等待程序进入进行处理。
代码示例:
res = db.query('select * from some_table');
res.output();
db.query('select * from some_table', function(res){
res.output();
NodeJS进程在同一时刻只会处理一个事件,完成后立即进入事件循环检查并处理后面的事件。CPU和内存在同一时间集中处理一件事,同时尽可能让耗时的I/O操作并行执行。只会在事件队列中添加请求等待操作系统的回应,因而不会有任何多线程开销,很大程度上可以提高Web应用的健壮性,防止恶意攻击。
1.3、统一在Javascript浏览器之外的实现, CommonJS
CommonJS试图定义一套普通应用程序使用的API,从而填补Javascript标准库过于简单的不足。CommonJS的终极目标是制定一个像C++标准库一样的规范,使得基于CommonJS API的应用程序可以在不同的环境下运行,就像用C++编写的应用程序可以使用不同的编译器和运行时函数库一样。
CommonJS规范: 模块,包,系统,二进制,控制台,编码,文件系统,套接字,单元测试等。
NodeJS是CommonJS规范最热门的一个实现。
1.4、CommonJS的各种实现
ringoJS: RingoJS 是一个用 Java 编写的 JavaScript 运行环境,基于 Mozilla 的 Rhino 的 JavaScript 引擎,可用来开发Web应用程序。
persevere:
mongoDB:基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB[2]是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
couchDB: 是一个开源的面向文档的数据库管理系统,可以通过 RESTful JavaScript Object Notation (JSON) API 访问。
2、Node.js的优势
2.1、不需要放在 Nginx / Apache 后,Node.js本身就内置了一个HTTP模块
NodeJS内建了一个HTTP服务器支持,可以轻而易举的实现一个网站和服务器的组合,不像PHP、Perl那样,在使用PHP的时候,必须先搭建一个Apache之类的HTTP服务器,然后通过HTTP服务器的模块加载CGI调用,才能将PHP脚本的执行结果呈现给用户。
加载http模块之后,即可创建一个http服务器
var http = require('http');
http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('&h1&Node.js&/h1&');
res.end('&p&Hello World&/p&');
}).listen(8080);
2.2、Node.js 可以更精细的控制 Request 和 Response 的时间和内容
http.request(options, callback)
host: A domain name or IP address of the server to issue the request to. Defaults to 'localhost'.
hostname: To support url.parse() hostname is preferred over host
port: Port of remote server. Defaults to 80.
localAddress: Local interface to bind for network connections.
socketPath: Unix Domain Socket (use one of host:port or socketPath)
method: A string specifying the HTTP request method. Defaults to 'GET'.
path: Request path. Defaults to '/'. Should include query string if any. E.G. '/index.html?page=12'
headers: An object containing request headers.
auth: Basic authentication i.e. 'user:password' to compute an Authorization header.
agent: Controls Agent behavior. When an Agent is used request will default to Connection: keep-alive.
Class: http.ServerResponse
Event: 'close'
response.writeContinue()
response.writeHead(statusCode, [reasonPhrase], [headers])
response.setTimeout(msecs, callback)
response.statusCode response.setHeader(name, value)
response.headersSent response.sendDate response.getHeader(name)
response.removeHeader(name)
response.write(chunk, [encoding])
response.addTrailers(headers)
response.end([data], [encoding])
2.3、能支持数万个并发连接
Node.js 用异步式 I/O 和事件驱动代替多线程,带来了可观的性能提升。Node.js 除了使用 V8 作为JavaScript引擎以外,还使用了高效的 libev 和 libeio 库支持事件驱动和异步式 I/O。
2.4、采用事件驱动、异步编程,为网络服务而设计
异步编程的设计,重要的优势在于,充分利用了系统资源,执行代码无须阻塞等待某种操作完成,有限的资源可以用于其他的任务。此类设计非常适合于后端的网络服务编程,Node.js的目标也在于此。
在服务器开发中,并发的请求处理是个大问题,阻塞式的函数会导致资源浪费和时间延迟。通过事件注册、异步函数,开发人员可以提高资源的利用率,性能也会改善。
3、Node.js的缺点
3.1、可靠性低
不支持故障恢复
当程序有错误发生时,整个进程就会结束,需要重新在终端中启动服务器。这一点在开发中无可厚非,但在产品环境下就是严重的问题了,因为一旦用户访问时触发了程序中某个隐含的bug,整个服务器就崩溃了,将无法继续为所有用户提供服务。在部署Node.js 应用的时候一定要考虑到故障恢复,提高系统的可靠性。 (后面讲多线程多进程支持的时候看看怎么解决的)
3.2、单进程,单线程,默认支持单核CPU(支持多进程的方法)
NodeJS中的相关模块:
cluster:生成与当前进程相同的子进程,并且允许父进程和子进程之间共享端口。cluster 允许跨进程端口复用。
Node.js 的另一个核心模块child_process 也提供了相似的进程生成功能。
cluster.js 的功能是创建与CPU 核心个数相同的服务器进程,以确保充分利用多核CPU 的资源。主进程生成若干个工作进程,并监听工作进程结束事件,当工作进程结束时,重新启动一个工作进程。分支进程产生时会自顶向下重新执行当前程序,并通过分支判断进入工作进程分支,在其中读取模块并启动服务器。
使用cluster模块
var cluster = require('cluster');
var os = require('os');
// 获取CPU的数量
var numCPUs = os.cpus().
var workers = {};
if (cluster.isMaster) {
// 主进程分支
cluster.on('death', function (worker) {
// 当一个进程结束时,重启工作进程
delete workers[worker.pid];
worker = cluster.fork();
workers[worker.pid] =
// 初始化开启与CPU数量相同的工作进程
for (var i = 0; i & numCPUs; i++) {
var worker = cluster.fork();
workers[worker.pid] =
// 工作进程分支,启动服务器
var app = require('./app');
app.listen(3000);
// 当主进程被终止时,关闭所有工作进程
process.on('SIGTERM', function () {
for (var pid in workers) {
process.kill(pid);
process.exit(0);
3.3、太新了,API还在成熟过程中
var settings = require('./settings');
var MongoStore = require('connect-mongo');
var settring = require('./settings');
var MongoStore = require('connect-mongo')(express);
因为异步的原因, 一些完整的逻辑不可避免的会被分割成很多小块, 放在不同的回调函数里去执行, 一旦项目巨大的话, 这种开发方式面临的风险不是一点点。不符合开发者的常规线性思路,往往需要把一个完整的逻辑拆分为一个个事件,增加了开发和调试难度。
// 传统代码
var user = db.user.get('name');
var article = db.article.get(user.id);
var comment = db.comments.get(article.id);
// 异步回调
db.user.get('name', function(err, user){
db.article.get(user.id, function(err, article){
db.comments.get(article.id, function(){
// doSomethingWithResults();
解决方法:针对这个问题,Node.js第三方模块提出了很多解决方案,例如异步库 async。
4、NodeJS现阶段适合做什么
4.1、node适合io操作多,cpu操作少的场合
阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。
而非阻塞模式下,一个线程永远在执行计算操作,这个线程所使用的 CPU 核心利用率永远是 100%,I/O 以事件的方式通知。在非阻塞模式下,线程不会被 I/O 阻塞,永远在利用 CPU。
多线程带来的好处仅仅是在多核 CPU 的情况下利用更多的核,而Node.js的单线程也能带来同样的好处。这就是为什么 Node.js 使用了单线程、非阻塞的事件编程模式。
4.2、数据简单,但是数据访问频繁的场合
5、NodeJS现阶段不适合做什么
5.1、高CPU消耗的app
最显而易见的用例是那种CPU使用率高同时I/O操作小的。所以如果你打算写一个视频编码软件,人工智能软件或者类似的CPU使用率高的软件,请不要用node.js。要是你肯稍微变通一下,用C或C++效果会更好。
但是,node.js允许你很轻松的写C++扩展,所以你可以把它作为一个你核心算法的脚本引擎。
NoSQL + Node.js——如果仅仅是为了追求时髦,且自己对这两门技术还未深入理解的情况下,不要冒险将业务系统搭建在这两个漂亮的名词上,建议使用MySQL之类的传统数据库
6、NodeJS比较热门的框架
6.1、UnitTest
· Expresso /visionmedia/expresso
· Nodeunit /caolan/nodeunit
npm install nodeunit
exports.testSomething = function(test){
// 指定一个测试内期望被执行的断言数量,确保你的回调和断言被执行到了。
test.expect(1);
// 判断是否为true
test.ok(1==1, 'this assertion should pass');
// 结束当前的测试函数并继续执行下一个
test.done();
exports.testSomethingElse = function(test){
test.equal(1, 3, 'this assertion should fail');
test.done();
它是目前最稳定、使用最广泛,而且 Node.js 官方推荐的唯一一个 Web 开发框架。Express ( / ) 除了为 http 模块提供了更高层的接口外,还实现了许多功能,其中包括:q 路由控制;q 模板解析支持;q 动态视图;q 用户会话;q CSRF 保护;q 静态文件服务;q 错误控制器;q 访问日志;q 缓存;q 插件支持。
它只是一个轻量级的 Web 框架,多数功能只是对 HTTP 协议中常用操作的封装,更多的功能需要插件或者整合其他模块来完成。
pomelo是基于node.js的高性能,分布式游戏服务器框架。它包括基础的开发框架和相关的扩展组件(库和工具包),可以帮助你省去游戏开发枯燥中的重复劳动和底层逻辑的开发。 pomelo不但适用于游戏服务器开发, 也可用于开发高实时web应用,它的分布式架构可以使pomelo比普通的实时web框架扩展性更好。
rrestjs是在expressjs代码的基础上开发的node.js框架(这样可以减少很多bug,同时要感谢expressjs作者 visionmedia无私的奉献),不过整个框架结构已经完全改变了,属性以及方法定义也是全新的,可以说是一个全新的node.js开发框架(不仅局限于web页面的输出)。rrestjs命名源自:ROA-Restful,面向资源和restful是rrestjs的宗旨,和expressjs不同的是expressjs是利用路由机制的,而rrestjs则完全根据用户请求的uri去找寻控制器。
如果简单定义“现代网站”是一个实时交互、超高性能、具备非凡体验的网站,那么 Meteor就是一个可为开发者以简单高效而且充满乐趣的方式进行现代网站开发的平台,以往开发周期需要几周到几个月的项目,现在可能只需要几个小时或者一个周末的时间就可以完成。Meteor构建的应用体验,会让人觉得浏览器的刷新按钮和地址栏是多余的。
7、基于NodeJS实现的案例
小米公司的抢购服务程序
搜狐小纸条后端采用NodeJS来处理 消息推送
NodeJS在朋友网的实践
统计用户在线时长
服务器端推送其他消息
专业技术分享站
原文地址:, 感谢原作者分享。
您可能感兴趣的代码温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
1.错误:Express Command not found最初操作:跟着《nodejs开发指南》敲npm install -g express,安装好了,就在linux命令行敲express --help就出现上面的原因了。解决方法:在安装一个包npm install -g express-generator原因:express3+已经把创建一个APP的功能分离出来为express-generator,没它你创建不了应用程序2.express -t ejs microblog创建的不是ejs模板引擎而是jade模板引擎最初操作:跟着《nodejs开发指南》在命令行敲express -t ejs microblog是用来创建应用程序的,应用程序的名字叫microblog、模板引擎是ejs出现情况:但是通过查看microblog文件夹中的package.json中知道创建出来的不是ejs模板而是jade模板引擎解决方法:版本不一样,用错命令了,应该是express -e microblog(-e就是ejs模板)3.node app.js 启动应用没效果最初操作:跟着《nodejs开发指南》在命令行敲node app.js,然后就用浏览器访问监听的3000端口出现情况:访问不到页面解决方法:版本不一样,用错命令了,应该是npm start4.安装了ejs后,如何使用ejs的layout模板1.安装express-partials2.在cmd中切换到项目目录,运行npm install express-partials或者在 package.json 里面的 dependencies 添加 "express-partials": "*"。然后在项目目录下运行 npm install 。3.然后在app.js 里面引用 express-partials,引用方法:1.添加引用 var partials = require('express-partials');2.在 app.set('view engine', 'ejs'); 下面添加 app.use(partials());4.在需要引用模板的地方调用 layout:'模版名称' 示例de
&app.get('/reg', function (req, res) {
res.render('reg', {
title: '用户注册',
layout: 'template'
});de&5.直接使用include5.var flash = require('connect-flash'); 安装 connect-flash Express 3.x以上版本6.连接数据库de
&app.use(session({
secret: settings.cookieSecret,
store: new MongoStore({
url: 'mongodb://localhost/blog'
}));de&7.视图交互de
&app.use(function(req, res, next){
console.log("app.usr local");
res.locals.user = req.session.
res.locals.post = req.session.
var error = req.flash('error');
res.locals.error = error.length ? error : null;
var success = req.flash('success');
res.locals.success = success.length ? success : null;
});de&8.mongodb使用_id主键de
&var BSON = require('bson').BSONP
BSON.ObjectID.createFromHexString(this._id),把Id转成可以删除的主键de&
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'node.js+express+mongodb学习遇到的坑',
blogAbstract:'Nodejs 入门(nodejs开发指南新版纠正)字数654&阅读17&评论0&喜欢01.错误:Express Command not found最初操作:跟着《nodejs开发指南》敲npm install -g express,安装好了,就在linux命令行敲express --help就出现上面的原因了。',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:7,
publishTime:4,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}}

我要回帖

更多关于 express和nodejs 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信