Programação de Servlets

Acesso a Bancos de Dados com JDBC

O Problema: Aplicação de Suporte Técnico

A Demo

A Teoria sobre Servlets e JDBC

Vários servlets numa mesma aplicação

Sobre JDBC e o acesso a Bancos de Dados

Criação do Banco de Dados

CREATE TABLE SUPP_REQUESTS(
  REQUEST_ID INTEGER PRIMARY KEY,
  NOME       VARCHAR(40),
  SOBRENOME  VARCHAR(40),
  EMAIL      VARCHAR(40),
  FONE       VARCHAR(40),
  SOFTWARE   VARCHAR(40),
  SO         VARCHAR(40),
  PROBLEMA   VARCHAR(256)
);

CREATE TABLE SEQ_NO(
  PROX_NUM   INTEGER
);

INSERT INTO SEQ_NO VALUES(0);

DataSource e JNDI

import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import java.util.*;

public class TechSupDB {
  Connection con;
  private String dbName = "java:comp/env/jdbc/TechSupDB";

  public TechSupDB() throws Exception {
    try  {               
      InitialContext ic = new InitialContext();
      DataSource ds = (DataSource)ic.lookup(dbName);
      con =  ds.getConnection();
    } catch (Exception ex) {
      throw new Exception("Nao pode abrir conexao para o banco de dados: " +
                          ex.getMessage());
    }
  }
    
  public void remove() {
    try {
      con.close();
    } catch (SQLException ex) {
      System.out.println(ex.getMessage());
    }
  }
  // ...
}

Abertura e fechamento de conexão de BD

Como fazer um query e processar a resposta

public class TechSupDB {
  // ...
  public Collection getTechSupRequests() throws RequestsNotFoundException {
    ArrayList techSupRequests = new ArrayList();
    try {
      String selectStatement = "select * from SUPP_REQUESTS";
      PreparedStatement prepStmt = con.prepareStatement(selectStatement);
      ResultSet rs = prepStmt.executeQuery();

      while (rs.next()) {
        techSupRequests.add(new RequestDetails(
                                         rs.getInt(1),
                                         rs.getString(2),
                                         rs.getString(3),
                                         rs.getString(4), 
                                         rs.getString(5), 
                                         rs.getString(6), 
                                         rs.getString(7), 
                                         rs.getString(8)));
      }
      rs.close();
      prepStmt.close();
    } catch(SQLException ex) {
      throw new RequestsNotFoundException(ex.getMessage());
    }
    Collections.sort(techSupRequests);
    return techSupRequests;
  }

Outro exemplo de query

public class TechSupDB {
  // ...
  public RequestDetails getRequestDetails(int requestId)
                        throws RequestNotFoundException {
    try {
      String selectStatement = "select * from SUPP_REQUESTS where REQUEST_ID = ?";
      PreparedStatement prepStmt = con.prepareStatement(selectStatement);
      prepStmt.setInt(1, requestId);
      ResultSet rs = prepStmt.executeQuery();
      if (rs.next()) {
        RequestDetails requestDetail = new RequestDetails(
                                         rs.getInt(1),
                                         rs.getString(2),
                                         rs.getString(3),
                                         rs.getString(4), 
                                         rs.getString(5), 
                                         rs.getString(6), 
                                         rs.getString(7), 
                                         rs.getString(8));
        rs.close();
        prepStmt.close();
        return requestDetail;
      } else {
        rs.close();
        prepStmt.close();
        throw new RequestNotFoundException("Nao pode achar request: " + 
                                           requestId);
      }
    } catch (SQLException ex) {
      throw new RequestNotFoundException("Nao pode achar request: " + 
                                         requestId + " " + ex.getMessage());
    }
  }

Como adicionar informação ao banco

public class TechSupDB {
  // ...
  public int addRequest(String nome,
                        String sobrenome, String email,
                        String fone, String software,
                        String so, String problema) 
                        throws RequestNotInsertedException {

    int requestId = 0;
    try {
      requestId = getPróximoNúmero();
    } catch (SQLException ex) {
      throw new RequestNotInsertedException("Nao pode obter requestId: " + 
                                            ex.getMessage());
    }
    try {
      String insertStatement = "insert into SUPP_REQUESTS VALUES(?, ?, ?, ?, ?, ?, ?, ?)";
      PreparedStatement prepStmt = con.prepareStatement(insertStatement);
      prepStmt.setInt(1, requestId);
      prepStmt.setString(2, nome);
      prepStmt.setString(3, sobrenome);
      prepStmt.setString(4, email);
      prepStmt.setString(5, fone);
      prepStmt.setString(6, software);
      prepStmt.setString(7, so);
      prepStmt.setString(8, problema);
      con.setAutoCommit(true);
      prepStmt.executeUpdate();
      prepStmt.close();
    } catch (SQLException ex) {
      throw new RequestNotInsertedException("Nao pode inserir request: " + 
                                         requestId + " " + ex.getMessage());
    }
    return requestId;
  }

Tratamento de transações

public class TechSupDB {
  // ...
  private int getPróximoNúmero() throws SQLException {
    final String updateStatementStr = "UPDATE SEQ_NO SET PROX_NUM = PROX_NUM + 1";
    final String selectStatementStr = "SELECT PROX_NUM FROM SEQ_NO";
    PreparedStatement updateStatement = con.prepareStatement(updateStatementStr);
    PreparedStatement selectStatement = con.prepareStatement(selectStatementStr);
    con.setAutoCommit(false);
    // Incrementa sequenciador
    updateStatement.executeUpdate();
    updateStatement.close();
    // Pega número de sequência
    ResultSet rs = selectStatement.executeQuery();
    rs.next();
    int next = rs.getInt(1);

    selectStatement.close();
    con.commit();
    // volta ao valor original do auto commit
    con.setAutoCommit(true);
    return next;
  }

Sobre o ciclo de vida de um servlet

servlet3.gif (13571 bytes)

Sobre o compartilhamento de informação entre servlets

Escopo Classe Quem pode acessar?
Contexto Web
(a aplicação toda)
javax.servlet.ServletContext Qualquer componente Web da aplicação
Sessão javax.servlet.http.HttpSession Qualquer componente Web tratando de um pedido da sessão
Pedido subtipo de javax.servlet.ServletRequest Qualquer componente Web tratando do pedido
Página javax.servlet.jsp.PageContext A página JSP que cria o objeto
(Veja outro capítulo sobre JSP)
import javax.servlet.*;

public final class ContextListener
  implements ServletContextListener {
  private ServletContext context = null;

  public void contextInitialized(ServletContextEvent event) {
    context = event.getServletContext();
   
    try {
      context.setAttribute("techSupDB", new TechSupDB());
    } catch (Exception ex) {
      context.log("Nao pode criar o objeto de base de dados de pedidos: " + ex.getMessage());
    }
  }
    
  public void contextDestroyed(ServletContextEvent event) {
    context = event.getServletContext();
    TechSupDB techSupDB = (TechSupDB)context.getAttribute("techSupDB");
    techSupDB.remove();
    context.removeAttribute("techSupDB");
  }
}
    context.setAttribute("techSupDB", new TechSupDB());
public class TechSupServlet extends HttpServlet {
  private TechSupDB techSupDB;

