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.
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.