JSP (JavaServer Pages) é um mecanismo que auxilia os desenvolvedores a implementarem páginas para internet no formato HTML ou em outros tipos, geradas de forma automaticamente e dinâmica. Nesse artigo o ambiente de desenvolvimento a ser utilizado é o Netbeans, pois nele, além de existir o servidor para a execução da aplicação, existem drivers específicos para a conectividade de dados como, por exemplo, a utilização PostgreSQL, que agiliza muito o envio e a troca de informações entre o banco de dados criado e a aplicação web. O objetivo desse artigo é criar um sistema de autenticação básico no qual serão implementadas duas páginas: uma de login e senha (entrada) no estilo padrão e a outra página principal com a opção de sair do sistema.
Para manipularmos o banco de dados será necessário o SGBD mais utilizado para o PostgreSQL, que é o pgAdmin. A instalação do mesmo é muito simples, por isso, partindo que ele já esteja instalado em sua máquina e aberto, será preciso criar um novo banco de dados com o nome Autentica. Para criar, basta clicar com o botão direito em Databases localizado no Object Explorer e depois em New Database. Aparecerá uma janela de acordo com a Figura 1.
Basta colocar no campo Name “Autentica” e clicar em OK que será criado.
Agora será criado uma tabela referente a Usuario e em seguida os campos e suas propriedades.
Para isso, é necessário clicar em clima do banco de dados criado e em seguida clicar no ícone Execute arbitrary SQL queries, localizado abaixo da barra de menus e colocar o código para a criação da tabela e seus campos, de acordo com a Listagem 1.
CREATE TABLE usuario
(
usu_codigo integer NOT NULL,
usu_nome character varying(100) NOT NULL,
usu_login character varying(6) NOT NULL,
usu_senha character varying(6) NOT NULL,
usu_adm boolean NOT NULL,
CONSTRAINT usuario_pkey PRIMARY KEY (usu_codigo),
CONSTRAINT usuario_usu_login_key UNIQUE (usu_login)
)
WITH (
OIDS=FALSE
);
ALTER TABLE usuario
OWNER TO postgres;
Para concluir, basta clicar no botão Execute Query (uma seta apontada para a direita), localizado abaixo da barra de menus, ou se preferir, aperte a tecla de atalho F5 para terminar de criar a tabela.
Para adicionar alguns registros na tabela, coloque os comandos descritos na Listagem 2.
insert into usuario (usu_codigo, usu_nome, usu_login, usu_senha, usu_adm) values
(1, 'Administrador', 'admin', '123456', true);
insert into usuario (usu_codigo, usu_nome, usu_login, usu_senha, usu_adm) values
(2, 'Convidado', 'guest', 'guest', false);
Objeto de Acesso a Dados (DAO)
Agora será criado um Objeto de Acesso a Dados (DAO) que servirá para que futuramente a aplicação web possa consumir todos os recursos presentes nesse objeto que por consequência se transformará em uma biblioteca.
Com o Netbeans instalado e aberto, vá em Arquivo → Novo Projeto e selecione Java. Clique em próximo para aparecer a janela de configurações, como mostra a Figura 2.
Coloque no campo nome como ‘dao” e no campo localização do Projeto coloque o caminho ‘D:\’. Não esqueça de desmarcar a opção Criar Classe Principal.
Em seguida basta clicar em Finalizar que o projeto dao estará pronto para ser implementado.
A proposta agora é criar três pastas: sql, entidades e ao.
Dentro da pasta sql será criada a nova classe Java com o nome de Conexão.java. Dentro da pasta entidades será criada a nova classe Java com o nome de Usuario.java e dentro da pasta dao será criada uma interface com o nome DAO.java e duas classes com os nomes DAOException.java e Usuario.java. Para vermos como ficará toda essa criação, o layout deve estar parecido com a Figura 3.
Dentro da classe Conexao.java será implementado o código descritos na Listagem 3.
package sql;
import java.sql.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public final class Conexao {
private static final String usuario = "postgres";
private static final String senha = "postgres123";
private static final String url = "jdbc:postgresql://127.0.0.1:5432/Autentica";
public static Connection open() {
try {
Class.forName("org.postgresql.Driver");
return DriverManager.getConnection(url, usuario, senha);
} catch (SQLException | ClassNotFoundException ex) {
Logger.getLogger(Conexao.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
public static void close(ResultSet rs, Statement st, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
public static void close(Statement st, Connection conn) {
close(null, st, conn);
}
public static void close(Connection conn) {
close(null, null, conn);
}
}
Dentro da classe Usuario.java será implementada os códigos descrito na Listagem 4. Essa classe terá como objetivo ser o modelo da aplicação, com as propriedades dos campos, receber e definir os dados de acordo com seu tipo, encapsulando-os e também comparar o que está salvo com os dados informados pelo usuário.
package entidades;
import java.io.Serializable;
import java.util.Objects;
public class Usuario
implements Serializable {
private Integer codigo;
private String nome;
private String login;
private String senha;
private boolean administrador;
public Usuario() {
this(null, null, null, null, false);
}
public Usuario(Integer codigo, String nome, String login, String senha,
boolean administrador) {
this.codigo = codigo;
this.nome = nome;
this.login = login;
this.senha = senha;
this.administrador = administrador;
}
public Integer getCodigo() {
return codigo;
}
public void setCodigo(Integer codigo) {
this.codigo = codigo;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getSenha() {
return senha;
}
public void setSenha(String senha) {
this.senha = senha;
}
public boolean isAdministrador() {
return administrador;
}
public void setAdministrador(boolean administrador) {
this.administrador = administrador;
}
@Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + Objects.hashCode(this.codigo);
return hash;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Usuario other = (Usuario) obj;
if (!Objects.equals(this.codigo, other.codigo)) {
return false;
}
return true;
}
}
Dentro da interface DAO.java será implementada os códigos descritos na Listagem 5.
package dao;
import java.util.List;
public interface DAO<T> {
public T getSingle(Object... chave);
public List<T> getList();
public List<T> getList(int top);
}
E dentro da classe DAOException.java será implementada o código descrito na Listagem 6.
package dao;
public class DAOException extends Exception {
public DAOException(Throwable cause) {
super(cause);
}
public DAOException(String message, Throwable cause) {
super(message, cause);
}
public DAOException(String message) {
super(message);
}
public DAOException() {
super();
}
}
Dentro da classe UsuarioDAO.java será implementada os códigos descrito na Listagem 7. Essa classe possui diversos métodos e cada um é responsável por buscar o registro de uma forma diferente.
package dao;
import entidades.Usuario;
import sql.Conexao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class UsuarioDAO
implements DAO<Usuario> {
public Usuario getSingle(String login) {
Connection conn = Conexao.open();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("select usu_codigo, usu_nome,
usu_login,
usu_senha, usu_adm from usuario where usu_login = ?");
ps.setString(1, login);
rs = ps.executeQuery();
if (rs.next()) {
return new Usuario(rs.getInt("usu_codigo"),
rs.getString("usu_nome"),
rs.getString("usu_login"), rs.getString("usu_senha"),
rs.getBoolean("usu_adm"));
}
} catch (SQLException ex) {
} finally {
Conexao.close(rs, ps, conn);
}
return null;
}
@Override
public Usuario getSingle(Object... chave) {
if (chave[0] instanceof Integer) {
Connection conn = Conexao.open();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("select usu_codigo,
usu_nome,
usu_login, usu_senha, usu_adm from usuario
where usu_codigo = ?");
ps.setInt(1, (Integer) chave[0]);
rs = ps.executeQuery();
if (rs.next()) {
return new Usuario(rs.getInt("usu_codigo"),
rs.getString("usu_nome"),
rs.getString("usu_login"),
rs.getString("usu_senha"), rs.getBoolean("usu_adm"));
}
} catch (SQLException ex) {
} finally {
Conexao.close(rs, ps, conn);
}
}
return null;
}
@Override
public List<Usuario> getList() {
return getList(0);
}
@Override
public List<Usuario> getList(int top) {
if (top < 0) {
return null;
}
List<Usuario> lista = null;
Connection conn = Conexao.open();
Statement ps = null;
ResultSet rs = null;
try {
ps = conn.createStatement();
rs = ps.executeQuery("select " + (top > 0 ?
"top " + top : "") +
"usu_codigo, usu_nome, usu_login, usu_senha,
usu_adm from usuario");
lista = new ArrayList<>();
while (rs.next()) {
lista.add(new Usuario(rs.getInt("usu_codigo"),
rs.getString("usu_nome"),
rs.getString("usu_login"), rs.getString("usu_senha"),
rs.getBoolean("usu_adm")));
}
} catch (SQLException ex) {
} finally {
Conexao.close(rs, ps, conn);
}
return lista;
}
}
Criando uma Nova Aplicação Web
Agora será criada uma nova aplicação web. Para isso, basta ir à barra de menus, em Arquivo → Novo Projeto. Selecione a categoria Java Web e o Projeto Aplicação Web. Depois clique em Próximo e aparecerá uma janela para definir o nome do projeto assim como fizermos anteriorente.
O resultado da configuração do servidor será o mesmo que o apresentado pela Figura 4.
Por padrão, será selecionado o Apache Tomcat, mas poderia estar selecionado o GlassFish Server. A versão do Java EE que está selecionada a última disponível no site da tecnologia. O caminho do Contexto pode deixar do jeito que foi definido automaticamente. Ao final clique em Finalizar para que o “esqueleto” do projeto seja criado.
Implementação do Projeto
Antes de criarmos as pastas de organização para o projeto, adicionaremos o projeto DAO desenvolvido anteriormente. Para isso, basta clicar com o botão direito em Biblioteca e depois em: “Adicionar Projeto”. Selecione o projeto criado e depois clique em Adicionar Arquivos JAR de Projeto para finalizar a importação.
Concluindo, é necessário importar o driver JDBC pronto e próprio para o PostgreSQL, com o objetivo de conectividade com o banco de dados. Com isso, clique com o botão direito em Biblioteca e selecione a opção Driver JDBC do PostgreSQL. Clique em Finalizar que o driver será adicionado automaticamente.
Agora definiremos as pastas para melhor organização do projeto, com a finalidade de não haver perca de caminhos, arquivos ou de trocas de informações.
Então, dentro da pasta Pacotes de Códigos-fonte será proposto colocar quatro Pacotes Java: filtro, logado, servlet, útil.
No pacote filtro introduza um novo “Filtro”, clicando com o botão direito em cima do pacote, vá para a opção: Outros, selecione a categoria: Web e o Tipo de Arquivo: Filtro. Clique em Próximo e coloque o nome para o novo filtro de UsuarioLogado. Após clicar em Próximo, aparecerá uma janela de configuração de implantação do filtro: clique em novo e deixe configurado do mesmo jeito que se encontra a Figura 5.
Após isso, clique em OK e depois em Finalizar.
Já no filtro criado UsuarioLogado.java, sobrescreva o seu conteúdo pelo código que se encontra na Listagem 8.
package filtro;
import entidades.Usuario;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebFilter(filterName = "UsuarioLogado", urlPatterns = {"/logado/*"})
public class UsuarioLogado implements Filter {
private String contextPath;
public UsuarioLogado() {
}
@Override
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession();
Usuario u = (Usuario) session.getAttribute("usuarioLogado");
if (u == null) {
session.invalidate();
res.sendRedirect(contextPath + "/index.jsp");
} else {
res.setHeader("Cache-control", "no-cache, no-store");
res.setHeader("Pragma", "no-cache");
res.setHeader("Expires", "-1");
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) {
this.contextPath = filterConfig.getServletContext().getContextPath();
}
}
Esse filtro é responsável por controlar todas as ações durante a autenticação do sistema, tornando as requisições e o acesso para as páginas web mais refinada.
Dentro do pacote logado será criada uma nova classe Java com o nome de Menu.java e terá o mesmo código que o mesmo encontrado na Listagem 9.
package logado;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "Menu", urlPatterns = {"/logado/menu.jsp"})
public class Menu extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher rd = request.getRequestDispatcher(
"/WEB-INF/view/logado/menu.jsp");
rd.forward(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
public String getServletInfo() {
return "Short description";
}
}
Esse código responsável por definir os modos de requisições para a página principal e redirecionamentos caso a autenticação esteja concluída e o usuário esteja logado no sistema.
Dentro do pacote servlet será criado uma nova classe chamada Index.java e será implementada com os códigos descritos na Listagem 10.
package servlet;
import dao.UsuarioDAO;
import entidades.Usuario;
import util.Erro;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "Index", urlPatterns = {"/index.jsp", "/logout.jsp"})
public class Index extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Erro erros = new Erro();
if (request.getParameter("bOK") != null) {
String login = request.getParameter("login");
String senha = request.getParameter("senha");
if (login == null || login.isEmpty()) {
erros.add("Login não informado!");
}
if (senha == null || senha.isEmpty()) {
erros.add("Senha não informada!");
}
if (!erros.isExisteErros()) {
UsuarioDAO dao = new UsuarioDAO();
Usuario user = dao.getSingle(login);
if (user != null) {
if (user.getSenha().equalsIgnoreCase(senha)) {
request.getSession().setAttribute("usuarioLogado", user);
response.sendRedirect("logado/menu.jsp");
return;
} else {
erros.add("Senha inválida!");
}
} else {
erros.add("Usuário não encontrado!");
}
}
}
request.getSession().invalidate();
request.setAttribute("mensagens", erros);
String URL = "/WEB-INF/view/index.jsp";
RequestDispatcher rd = request.getRequestDispatcher(URL);
rd.forward(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
public String getServletInfo() {
return "Short description";
}
}
Essa classe é responsável por tratar o envio e recebimento do redirecionamento das páginas e suas declarações, sendo armazenadas no servidor para que haja o processamento e enfim validação dos dados que o usuário informou, fazendo o tratamento de erros e adicionando para a propriedade de erros instanciada caso obtiver erro na autenticação.
E por fim, no pacote util será criada a classe Erro.java e será implementada os códigos descritos na Listagem 11.
package util;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public final class Erro
implements Serializable {
private final List<String> erros;
public Erro() {
erros = new ArrayList<>();
}
public Erro(String mensagem) {
erros = new ArrayList<>();
erros.add(mensagem);
}
public void add(String mensagem) {
erros.add(mensagem);
}
public boolean isExisteErros() {
return !erros.isEmpty();
}
public List<String> getErros() {
return erros;
}
}
Agora a proposta é apagar o arquivo index.html que foi criado automaticamente (por padrão) localizado dentro da pasta Páginas Web e criar uma nova pasta com o nome view para dentro da pasta WEB-INF. Dentro dessa pasta view será criada a página index, só que no formato .jsp. Além disso, crie outra pasta com o nome logado e dentro dessa crie um arquivo: .jsp com o nome de Menu. Para efeitos de design, dentro da pasta Páginas Web crie uma nova pasta chamada css e dentro crie um arquivo CSS. Para esse último passo, clique com o botão direito em cima da pasta criada: vá em Novo → Outros e na parte Categorias selecione HTML5. Logo após, em Tipos de Arquivos, selecione a opção Folha de Estilo em Cascata e defina o nome de layout. Ao clicar em Finalizar, a estrutura do projeto web deve ficar da mesma maneira que a demonstrada a Figura 6.
Vamos agora preencher o arquivo menu.jsp com o código descrito na Listagem 12. Esse código HTML tags em JSP responsável é responsável por buscar o nome do usuário logado (autenticado) para a página principal. Ele contém também o link para o logout do sistema.
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Menu do Sistema</title>
</head>
<body>
<h1>Menu do Sistema</h1>
<p>Olá ${sessionScope.usuarioLogado.nome}</p>
<ul>
<li>
<a href="${pageContext.request.contextPath}/logout.jsp">Sair</a>
</li>
</ul>
</body>
</html>
Dentro do arquivo index.jsp coloque os códigos descritos na Listagem 13.
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Autenticação de Usuário</title>
<link href="${pageContext.request.contextPath}/css/layout.css"
rel="stylesheet" type="text/css"/>
</head>
<body>
<h1>Autenticação de Usuário</h1>
<c:if test="${mensagens.existeErros}">
<div id="erro">
<ul>
<c:forEach var="erro" items="${mensagens.erros}">
<li> ${erro} </li>
</c:forEach>
</ul>
</div>
</c:if>
<form method="post" action="index.jsp">
<table>
<tr>
<th>Login: </th>
<td><input type="text" name="login"
value="${param.login}"/></td>
</tr>
<tr>
<th>Senha: </th>
<td><input type="password" name="senha" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="bOK" value="Entrar"/>
</td>
</tr>
</table>
</form>
</body>
</html>
Esse código HTML com JSP é responsável por exibir ao usuário os campos para inserção de login, senha e botão para autenticação. Caso o usuário informe dados incorretos ou não informe, é emitido uma mensagem no canto superior dizendo que existem erros.
E para finalizar, coloque dentro do arquivo layout.css o código descrito na Listagem 14.
#erro {
width: 80%;
margin: 0 auto;
border: 1px solid red;
background-color: beige;
}
O código é responsável por deixar a aparência da mensagem mais apresentável ao usuário.
Após ter finalizado, basta salvar o projeto e executar o mesmo apertando F6.
O resultado será um formulário simples de autenticação, como mostra a Figura 7(no Mozilla Firefox).
Para autenticar, basta colocar os dados que foram cadastrados na tabela anteriormente e depois clique em Entrar.
Caso o usuário não preencha os dados, então será apresentada uma mensagem de erro com a necessidade do sistema, por exemplo: se o Login e/ou a Senha não forem informados, como mostra a Figura 8.