  public void init() throws ServletException {
    techSupDB = (TechSupDB)getServletContext().getAttribute("techSupDB");
    if(techSupDB == null) {
      throw new UnavailableException("Nao pode obter o banco de dados.");
    }
  }
  // ...

A Solução

A classe TechSupDB

A classe RequestDetails

    Collections.sort(techSupRequests);

O ContextListener

techsup.html

<html>

<head>
<title>UFPb - Help Desk</title>
</head>

<body>

<h1>Pedido de Suporte Técnico - Help Desk da UFPb</h1>

<hr>

<p align="center"><br>
</p>

<form ACTION="/techsup/cadastra" METHOD="POST">
  <table ALIGN="center" WIDTH="100%" CELLSPACING="2" CELLPADDING="2">
    <tr>
      <td ALIGN="right">Nome:</td>
      <td><input TYPE="Text" NAME="nome" ALIGN="LEFT" SIZE="15"></td>
      <td ALIGN="right">Sobrenome:</td>
      <td><input TYPE="Text" NAME="sobrenome" ALIGN="LEFT" SIZE="15"></td>
    </tr>
    <tr>
      <td ALIGN="right">Email:</td>
      <td><input TYPE="Text" NAME="email" ALIGN="LEFT" SIZE="25"></td>
      <td ALIGN="right">Fone:</td>
      <td><input TYPE="Text" NAME="fone" ALIGN="LEFT" SIZE="15"></td>
    </tr>
    <tr>
      <td ALIGN="right">Software:</td>
      <td><select NAME="software" SIZE="1">
        <option VALUE="Word">Microsoft Word</option>
        <option VALUE="Excel">Microsoft Excel</option>
        <option VALUE="Access">Microsoft Access</option>
      </select> </td>
      <td ALIGN="right">Sistema Operacional:</td>
      <td><select NAME="so" size="1">
        <option VALUE="95">Windows 95</option>
        <option VALUE="98">Windows 98</option>
        <option VALUE="NT">Windows NT</option>
        <option VALUE="2000">Windows 2000</option>
      </select> </td>
    </tr>
  </table>
  <p><br>
  Descrição do Problema<br>
  <textarea NAME="problema" COLS="50" ROWS="4"></textarea> </p>
  <hr>
  <p><br>
  <input TYPE="submit" NAME="submit" VALUE="Submeter Pedido"> </p>
</form>

<p><a href="/techsup/lista">Listar pedidos de suporte existentes</a></p>
</body>
</html>

TechSupServlet

// Import Servlet packages
import javax.servlet.*;
import javax.servlet.http.*;

// Import other Java packages
import java.io.*;
import java.sql.*;

public class TechSupServlet extends HttpServlet {
  private TechSupDB techSupDB;

