domingo, 16 de outubro de 2011

Exemplo CRUD Spring com JDBC Template e Servlet/JSP

Neste post, vamos estudar um dos Frameworks que é líder no mercado em aplicações JEE.
Estou falando do Spring Framework, que foi desenvolvido por Rod Johnson, e é mantido pela empresa 
Interface21. Este Framework oferece vários benefícios, possui módulos bem diversificados e pode 
ser usado em diversos cenários.
No nosso caso, vamos focar em um dos principais recursos do Spring que é o container de IoC 
(Inversion of Control), que também é conhecido como DI (Dependency Injection), a idéia da DI 
é de separar uma Interface da classe que a implementa, nos exemplos de DI deste tutorial será 
aplicado a injeção através de métodos Setter, mais também pode ser injetado com Construtor.
Através da Injeção de Dependência, facilitará em ligar a camada de persistência de dados 
com a camada de negócio e consequentemente com a camada de controller, deixando ambas as camadas 
desacopladas entre si.
Além da DI que o Spring ofere, iremos usar o JDBCTemplate para manipular os dados da camada de 
persistência, este template possui vários métodos utilitários para trabalhar com JDBC, e o mesmo 
já fica encarregado de abrir/fechar conexão, statement e result, apenas vamos precisar de um 
Data Source para trabalhar com as querys.
A camada de controller e apresentação, será feita com Servlet/JSP, mostrando assim, como o Spring 
é bem modular e que integra facilmente nossas camadas.
Para o exemplo será usado o Eclipse Indigo, TomCat 6, Banco de Dados Derby e o Spring 2.5.6,  para baixar o framework, acesse: http://www.springsource.org/download, baixe a versão full, com todos as dependências.
Ao final do post, o projeto está disponível para download, com todas as libs necessárias.


Segue o modelo da estrutura do projeto:


1. Passo: Vamos criar nossa classe modelo, que se chamará Pessoa:
 package model;  
 public class Pessoa {  
      private int id;  
      private String nome;  
      public Pessoa() {  
           super();  
      }  
      public Pessoa(String nome) {  
           super();            
           this.nome = nome;  
      }  
      public int getId() {  
           return id;  
      }  
      public void setId(int id) {  
           this.id = id;  
      }  
      public String getNome() {  
           return nome;  
      }  
      public void setNome(String nome) {  
           this.nome = nome;  
      }  
      @Override  
      public String toString() {  
           return "Pessoa [id=" + id + ", nome=" + nome + "]";  
      }  
 }  
Pessoa.java

2. Passo: Agora vamos criar a Interface DAO.
 package dao;  
 import java.util.List;  
 import model.Pessoa;  
 public interface PessoaDAO {  
      void insert(Pessoa pessoa);  
      List<Pessoa> select();   
      void delete(int id);  
 }  

PessoaDAO.java

3. Passo: Nesta classe, vamos implementar os métodos de contrato da Interface, além disto, teremos um método que será responsável por criar a tabela PESSOA, no banco de dados Derby, (as configurações do banco, data source, etc..., será explicada daqui alguns instantes.). Deve-se ressaltar, que o atributo jdbcTemplate do tipo JdbcTemplate, é responsável por manipular os dados nessa camada de persistência, observe-se que não instanciamos o objeto com new, apenas teremos que ter o método setter deste atributo, para que o container do Spring, posso se encarregar de fazer a injeção de dependência.
 package dao;  
 import java.util.ArrayList;  
 import java.util.List;  
 import java.util.Map;  
 import model.Pessoa;  
 import org.springframework.dao.DataAccessException;  
 import org.springframework.jdbc.core.JdbcTemplate;  
 public class PessoaDAOImp implements PessoaDAO {  
      private JdbcTemplate jdbcTemplate;  
      @SuppressWarnings("unused")  
      private void init() {  
           StringBuilder sb = new StringBuilder();  
           sb.append("CREATE TABLE pessoa (");  
           sb.append("id INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (");  
           sb.append("START WITH 1, INCREMENT BY 1),");  
           sb.append(" nome VARCHAR(50),");  
           sb.append(" CONSTRAINT primary_key PRIMARY KEY (id))");  
           try {  
                jdbcTemplate.execute(sb.toString());  
                insert(new Pessoa("Jabes Felipe"));  
           } catch (DataAccessException e) {                 
 //               jdbcTemplate.execute("drop table autor ");  
                e.printStackTrace();  
           }  
      }  
      @Override  
      public void insert(Pessoa pessoa) {  
           jdbcTemplate.update("INSERT INTO pessoa (nome) VALUES (?) ", new Object[]{pessoa.getNome()});  
      }  
      @SuppressWarnings("unchecked")  
      @Override  
      public List<Pessoa> select() {                      
           List<Map<String, Object>> list = jdbcTemplate.queryForList("SELECT id, nome FROM pessoa");  
           List<Pessoa> pessoas = new ArrayList<Pessoa>(list.size());  
           for (Map<String, Object> map : list) {                 
                Pessoa pessoa = new Pessoa();  
                pessoa.setId(Integer.parseInt(map.get("ID").toString()));  
                pessoa.setNome(map.get("NOME").toString());  
                pessoas.add(pessoa);  
           }  
           return pessoas;  
      }  
      @Override  
      public void delete(int id) {  
           jdbcTemplate.update("DELETE FROM pessoa WHERE id=?", new Object[]{id});            
      }  
      public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {  
           this.jdbcTemplate = jdbcTemplate;  
      }       
 }  

