do mini-curso

Download Report

Transcript do mini-curso

Criando aplicações web
com Node.js
Charles Viegas
[email protected]
@charlesviegas
Referências
• nodejs.org
• http://expressjs.com/
• https://github.com/expressjs/body-parser
• https://github.com/expressjs/session
• Livro: Node.js: aplicações web real-time com Node.js
– Caio Ribeiro
– Casa do código
Código fonte da solução
https://github.com/charlesviegas/minicurso-nodejs.git
INTRODUÇÃO AO NODE.JS
O que é o Node.js?
• Javascript no lado do servidor
• Construído sobre o engine V8 do Chrome
• Executa por linha de comando
• Projetado para alta concorrência
• Single thread
• Não bloqueante
• Utiliza o framework CommonsJS
Não bloqueia IO
• Esperar pedidos de I/O degrada a performance.
• O Node usa evento em JS para anexar retornos a chamadas
de IO.
Exemplo
BLOQUEANTE
NÃO BLOQUEANTE
...
String sql = "SELECT c FROM Contato";
…
var callback = function(err, rows) {
if(err) throw err;
console.log(rows);
});
Query q= em.createQuery(sql);
List result = query.getResultList();
...
con.query("SELECT * FROM Contato",
callback);
…
Event Loop
• Ao invés de threads, o Node usa um loop de eventos,
aliviando o overhead da troca de contexto.
Instalação e Configuração
• Acesse o site http://nodejs.org
• Faça download do executável e instale de forma padrão
• Verifique se a instalação funcionou corretamente executando
os comandos:
– node –version
– npm --version
Prática 1 - Olá Javaneiros
• Abra o terminal e navegue para a pasta:
– curso\pratica1
• Execute o comando: node olajavaneiros.js
– Observe a saída no próprio terminal
• Execute o comando: node olajavaneiroshttp.js
– Abra seu navegador e acesse a url impressa no terminal
NPM
• Node Package Manager
– Gerencia os módulos do node, baixando da web os módulos e suas
dependências
• Baseado em linha de comando
– npm install nome_do_modulo --save
– npm install – g nome_do_modulo
– npm remove nome_do_modulo
– npm update nome_do_modulo
– npm list
package.json
• O Node utiliza o arquivo package.json para descrever os
metadados do projeto.
– Nome, versão, dependências
• Deve estar presente na pasta raiz de cada projeto.
package.json
{
"name": “nome_do_projeto",
"description": "Meu primeiro app em Node.js",
"author": “Charles Viegas <[email protected]>",
"version": "1.0.0",
"private": true,
"dependencies": {
"modulo-1": "1.0.0",
"modulo-2": "~1.0.0",
"modulo-3": ">=1.0.0"
},
"devDependencies": {
"modulo-4": "*"
}
}
Prática 2 - Criando o package.json
• Durante o curso iremos criar uma pequena aplicação para
controlar uma lista de presentes para casamento.
• Crie a pasta raiz:
– Nome: casalista
• Crie dentro da pasta o arquivo:
– Nome: package.json
– Conteúdo: name, description, author, version e private
• Execute dentro da pasta raiz o seguinte comando:
– npm install
Prática 2 - Criando o package.json
{
"name": “casalista",
"description": “App para lista de casamento em Node.js",
"author": “Seu Nome <[email protected]>",
"version": "1.0.0",
"private": true
}
Objetos globais
• global: assim como nos browsers o Node também possui um
contexto de alto nível.
• process: contém os dados do processo de execução.
• console: usado para imprimir mensagens nas saídas de fluxo
padrões.
• Buffer: usado para manipular dados binários.
• require: usado para importação de módulos
Objetos globais
• __filename: o nome do arquivo que está sendo executado
• __dirname: o nome do diretório que reside o arquivo que está
sendo executado.
• module: uma referência para o módulo corrente.
CommonJS
• O Node utiliza nativamente o padrão CommonJS para
organização e carregamento dos módulos.
modulo1.js
modulo2.js
var m2 = require(“./modulo2.js”);
m2(“Ola Javaneiros”);
module.exports = function(msg){
console.log(msg);
}
DOMINANDO EXPRESS
O que é o Express?
• Escrever código usando a API HTTP do Node é muito
trabalhoso.
• O Express é um módulo para desenvolvimento de aplicações
web de grande escala.
Características do Express
• MVR (Model-View-Routes)
• MVC (Model-View-Controller)
• Roteamento de urls via callbacks
• Middleware
• Interface RESTFul
• Suporte a File Uploads
• Integração com Template Engines
Módulos do Express
• A partir da versão 4, o Express passou a ser distribuído em vários
módulos, sendo eles:
– express: Módulo principal do express.
– express-load: Carregamento dinâmico de arquivos JS.
– express-session: Controle de sessões do usuário.
– method-override: Traduz método POST para PUT e DELETE.
– body-parser: Parser de campos do html para objeto JSON.
– cookie-parser: Parser de cookie para objeto JSON.
– ejs: Engine de template.
Prática 3 - Instalando o express
• Altere o seu package.json incluindo como dependência as
últimas versões dos módulos:
– express, express-load, express-session, method-override, bodyparser, cookie-parser e ejs
• Dentro da pasta raiz execute o comando:
– npm install
• O npm vai criar a pasta node_modules e dentro delas todos
os seus módulos
Prática 4 – Criando as pastas do
projeto
• Copie para a pasta raiz do seu projeto a estrutura de pastas e
arquivos definida em curso\pratica4
Prática 4 – Criando as pastas do
projeto
• controllers: vai conter os nossos controladores (MVC).
• routes: vai conter os nossos roteadores.
• public: vai conter os css e imagens.
• views: vai conter as nossas views (MVC).
• app.js: arquivo JS principal do nosso projeto.
Atenção: por questões de simplificação
não teremos o model (MVC) neste curso.
Iniciando um servidor Express
// Importa e instancia um servidor express
var express = require("express"),
app = express();
// Configurações futuras
// Sobe o servidor HTTP na posta 3000
app.listen(3000, function () {
console.log(“Servidor está no ar.");
});
Prática 5 – Iniciando um servidor
express
• Conforme exemplo anterior altere o arquivo app.js
• Execute o comando:
– node app.js
• Abra o navegador no endereço: http://localhost:3000
• Você deve receber a mensagem: Cannot GET /
Definindo views
...
// Configurações futuras
// Define a pasta onde irão ficar as views
app.set("views", __dirname + "/views");
// Define o template engine usado nas views
app.set("view engine", "ejs");
...
Definindo conteúdo estático
// Configurações futuras
...
// Define a pasta public para conteúdo estático
app.use(express.static(__dirname + "/public"));
...
Definindo as rota inicial
// Configurações futuras
...
// Responde ao acessar o localhost:3000/
app.use("/", function(req, res){
res.send("Ola Javaneiros");
});
...
Prática 6 – Definindo views,
conteúdo estático e rota inicial
• Altere o arquivo app.js com os passos feitos nos últimos três
slides.
• Reinicie o node visualizar as alterações.
• Para ver os resultados, abra seu navegador no endereço
http://localhost:3000/
• Para testar o conteúdo estático abra também o endereço
http://localhost:3000/app/css/style.css
Express-load
• Utilizaremos o express-load que carrega modulos dentro da
instância do express simplementes informando a pasta onde
estas scripts estão.
• Portanto, ao invés de usar o require(“nome_do_modulo”), nós
utilizaremos o express-load para esta função.
Express-load
// Importa o módulo express-load
var express = require("express"),
load = require("express-load"),
app = express();
...
// Carrega todas as scripts da pasta controller e routes
load("controllers")
.then("routes")
.into(app);
Prática 7 – Express-load
• Adicione o express-load conforme slides anteriores.
• Reinicie o node visualizar as alterações.
Criando Roteadores
• É comum que os roteamento no express fiquem separados
em módulos externos para melhorar a legibilidade do código.
• Portanto iremos remover o código abaixo da app.js:
app.use("/", function(req, res){
res.send("Ola Javaneiros");
});
Criando Roteadores
• E criaremos um módulo a parte só para roteamento.
module.exports = function (app) {
var home = app.controllers.home;
app.get("/", home.index);
app.post("/entrar", home.entrar);
};
Criando Controladores
• Os controladores controlam a sequência de execução e a
navegação entre as páginas.
• Também é recomendável a separação da sua lógica num módulo
separado.
module.exports = function (app) {
var HomeController = {
index: function (req, res) {
res.render("home");
},
entrar: function (req, res) {
}
};
};
return HomeController;
Prática 8 – Roteadores e
Controladores
• Crie os roteadores e controladores conforme slides
anteriores.
Criando views com EJS
• Para criação das Views utilizaremos o EJS.
• O EJS permite imprimir o conteúdo de objetos JSON em
partes do html
• Também permite a inclusão de loops, estruturas condições e
includes
Criando views com EJS
• Organizaremos nosso código da seguinte forma:
– header.ejs
– footer.ejs
– home.ejs
header.ejs
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Javaneiros - Lista de presentes de casamento</title>
<link rel="stylesheet" href="/bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="/bootstrap/css/bootstrap-theme.css"/>
<link rel="stylesheet" href="/app/css/style.css" />
</head>
<body>
footer.ejs
<footer class="navbar navbar-default navbar-fixed-bottom">
<div class="container">
Javaneiros 2014
</div>
</footer>
<script src="/bootstrap/js/jquery.js"></script>
<script src="/bootstrap/js/bootstrap.js"></script>
</body>
</html>
home.ejs
<% include ./header %>
<div class="container">
<form action="/entrar" method="post" role="form" class="form-signin">
<h2>Lista de presentes</h2>
<input type="text" name="noivo" placeholder="Noivo" class="form-control"
required="required" autofocus="autofocus"/>
<input type="text" name="noiva" placeholder="Noiva" class="form-control"
required="required"/>
<button type="submit"
class="btn btn-lg btn-primary btn-block">Ver lista</button>
</form>
</div>
<% include ./footer %>
Prática 9 – Views
• Crie as views header, footer e home conforme slides
anteriores.
Body-parser
• O express utiliza o modulo body-parser para realizar a
conversão dos dados submetidos por um formulário html em
objeto JSON.
Body-parser
var express = require("express"),
bodyParser = require("body-parser"),
load = require("express-load"),
app = express();
…
// Inclui o parser para formato json
app.use(bodyParser.json());
// Inclui parser para urlencoded
app.use(bodyParser.urlencoded({extended: true}));
...
Express-session
• Recurso que permite manter dados do usuário no servidor.
• Para acessar o objeto a ser mantido na sessão basta acessar
req.session
Express-session
var express = require("express"),
bodyParser = require("body-parser"),
load = require("express-load"),
expressSession = require("express-session"),
app = express();
…
app.use(expressSession({
secret: "keyboard cat",
resave: false,
saveUninitialized: true
}));
...
Prática 10 – Body-parser e Session
• Adicione o body-parser e o express-session conforme slides
anteriores.
Manipulando session
• Agora iremos gravar na sessão do usuário os dados
submetidos pela tela de home.
• Para isso, iremos alterar o controlador do home.
Manipulando Session
...
var HomeController = {
...
entrar: function (req, res) {
var lista = {
noivo : req.body.noivo,
noiva : req.body.noiva,
presentes : []
};
req.session.lista = lista;
res.redirect("/presentes");
}
};
...
Prática 11 – Manipulando session
• Complete o código do HomeController conforme slide
anterior.
• Após submeter o formulário você verá a seguinte mensagem:
Cannot GET /presentes
routers\presente.js
module.exports = function (app) {
var presentes = app.controllers.presentes;
app.get("/presentes", presentes.index);
app.get("/comprar/:id", presentes.comprar);
app.post("/presentes", presentes.incluir);
};
controllers\presente.js
module.exports = function (app) {
var PresentesController = {
index: function (req, res) {
res.render("presentes", {presentes: req.session.lista.presentes});
},
incluir: function (req, res) {
var lista = req.session.lista;
var presente = {
nome: req.body.nome,
valor: req.body.valor
};
lista.presentes.push(presente);
res.redirect("/presentes");
},
comprar: function (req, res) {
var id = req.params.id;
req.session.lista.presentes[id].comprado = true;
res.redirect("/presentes");
}
};
return PresentesController;
};
view\presentes.ejs
<% include ./header %>
<div class="container">
<div class="page-header">
<h1>Lista de presentes</h1>
</div>
<div class="row">
<!– ****************** Formulário -->
</div>
<div class="row">
<!– ****************** Tabela -->
</div>
<div class="row">
<a href="/">Sair</a>
</div>
</div>
<% include ./footer %>
view\presentes.ejs - formulário
<div class="col-xs-12">
<form action="/presentes" method="post" role="form">
<div class="row">
<div class="col-xs-4">
<input type="text" name=“nome" placeholder="Presente"
class="form-control"/>
</div>
<div class="col-xs-4">
<input type="text" name=“valor" placeholder="Valor"
class="form-control"/>
</div>
<div class="col-xs-4">
<button type="submit" class="btn btn-default">Incluir</button>
</div>
</div>
</form>
</div>
view\presentes.ejs - tabela
<div class="col-xs-12">
<table class="table table-bordered table-striped">
<thead><tr>
<th>Presente</th> <th>Valor</th><th>Ação</th>
</tr></thead>
<tbody>
<% presentes.forEach(function(presente, index) { %>
<tr>
<td><%- presente.nome %></td> <td><%- presente.valor %></td>
<td>
<% if (!presente.comprado) {%>
<a href="/comprar/<%- index %>">Comprar</a>
<%}%>
</td>
</tr>
<% }) %>
</tbody>
</table>
</div>
Prática 12 – Final
• Crie o roteador, controlador e a view para a tela de presentes
conforme slides anteriores.