  public void init() throws ServletException {
    techSupDB =
            (TechSupDB)getServletContext().getAttribute("techSupDB");
    if(techSupDB == null) {
      throw new UnavailableException("Nao pode obter o banco de dados.");
    }
  }

  public void destroy() {
    techSupDB.remove();
    techSupDB = null;
  }

  protected void doPost(HttpServletRequest req, HttpServletResponse res) 
          throws ServletException, IOException {
    String nome = req.getParameter("nome");
    String sobrenome = req.getParameter("sobrenome");
    String email = req.getParameter("email");
    String fone = req.getParameter("fone");
    String software = req.getParameter("software");
    String so = req.getParameter("so");
    String problema = req.getParameter("problema");
    // deveria verificar os parametros para ter certeza que não são nulos
    int requestId = 0;
    try {
      requestId = techSupDB.addRequest(nome, sobrenome, email, fone,
                             software, so, problema);
    } catch (RequestNotInsertedException e) {
      throw new ServletException("Erro no banco de dados: ", e);
    } 

    // Prepara resposta
    PrintWriter out = res.getWriter();

    res.setContentType("text/html");

    out.println("<HTML><HEAD><TITLE>");
    out.println("Suporte Técnico: Confirmação de Pedido");
    out.println("</TITLE></HEAD>");
    out.println("<BODY>");
    out.println("<H1>Suporte Técnico: Confirmação de Pedido</H1>");
    out.println("<P>Obrigado por seu pedido. Recebemos seu pedido e ele recebeu o número de identificação seguinte.</P>");
    out.println("<P>Identificação do Pedido: " + requestId + "</P>");
    out.println("<P>Favor anotar este número para referência futura.</P>");
    out.println("<P>Atenderemos seu pedido nos próximos 24 horas.</P>");
    out.println("<P>O administrador<br>Equipe de Suporte Técnico. </P>");
    out.println("</BODY></HTML>");

    out.close();
  } 
}

TechSupListaServlet

// Import Servlet packages
import javax.servlet.*;
import javax.servlet.http.*;

// Import other Java packages
import java.io.*;
import java.util.*;
import java.sql.*;

public class TechSupListaServlet extends HttpServlet {
  private TechSupDB techSupDB;

  public void init() throws ServletException {
    techSupDB =
            (TechSupDB)getServletContext().getAttribute("techSupDB");
    if(techSupDB == null) {
      throw new UnavailableException("Nao pode obter o banco de dados.");
    }
  }

  public void destroy() {
    techSupDB.remove();
    techSupDB = null;
  }