PessoaDAOImp.java


4. Passo: Vamos criar a camada de serviço, definimos a Interface.
 package service;  
 import java.util.List;  
 import model.Pessoa;  
 public interface PessoaService {  
      void insert(Pessoa pessoa);  
      List<Pessoa> select();  
      void delete(int id);  
 }  

PessoaService.java


5. Passo: Classe que implementa a Interface de serviço, vale apena ressaltar, que a referência PessoaDAO que um atributo pessoaDAO, será injetado pelo Spring através do método Setter que criamos.

 package service;  
 import java.util.List;  
 import model.Pessoa;  
 import dao.PessoaDAO;  
 public class PessoaServiceImp implements PessoaService {  
      private PessoaDAO pessoaDAO;  
      @Override  
      public void insert(Pessoa pessoa) {  
           pessoaDAO.insert(pessoa);  
      }  
      @Override  
      public List<Pessoa> select() {  
           return pessoaDAO.select();  
      }  
      @Override  
      public void delete(int id) {  
           pessoaDAO.delete(id);            
      }  
      public void setPessoaDAO(PessoaDAO pessoaDAO) {  
           this.pessoaDAO = pessoaDAO;  
      }  
 }  

PessoaServiceImp.java


6. Passo: Já criamos nossa camada de persistência e de serviço, agora vamos criar um Servlet que será nosso controller da camada de tela e serviço.
 package servlets;  
 import java.io.IOException;  
 import javax.servlet.ServletException;  
 import javax.servlet.http.HttpServlet;  
 import javax.servlet.http.HttpServletRequest;  
 import javax.servlet.http.HttpServletResponse;  
 import model.Pessoa;  
 import org.springframework.beans.factory.annotation.Autowired;  
 import org.springframework.web.context.support.SpringBeanAutowiringSupport;  
 import service.PessoaService;  
 import service.PessoaServiceImp;  
 public class PessoaServlet extends HttpServlet {  
      private static final long serialVersionUID = 1L;  
      @Autowired   
      private PessoaService pessoaService;  
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
           SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);  
           String acao = request.getParameter("acao");  
           if ("salvar".equals(acao)) {  
                Pessoa pessoa = new Pessoa();  
                pessoa.setNome(request.getParameter("nome"));  
                pessoaService.insert(pessoa);  
           } else if ("excluir".equals(acao)) {  
                int id = Integer.parseInt(request.getParameter("id"));  
                pessoaService.delete(id);  
           }  
           request.setAttribute("pessoas", pessoaService.select());  
           getServletConfig().getServletContext().getRequestDispatcher("/home.jsp").forward(request,response);  
      }  
      public void setAutorService(PessoaServiceImp pessoaService) {  
           this.pessoaService = pessoaService;  
      }  
 }  

PessoaServlet.java

7. Passo: Agora vamos configurar as definições necessárias do Spring no arquivo web.xml.
 <?xml version="1.0" encoding="UTF-8"?>  
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">  
  <display-name>Spring</display-name>  
  <welcome-file-list>    
   <welcome-file>index.jsp</welcome-file>    
  </welcome-file-list>  
  <!-- Define os arquivos de configuracoes XML para o contexto Spring -->  
  <context-param>  
   <param-name>contextConfigLocation</param-name>  
   <param-value>/WEB-INF/applicationContext.xml</param-value>  
  </context-param>  
  <!-- Inicializa o Spring Web Application Context -->  
  <listener>  
   <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  </listener>  
  <!-- Ativa os escopos web para os beans no Spring -->  
  <listener>  
   <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>  
  </listener>  
  <servlet>  
   <description></description>  
   <display-name>PessoaServlet</display-name>  
   <servlet-name>PessoaServlet</servlet-name>  
   <servlet-class>servlets.PessoaServlet</servlet-class>  
  </servlet>  
  <servlet-mapping>  
   <servlet-name>PessoaServlet</servlet-name>  
   <url-pattern>/PessoaServlet</url-pattern>  
  </servlet-mapping>  
 </web-app>  

web.xml

