Desenvolvendo uma aplicação Web com o Eclipse

Nesse artigo, será fornecido uma visão geral de cada parte de uma aplicação Web desenvolvida com a linguagem de programação Java, de modo a auxiliar quem está começando a desenvolver as suas próprias aplicações.

Estaremos usando aqui o IDE Eclipse, como as ferramentas de desenvolvimento Web instaladas. Para verificar se essas ferramentas estão instalada, no Eclipse acesse a opção Help > Install New Software. Caso o Eclipse não esteja instalado em sua máquina, você pode achar mais fácil baixar a versão para desenvolvedores EE disponível na página de download do site do Eclipse.

Para começar o desenvolvimento de uma nova aplicação Web, o primeira passo é criar um novo projeto no Eclipse. Para isso, acesse a opção File > New > Project. Na caixa de diálogo que aparece, selecione Web > Dynamic Web Project e clique em Next. Na próxima tela, digite apenas um nome para seu projeto e clique em Finish.

O Eclipse criará um novo projeto com a estrutura de um projeto Web e perguntará (em alguns casos) se você quer mudar para a perspectiva Java EE. Apenas diga que sim, e seu projeto irá aparecer no Project Explorer (localizado na parte esquerda da janela do Eclipse). Recomendo expandir cada pasta do projeto para ter uma visualização global do conteúdo de seu projeto.

Para os propósitos desse artigo, estaremos adicionando arquivos dentro das pastas Java Resources (subpasta src) e WebContent (sub-pasta WEB-INF). A primeira conterá os arquivos *.java, que são o código fonte da aplicação, escritos na linguagem Java. A segunda pasta conterá os arquivos *.jsp da interface da aplicação com o usuário, escritos em HTML com algumas tags especificas do JSP.

Dentro da pasta src/, iremos criar dois pacotes (botão direito no nome do projeto e selecione New > Package):

  • data: possuirá classes de suporte para acesso ao banco de dados, usado para ler e gravar os dados nos quais a aplicação irá trabalhar.
  • servlet: possuirá classes que receberão os dados da interface e repassarão esses dados para as classes do pacote data, que gravarão esses dados no banco de dados, e vice-versa, lerão dados do banco de dados (através das classes de data) para que sejam exibidos pela interface.

Você pode dar o nome que quiser aos seus pacotes, mas, por convenção, normalmente usa-se algo do tipo:

  • com.nome_da_aplicação.data
  • com.nome_da_aplicação.servlet

O pacote data terá as seguintes classes:

  • Uma classe nomeada convencionalmente DataHelper, que conterá os comando específicos de comunicação com o banco de dados e encapsula os comandos SQL necessários para ler/inserir dados no banco de dados.
  • Classes POJO (PlainOld Java Objects), que armazenarão os dados do banco de dados, e terão os mesmos nomes e atributos das tabelas do banco de dados.

Um exemplo de classe DataHelper seria o seguinte:

public class DataHelper {
	private Connection db;  // Conexão com o servidor de banco de dados
    private Statement st;   // Declaração para executar os comandos

    .
    .
    .

    //Métodos da classe
}

Essa classe classe terá diversos métodos para ler dados específicos no banco de dados, que terão uma estrutura comum. Os métodos que efetuam LEITURA de dados do banco de dados, tem uma estrutura parecida com o método a seguir:

public user doProcessaLogin(String username, String password) throws SQLException, ClassNotFoundException
    {
    	// Banco de dados, usuário e senha igual a "teste"
    	// CREATE USER teste WITH password 'teste';
    	// CREATE DATABASE teste WITH OWNER teste ENCODING 'LATIN1';

    	String url = "jdbc:postgresql://localhost/testedb?charSet=LATIN1";
    	String usr = "postgres";
    	String pwd = "kmo1982";

    	// Carregar o driver
    	Class.forName("org.postgresql.Driver");

    	// Conectar com o servidor de banco de dados
    	System.out.println("Conectando ao banco de dados\nURL = " + url);
    	db = DriverManager.getConnection(url, usr, pwd);

    	System.out.println("Conectado...Criando a declaração");
    	st = db.createStatement();

    	// Limpar o banco de dados (no caso de uma falha anterior) e inicializar
    	cleanup();

    	// Executar os testes utilizando os métodos do JDBC

    	user login = null;

    	ResultSet rs = st.executeQuery("select senha,first_name,last_name,id from \"user\" where username='"+username+"'");
    	if (rs != null)
    	{
    	    // Percorrer o conjunto de resultados mostrando os valores.
    	    // É necessário chamar .next() antes de ler qualquer resultado.
    	    while (rs.next())
    	    {
    	    	if (rs.getString("senha").equalsIgnoreCase(password)) {
    	    		System.out.println("Recuperando dados do nome");
    	    		login = new user();
    	    		login.setFirstName(rs.getString("first_name"));
    	    		login.setLastName(rs.getString("last_name"));
    	    		login.setId(rs.getInt("id"));
    	    		break;
    	    	}
    	    }
    	    rs.close(); // é necessário fechar o resultado ao terminar
    	}

    	// Limpar o banco de dados
    	cleanup();

    	// Fechar a conexão
    	System.out.println("Fechando a conexão");
    	st.close();
    	System.out.println("Fechando o banco de dados");
    	db.close();
    	return login;
    }

Os métodos que efetuam a GRAVAÇÃO de dados no banco de dados possuem a seguinte estrutura:

public void doRegistraSessao(String first_name, String last_name, Timestamp data_login, int id) throws SQLException, ClassNotFoundException {
    	// Banco de dados, usuário e senha igual a "teste"
    	// CREATE USER teste WITH password 'teste';
    	// CREATE DATABASE teste WITH OWNER teste ENCODING 'LATIN1';

    	String url = "jdbc:postgresql://localhost/testedb?charSet=LATIN1";
    	String usr = "postgres";
    	String pwd = "kmo1982";

    	// Carregar o driver
    	Class.forName("org.postgresql.Driver");

    	// Conectar com o servidor de banco de dados
    	System.out.println("Conectando ao banco de dados\nURL = " + url);
    	db = DriverManager.getConnection(url, usr, pwd);

    	System.out.println("Conectado...Criando a declaração");
    	st = db.createStatement();

    	// Limpar o banco de dados (no caso de uma falha anterior) e inicializar
    	cleanup();

    	// Executar os testes utilizando os métodos do JDBC

    	System.out.println("Inserindo os dados da sessão");

    	String data_conv = data_login.toString();
    	System.out.println("Data formatada:"+data_conv);

    	st.executeUpdate("INSERT INTO session (time_login, id_user) VALUES ('"+data_conv+"',"+id+");");
    	System.out.println("Dados inseridos na tabela");

    	// Limpar o banco de dados
    	System.out.println("Limpando dados da sessão");
    	cleanup();

    	// Fechar a conexão
    	System.out.println("Fechando a conexão");
    	st.close();
    	System.out.println("Fechando o banco de dados");
    	db.close();
    }

Note que os métodos que gravam dados são do tipo void (podendo ser boolean caso seja necessário), enquanto os métodos que lêem dados retornam um objeto (normalmente de um das demais classes do pacote data, mas pode-se precisar que retornem um tipo primitivo).

O pacote servlet terá classes associadas com as opções disponíveis da aplicação (e normalmente terão nomes equivalentes aos nomes dos arquivos JSP), e terão normalmente 1 ou 2 métodos, que são associados ao método de comunicação do formulário contido na página JSP com a aplicação (POST ou GET).

A seguir um exemplo de classe servlet que possui tanto um método doGet quanto um doPost (a maioria das classes terá somente um ou outro – normalmente os servlets que capturam os dados do JSP e salvam no formulário usam doPost e os servlets que retornam dados para o JSP exibir usam doGet):

public class Login extends HttpServlet {
	private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public Login() {
        super();
        // TODO Auto-generated constructor stub
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
    }

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	@SuppressWarnings({ "deprecation" })
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		String username = request.getParameter("username");
		String password = request.getParameter("password");

		Date data_login = new Date(System.currentTimeMillis());
		java.sql.Timestamp nova_data = new java.sql.Timestamp(0, 0, 0, 0, 0, 0, 0);
		nova_data.setDate(data_login.getDay());
		nova_data.setMonth(data_login.getMonth());
		nova_data.setYear(data_login.getYear());
		nova_data.setHours(data_login.getHours());
		nova_data.setMinutes(data_login.getMinutes());
		nova_data.setSeconds(nova_data.getSeconds());

		DataHelper dhelper = new DataHelper();

		try {
			System.out.println("Registrando login...");
			user temp = dhelper.doProcessaLogin(username, password);

			if(temp!=null) {
				String fname = temp.getFirstName();
				String lname = temp.getLastName();
				int id = temp.getId();

				System.out.println("Dados corretos");
				request.getSession().setAttribute("user", fname+" "+lname);
				request.getSession().setAttribute("fname", fname);
				request.getSession().setAttribute("lname", lname);
				dhelper.doRegistraSessao(fname, lname, nova_data, id);
				Cookie ck = new Cookie("User",fname+" "+lname);
				ck.setMaxAge(7);
				response.addCookie(ck);
				request.getRequestDispatcher("/WEB-INF/menu.jsp").forward(request,response);
			}
			else {
				System.out.println("Dados incorretos");
				request.getSession().setAttribute("erro", "Não foi possivel efetuar o login");
				System.out.println("Direcionando de volta para a pagina de login");
				request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

Essas classes do pacote servlet precisam estar declaradas no arquivo web.xml contido no diretório WEB-INF do projeto. Cada classe deve estar associada a seguinte entrada nesse arquivo:

<servlet>
    <servlet-name>Login</servlet-name>
    <servlet-class>com.webapp.servlet.Login</servlet-class>
  </servlet>
<servlet-mapping>
    <servlet-name>Login</servlet-name>
    <url-pattern>/login</url-pattern>
  </servlet-mapping>

Na pasta WebContent, iremos adicionar os arquivos JSP (botão direito sobre o nome do projeto e selecione New > JSP File) que irão ser a interface do sistema com o usuário. Aqui, temos duas opções para salvar os arquivos:

  • Caso os arquivos sejam salvos na raiz da pasta WebContent/, esses arquivos estarão disponíveis diretamente ao usuário.
  • Caso sejam salvos dentro da sub-past WEB-INF, esses arquivos somente poderão ser acessados através das classes Servlet

Aqui, temos 2 tipos de arquivos que são comuns a quase todas as aplicações Web: login.jsp que irá permitir que o usuário entre no sistema, informando um nome de usuário e senha, e menu.jsp que listará as opções do sistema.

Além dessas duas páginas, teremos também um par de páginas para inserir/listar dados do sistema. Para inserir, usa-se uma pagina que contenha um formulário com diversos campos (que normalmente coincidem com os atributos do banco de dados) e um botão para submeter esses dados ao servlet que processará esses dados e encaminhará eles para o método DataHelper; isso é feito através do método POST.

Para listar os dados, usa-se uma página JSP com algumas tags específicas de JavaServer Pages, como <c:forEach> e <c:out>. Esses dados são retornados pelo servlet em uma estrutura de dados List através do método GET.