  protected void doGet(HttpServletRequest req, HttpServletResponse res) 
          throws ServletException, IOException {

    Iterator it = null;
    try {
      Collection requests = techSupDB.getTechSupRequests();
      it = requests.iterator();
    } catch(RequestsNotFoundException e ) {
      throw new ServletException("Erro no banco de dados: ", e);
    }
    PrintWriter out = res.getWriter();
    res.setContentType("text/html");
    out.println("<HTML><HEAD>");
    out.println("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"style.css\"/>");
    out.println("<TITLE>");
    out.println("Suporte Técnico: Lista de Pedidos");
    out.println("</TITLE>");
    out.println("</HEAD>");
    out.println("<BODY>");
    out.println("<H1>Suporte Técnico: Lista de Pedidos</H1>");
    out.println("<TABLE CLASS=\"clsIndex\">");
    out.println("<TR>");
    out.println("<TD CLASS=\"clsBigNav\">");
    out.println("Identificação de pedido");
    out.println("</TD>");
    out.println("<TD CLASS=\"clsBigNav\">");
    out.println("Sobrenome");
    out.println("</TD>");
    out.println("<TD CLASS=\"clsBigNav\">");
    out.println("Software");
    out.println("</TD>");
    out.println("</TR>");
    while(it.hasNext()) {
      RequestDetails rd = (RequestDetails)it.next();
      out.println("<TR>");
      out.println("<TD CLASS=\"clsTitle\">");
      out.println("<a href=\"/techsup/detalha?requestId=" + rd.getRequestId() + "\">");
      out.println(rd.getRequestId());
      out.println("</A>");
      out.println("</TD>");
      out.println("<TD CLASS=\"clsTitle\">");
      out.println(rd.getSobrenome());
      out.println("</TD>");
      out.println("<TD CLASS=\"clsTitle\">");
      out.println(rd.getSoftware());
      out.println("</TD>");
      out.println("</TR>");
    }
    out.close();
  } 
}

TechSupDetalhaServlet

// Import Servlet packages
import javax.servlet.*;
import javax.servlet.http.*;

// Import other Java packages
import java.io.*;
import java.util.*;
import java.sql.*;

public class TechSupDetalhaServlet extends HttpServlet {
  private TechSupDB techSupDB;

  public void init() throws ServletException {
    techSupDB =
            (TechSupDB)getServletContext().getAttribute("techSupDB");
    if(techSupDB == null) {
      throw new UnavailableException("Nao pode obter o banco de dados.");
    }
  }

  public void destroy() {
    techSupDB.remove();
    techSupDB = null;
  }

  protected void doGet(HttpServletRequest req, HttpServletResponse res) 
          throws ServletException, IOException {

    int requestId = Integer.parseInt(req.getParameter("requestId"));
    RequestDetails rd = null;
    try {
      rd = techSupDB.getRequestDetails(requestId);
    } catch(RequestNotFoundException e) {
      throw new ServletException("Erro no banco de dados: ", e);
    }

    PrintWriter out = res.getWriter();
    res.setContentType("text/html");
    out.println("<HTML><HEAD>");
    out.println("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"style.css\"/>");
    out.println("<TITLE>");
    out.println("Suporte Técnico: Detalhe de Pedido");
    out.println("</TITLE>");
    out.println("</HEAD>");
    out.println("<BODY>");
    out.println("<H1>Suporte Técnico: Detalhe de Pedido</H1>");
    out.println("<H2>Identificação de Pedido: " + rd.getRequestId() + "</H2>");
    out.println("<UL>");
    out.println("<LI>Nome: " + rd.getNome() + "</LI>");
    out.println("<LI>Sobrenome: " + rd.getSobrenome() + "</LI>");
    out.println("<LI>Email: " + rd.getEmail() + "</LI>");
    out.println("<LI>Fone: " + rd.getFone() + "</LI>");
    out.println("<LI>Software: " + rd.getSoftware() + "</LI>");
    out.println("<LI>SO: " + rd.getSo() + "</LI>");
    out.println("<LI>Problema: " + rd.getProblema() + "</LI>");
    out.println("</UL>");
    out.close();
  } 
}

A Composição da Aplicação

C:\...\src>ant techsup
Buildfile: build.xml

init:

techsup:
    [mkdir] Created dir: C:\...\build\techsup
     [copy] Copying 2 files to C:\...\build\techsup
    [javac] Compiling 10 source files to C:\...\build\techsup

BUILD SUCCESSFUL

Total time: 5 seconds

O Deployment da Aplicação

No servidor de banco de dados

DROP TABLE SUPP_REQUESTS;
CREATE TABLE SUPP_REQUESTS(
  REQUEST_ID INTEGER PRIMARY KEY,
  NOME       VARCHAR(40),
  SOBRENOME  VARCHAR(40),
  EMAIL      VARCHAR(40),
  FONE       VARCHAR(40),
  SOFTWARE   VARCHAR(40),
  SO         VARCHAR(40),
  PROBLEMA   VARCHAR(256)
);

DROP TABLE SEQ_NO;
CREATE TABLE SEQ_NO(
  PROX_NUM   INTEGER
);

INSERT INTO SEQ_NO VALUES(0);

No servidor J2EE

j2ee -stop
j2eeadmin -addJdbcDatasource jdbc/TechSupDB jdbc:cloudscape:rmi:TechSupDB;create=true
j2eeadmin -addJdbcDatasource <nome JNDI> <URL>
j2ee -verbose
Binding DataSource, name = jdbc/TechSupDB, url = jdbc:cloudscape:rmi:TechSupDB;create=true

Na máquina de deployment

Conclusão

techsupport programa