8. Passo: Agora chegou, a parte mais importante, que é o arquivo de configuração dos beans, contexto e datasource do Spring. Neste arquivo está configurado o Data Source que contém as informações do banco, o jdbcTemplate que contém uma referência ao dataSource, também configuramos os properties do banco e por fim, temos a definição de pessoaDAO e pessoaService.
 <?xml version="1.0" encoding="UTF-8"?>  
 <!--  
  - Application context definition for JPetStore's business layer.  
  - Contains bean references to the transaction manager and to the DAOs in  
  - dataAccessContext-local/jta.xml (see web.xml's "contextConfigLocation").  
  -->  
 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
           xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"  
           xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee"  
           xmlns:tx="http://www.springframework.org/schema/tx"  
           xsi:schemaLocation="  
                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd  
                http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd  
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">  
      <bean id="pessoaService" class="service.PessoaServiceImp" lazy-init="false" scope="singleton">  
           <property name="pessoaDAO" ref="pessoaDAO" />  
      </bean>  
      <bean id="pessoaDAO" class="dao.PessoaDAOImp" init-method="init" lazy-init="false" scope="singleton">  
           <property name="jdbcTemplate" ref="jdbcTemplate" />  
      </bean>  
      <!-- arquivo properties -->  
      <context:property-placeholder location="classpath:resources/jdbc.properties" />  
      <!-- Config. datasource -->  
      <bean id="dataSource"   
            class="org.apache.commons.dbcp.BasicDataSource"   
            destroy-method="close"  
            p:driverClassName="${jdbc.driverClassName}"   
            p:url="${jdbc.url}"   
            p:username="${jdbc.username}"  
            p:password="${jdbc.password}" />  
      <!-- Transaction manager for a single JDBC DataSource (alternative to JTA) -->  
      <bean id="transactionManager"   
         class="org.springframework.jdbc.datasource.DataSourceTransactionManager"  
            p:dataSource-ref="dataSource"/>  
      <!-- JDBC template -->  
      <bean  
           id="jdbcTemplate"  
           class="org.springframework.jdbc.core.JdbcTemplate"  
           lazy-init="false">  
                <property name="dataSource" ref="dataSource" />  
                <property name="lazyInit" value="false" />  
      </bean>  
 </beans>  

applicationContext.xml


9. Passo: Segue informações do banco de dados Derby, que estão contidas em um arquivo de properties.
 # Properties file with JDBC settings.  
 #  
 # Applied by <context:property-placeholder location="jdbc.properties"/> from  
 # various application context XML files (e.g., "applicationContext-*.xml").  
 # Targeted at system administrators, to avoid touching the context XML files.  
 #-------------------------------------------------------------------------------  
 jdbc.driverClassName=org.apache.derby.jdbc.EmbeddedDriver  
 jdbc.hostname=localhost  
 jdbc.database=spring  
 jdbc.username=spring  
 jdbc.password=spring  
 jdbc.port=3306  
 jdbc.url=jdbc\:derby\:directory\:${jdbc.database}ExemploDB;create\=true  


10. Passo: Segue as telas jsp.
 <% response.sendRedirect("./PessoaServlet"); %>  

index.jsp

 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>  
 <%@ page language="java" contentType="text/html; charset=ISO-8859-1"  
      pageEncoding="ISO-8859-1"%>  
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
 <html>  
 <head>  
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">  
 <title>SPRING</title>  
 <script type="text/javascript">  
 function validar() {  
      var nome = document.getElementById("nome");  
      if (nome == null || nome.value == '') {  
           alert("Nome obrigatorio!");   
           return false;            
      } else {            
            return true;  
      }  
 }  
 </script>  
 </head>  
 <body>  
      <form action="./PessoaServlet" method="get" onsubmit="return validar();">  
           <table>  
                <tr>  
                     <td>Nome:</td>  
                     <td><input id="nome" name="nome" type="text"></td>  
                </tr>  
                <tr>  
                     <td colspan="2"><input name="acao" type="hidden" value="salvar" />  
                          <input type="submit" value="salvar" />  
                     </td>  
                </tr>  
           </table>  
           <br />  
           <table>  
                <tr>  
                     <td>ID</td>  
                     <td>Nome</td>  
                     <td>Excluir</td>  
                </tr>  
                <c:forEach var="pessoa" items="${pessoas}">  
                     <tr>  
                          <td><c:out value="${pessoa.id}" /></td>  
                          <td><c:out value="${pessoa.nome}" /></td>  
                          <td><a href="./PessoaServlet?acao=excluir&id=${pessoa.id}">Excluir</a>  
                          </td>  
                     </tr>  
                </c:forEach>  
           </table>  
      </form>  
 </body>  
 </html>  

home.jsp

Exemplo da tela:



Para quem quiser baixar o projeto desenvolvido, clique aqui.
Qualquer dúvida, crítica ou sugestão, fico à disposição.

Jabes Felipe RSS Feed Jabes Felipe